ao-tools/ao-dump-up/ao-dump-up
ao-tools/ao-eeprom/ao-eeprom
ao-tools/ao-edit-telem/ao-edit-telem
+ao-tools/ao-elftohex/ao-elftohex
ao-tools/ao-list/ao-list
ao-tools/ao-load/ao-load
ao-tools/ao-postflight/ao-postflight
ao-tools/ao-rawload/ao-rawload
ao-tools/ao-send-telem/ao-send-telem
ao-tools/ao-sky-flash/ao-sky-flash
+ao-tools/ao-usbload/ao-usbload
ao-tools/ao-view/ao-view
ao-view/Makefile
ao-view/ao-view
autom4te.cache
+compile
config.*
config.h
config.h.in
doc/telemetrum.html
doc/telemetrum.pdf
altosui/altos-windows.log
+pdclib-root
--- /dev/null
+[submodule "pdclib"]
+ path = pdclib
+ url = git://git.gag.com/fw/pdclib
-commit 5a329c7f588334df7443b47c8f478ebadf312f62
-Merge: 9b13822 03fe10e
+commit 701c26ed85c28ac59e338975f2a6ba6bd25f6493
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Dec 19 00:16:16 2013 -0800
+
+ altosdroid: bump versionName to 1.3 and versionCode to 4
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9f95ffbad918a73cfd5460d6ce037d680465c35d
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Dec 19 00:12:21 2013 -0800
+
+ altosui: When device has no valid romconfig, set RF cal to 0
+
+ This is intended to signal to the user that no valid value was found
+ and that they'd best pick something sensible.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a04c1dd5df76c9127615bc797a9d9f764eec1234
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Dec 19 00:08:50 2013 -0800
+
+ altos/lpc: Stop sending SETUP IN when the requested size is reached
+
+ The host won't keep asking for SETUP IN packets once it has received
+ the amount of data requested, so check to see if we've sent that much
+ and flip back to IDLE state if so.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 1ab12861c3e70d7c22b27d988546a925616a0adc
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Dec 18 23:27:34 2013 -0800
+
+ altos/lpc: Reset less of the device on USB reset.
+
+ This leaves most of the device configured across USB reset, which
+ appears to help when sending a IN reply to the first SETUP packet;
+ without this change, the IN reply would always get a length of 0,
+ which is fine for SET_ADDRESS, but not for GET_DESCRIPTOR_DEVICE,
+ which OS X appears to send before setting the address (go figure).
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3b13cc2ca035b13582cd2e59ba7286f872f43c6e
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Dec 18 22:00:13 2013 -0800
+
+ altoslib: Remove some old debug printfs for self flashing
+
+ These aren't necessary anymore and just slow down flashing boards.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 408b0dea338147382e94717dab85b4a204e7bdf5
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Dec 18 21:08:33 2013 -0800
+
+ micropeak: Add micropeak man page
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2b2ba87d5f68b9e052dddd49d69341f36d777122
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Dec 18 21:02:15 2013 -0800
+
+ ao-tools: Add man pages for ao-flash utilities
+
+ These aren't very wordy, but these tools are pretty simple scripts.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 39cb8c2896317b7538353be979ac99baffc14489
+Merge: 2a6016c ee42796
+Author: Bdale Garbee <bdale@gag.com>
+Date: Wed Dec 18 21:53:52 2013 -0700
+
+ Merge branch 'master' of ssh://git.gag.com/scm/git/fw/altos
+
+commit 2a6016cfabc8cd56f5219871e3b3df316a639289
+Author: Bdale Garbee <bdale@gag.com>
+Date: Wed Dec 18 21:53:36 2013 -0700
+
+ update Debian standards version we claim compliance with
+
+commit ee4279613b4757453d0d8f8afc06037c61eeb520
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Dec 18 20:32:05 2013 -0800
+
+ altos: Try IMU self-test 10 times before giving up
+
+ This should keep the device from failing to boot unless the IMU is
+ actually broken. Oh, and if self test does fail, this places the
+ flight computer in 'Invalid' state rather than panic.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 1bf84ec28a41f7bd1b11ba45b4639856266227bc
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Dec 18 20:30:58 2013 -0800
+
+ doc: Add tables describing AltOS beeps and flashes
+
+ Provide a convenient place to reference when listening to the device.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 0673344289772ed89483948184d6608c272c7c26
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Dec 18 18:20:55 2013 -0800
+
+ altos/stm: Semantic error in STM usb disable caused it to not work
+
+ The USB enable register wasn't actually getting rewritten with the
+ enable bit turned off, so the USB device was still powered on in flight.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 122f491e459b6ff417932370b3f1aa2091c71aca
+Author: Bdale Garbee <bdale@gag.com>
+Date: Wed Dec 18 18:30:54 2013 -0700
+
+ update release docs to include option for submodules
+
+commit d9982c257463f23be940eea66bd4dc3aadff0043
+Merge: 1b97ed2 b63fc05
+Author: Bdale Garbee <bdale@gag.com>
+Date: Wed Dec 18 18:25:35 2013 -0700
+
+ Merge branch 'master' of ssh://git.gag.com/scm/git/fw/altos
+
+commit 1b97ed2b64bcbcd969124964f1e49837899f1c70
+Author: Bdale Garbee <bdale@gag.com>
+Date: Wed Dec 18 18:25:03 2013 -0700
+
+ we're using packaged and local-to-our-tree ARM toolchain now
+
+commit b63fc05481bf6d57e6385704ce53c1c19afa9c2e
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Dec 18 14:34:31 2013 -0800
+
+ doc: typo in micropeak doc hole->hold
+
+commit 6827961c002757f8e74de44f6eb9c9029d099ebc
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Dec 18 14:25:41 2013 -0800
+
+ doc: Update micropeak quick start guide to note new boost detect
+
+ Now waits for one minute and 30m of altitude change to avoid false detections.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c0966cd40f05f3a65b0c977b4b92586a58192f4b
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Dec 18 14:22:51 2013 -0800
+
+ micropeak: Compile for java 6
+
+ Don't a require later version as not all target OSes support it
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit eea036650e62bc0f8652155974b512686754fd13
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Dec 18 14:08:41 2013 -0800
+
+ Move pdclib build results to pdclib-root
+
+ This makes pdclib easier to manage as a submodule
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c1bfe09b6d3eb28d0c7cfe07a248843cf81bcd25
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Dec 18 13:36:04 2013 -0800
+
+ altosui: Remove some debug printfs
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 58ceb9c845d51547244538fe6beec27e9a232af8
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Dec 18 13:25:31 2013 -0800
+
+ altosdroid: Use altoslib standard voltages to control lights
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit dbcf3264f950c4e1d450828c9f161b4c418bee97
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Dec 18 13:22:45 2013 -0800
+
+ altoslib: Define 3.8 as a good battery and 3.5 as a good igniter
+
+ Use defined values everywhere instead of copying. Adjust battery up to
+ 3.8 to ensure there's enough voltage to not trip the comparators
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit b19a648b667c298d2d9d5ed4ee9db661be058d1a
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Dec 18 13:09:48 2013 -0800
+
+ altoslib: create eeprom download thread before telling monitor about it
+
+ Telling the monitor too early resulted in passing a null thread
+ handle, which meant that 'cancel' wouldn't ever work.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 216405bc49ef2fc0e9941989f054e41f2fef9cfe
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Dec 18 12:40:22 2013 -0800
+
+ altoslib: Don't close telemetry reader at startup unless something fails
+
+ Was always closing the file, which led to very little telemetry being received.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit f2e589c59ed0a4c586c5accca8772df15010c46a
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Dec 18 12:16:55 2013 -0800
+
+ libaltos: Import newly build libaltos.dylib
+
+commit 0484ca97828da0d56be7bf395fa4a4b09c591e02
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Dec 18 12:15:54 2013 -0800
+
+ libaltos: remove usb id filtering from darwin code
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 36197a388a9ba1d1ee4acd96ac0079ad3af9d3d0
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Dec 18 12:15:22 2013 -0800
+
+ libaltos: fix test harness main type
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 119dd56512404e0c39dd5001ba4da9373515c02c
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Dec 18 11:25:05 2013 -0800
+
+ altosui: Add docs to Mac OS X dmg distribution
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6df58bb0115a8da13d35ab38861f6231bea7f2a7
+Merge: 4383baf 02195f2
+Author: Bdale Garbee <bdale@gag.com>
+Date: Wed Dec 18 12:19:31 2013 -0700
+
+ Merge branch 'master' of ssh://git.gag.com/scm/git/fw/altos
+
+commit 4383bafc6ccdde10f06882ba3e96126c61d5e988
+Author: Bdale Garbee <bdale@gag.com>
+Date: Wed Dec 18 12:18:30 2013 -0700
+
+ a fresher changelog entry for test builds
+
+commit 7db8e8190bc8b9a17a7b5107954e2362a0e9c7a2
+Author: Bdale Garbee <bdale@gag.com>
+Date: Wed Dec 18 11:08:55 2013 -0700
+
+ need to include the Cortex toolchain
+
+commit 02195f2970fb7243fd9a9992abb6ada6709db4e1
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Dec 18 11:14:40 2013 -0800
+
+ fix git: path for pdclib
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit fbca372edd5609bc253b622b55b7faffd19ae6cd
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Dec 18 11:12:44 2013 -0800
+
+ Use git: path for pdclib
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e2635d07d0f0a91dd7d59f2c94765a40907d2732
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Dec 18 11:08:11 2013 -0800
+
+ Ignore .dll files in libaltos
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8fdbdebdbb4d1579fd2af47430807d0d2a78105b
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Dec 18 11:07:55 2013 -0800
+
+ ao-tools: complain if st-flash is not available
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8f529633cd4be8a0edb1b067bbf5d7cc055dcc1b
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Dec 18 10:55:06 2013 -0800
+
+ altos: get stm-bringup building again
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 262ee65885d55902df96f4aec6a114f5ac6f2c61
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Dec 18 10:53:09 2013 -0800
+
+ Remove stale stm test apps from regular build
+
+commit 90386115204bd3bfa55deb5ebe1972bacdba725a
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Dec 18 10:50:45 2013 -0800
+
+ altos/stm: Update pdclib paths for flash-loader builds
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit eb659fb0ee80c25312be36b3d8adb686813db125
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Dec 18 10:43:16 2013 -0800
+
+ altos: create target pdclib directories before building
+
+commit 9c200c3bc742b4dd1a7e28bfce9d5b27e833aae5
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Dec 18 10:01:29 2013 -0800
+
+ altos: Build pdclib locally if necessary
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit fbde0c3e4bdb419d6bd4dbcc96b0e01c59e9fa13
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Dec 18 09:59:33 2013 -0800
+
+ include pdclib in wrong place
+
+commit 77b04d662a6704f5db10522a2f9b169d31df5bea
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Dec 18 02:03:15 2013 -0800
+
+ altosui: Hide non-applicable altimeter config values
+
+ This makes configuring EasyMini a lot easier...
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 012abeda6ae846d74729e96e7ed7c8af2edca572
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Dec 18 02:02:12 2013 -0800
+
+ altos/lpc: Be a bit more resistant to toolchain section name changes
+
+ Just add some wild cards on the ends of each section name in case the
+ toolchain changes names in the future.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e26306c9350ef1d107d4257ef1c09d15165c9154
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Dec 18 01:14:11 2013 -0800
+
+ altoslib: Pass InterruptedException up the stack instead of hiding it
+
+ When interrupting a thread that is talking to a serial device, it's
+ important not to have that thread discard the InterruptedException so
+ that it will actually terminate. This patch removes a bunch of places
+ that were discarding InterruptedExceptions and lets higher level code
+ see them so that they can exit cleanly.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 18852efa108ba6e6e69dfd5076d4f4c01f62b4ef
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Dec 18 01:12:11 2013 -0800
+
+ altos: Make TeleMega v0.1 work more like TeleMega v1.0
+
+ I've still got one working v0.1 board which is useful for testing
+ stuff, so make it work more like the released TeleMega:
+
+ * Use E for drogue, F for main
+ * Use on-chip eeprom for config
+ * Fix ADC report printf to match
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 1f035ac2df1cfa6964ae904aba0aedde279ca921
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Dec 17 23:50:54 2013 -0800
+
+ altos: Use all 16 bits of setup packet len when limiting reply len
+
+ We were only using the low 8 bits of the setup packet reply max len,
+ which meant that if the other side sent a weird max len (as Windows 7
+ does), then we'd truncate our setup reply to whatever was in the low 8
+ bits of that value.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 1280ba2e51b36f417f3adb6d101405ee75e7e509
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Dec 17 22:53:45 2013 -0800
+
+ altosui: Add EasyMini bits to fat distribution images. Update telemetrum.inf
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 212a1b66ae04317b7b42ba57573b910fde09ca6c
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Dec 17 20:24:19 2013 -0800
+
+ doc: Publish images with HTML bits
+
+ Otherwise the html won't render right.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2ecb6a8276b2ce40d2a4da586dbc17581cfda26d
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Dec 17 20:23:00 2013 -0800
+
+ altos: Broke TeleMetrum GPS reporting by holding the GPS mutex too much
+
+ We can't hold the GPS mutex while waiting for the GPS receiver to load
+ data as it protects the GPS data with the GPS mutex.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e44ce127ece149e7b07be49142bc0f9d50bbe97d
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Dec 17 20:05:12 2013 -0800
+
+ doc: Add screen shots everywhere
+
+ This has screen shots of every dialog in altosui
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e4b223df372348718b74d2ecad4957f3e30f8d79
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Dec 17 17:37:39 2013 -0800
+
+ Add altosui image and attempt to add launch photo to title
+
+commit 1d093383fe58fc8c8c11e1c7cd1cd929ae1bd9e4
+Author: Bdale Garbee <bdale@gag.com>
+Date: Tue Dec 17 14:53:59 2013 -0700
+
+ further documentation tweaks
+
+commit 90c88bab305c43eb62f964fd3ff350b8b0b5320d
+Merge: d5d6d10 dffbdd9
Author: Bdale Garbee <bdale@gag.com>
-Date: Tue May 21 09:31:48 2013 -0600
+Date: Tue Dec 17 14:09:30 2013 -0700
+
+ Merge branch 'master' of ssh://git.gag.com/scm/git/fw/altos
+
+ Conflicts:
+ doc/altusmetrum.xsl
+
+commit d5d6d10ceb724081c7cf89a3885d7e6c3da14604
+Author: Bdale Garbee <bdale@gag.com>
+Date: Tue Dec 17 14:08:12 2013 -0700
+
+ capture my changes so far
+
+commit dffbdd93d7a86a12d83a412de37dfd2a5f063995
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Dec 17 11:38:46 2013 -0800
+
+ doc: Add product pictures to manual
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9d8da4ef325171960e16fc027c6039cb63eae942
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Dec 17 11:19:54 2013 -0800
+
+ Keep tables together on a page
+
+commit 7acd0cf17c5ca7a00893f35c7fe9c657389070e0
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Dec 17 10:33:29 2013 -0800
+
+ doc: Convert several more itemizedlists to variablelists
+
+ When defining a term, use variablelist to pull the term out to the left.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8bb6dd75a602792936d623713fb009fea25ef491
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Dec 16 21:21:24 2013 -0800
+
+ Clean up reflashing section, include section on self-flash recovery
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 1562affc4951e147eba20380ea5be2e9f7152789
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat Dec 14 11:47:31 2013 -0800
+
+ ao-tools: Use st-flash for STM flashing instead of openocd
+
+ st-flash, from the stlink tools, appears more reliable when flashing
+ STM CPUs.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 7d7ae63d8dfcc99a30285e0bd2411901941d1813
+Author: Bdale Garbee <bdale@gag.com>
+Date: Sat Dec 14 12:16:03 2013 -0700
+
+ add serial number to ao-usbload call, pass SERIAL to cal-freq
+
+commit c94ca50fd9f24f271c160f6e0e95cb7340289354
+Author: Bdale Garbee <bdale@gag.com>
+Date: Fri Dec 13 18:37:29 2013 -0700
+
+ temporarily force stlink location in debian/rules to allow complete build
+
+commit 6545a72012e94a50d185e1c4ecff3c3769d60acd
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Dec 10 00:54:32 2013 -0800
+
+ java: Missed libaltos java compile flags from previous patch
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8959c059ec67f5334e31abbe3f831dd571a0b464
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Dec 10 00:51:01 2013 -0800
+
+ java: Add -target 1.6 to all java compiles
+
+ This makes sure the results can run with the old JVM
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a4596c134aa5e7867f1ca1d86d36afb2af9b8999
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Dec 10 00:39:52 2013 -0800
+
+ altos: Remove ARM .ihx files on 'make clean'
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 50753e84871b2a01d270d28b8b77a19614d2180c
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Dec 10 00:03:20 2013 -0800
+
+ Set version to 1.3 in preparation for release
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 54f7888dc65ffc27c6ee5ef93953bd9b8fc029ed
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Dec 10 00:00:31 2013 -0800
+
+ doc: More altusmetrum.xsl updates for 1.3
+
+ Spell checking even
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a140b3ad689bcebdcf87caab1e64048f693a9b85
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Dec 9 23:16:13 2013 -0800
+
+ debian: .ihx and .map files are left in subdirs now
+
+ Install them from the right place
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 95c1a5a61267233cf2c16175aeb73bfb7d12ba8f
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Dec 9 23:14:55 2013 -0800
+
+ altosui: Ship TeleMega-v1.0 firmware
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit b023c87e2b86ba57cbf97be1ab76b532e0a00fad
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Dec 9 23:12:40 2013 -0800
+
+ ao-bringup: Add turnon_telemega script
+
+ And a few helper programs
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ecb0465be76e9299511aeec663d267967834f6c3
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Dec 9 16:06:22 2013 -0800
+
+ altos: Rename telemega-v0.3 to telemega-v1.0
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit dd91a5d5069ff940e07b8817a934ee65d4e8e235
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Dec 8 21:08:36 2013 -0800
+
+ altos: Oops. Was only filling out part of the TeleMetrum ADC record
+
+ Because it's missing a return, we'd end up filling out one element of
+ the ADC record per interrupt, and rotating through which one was set,
+ hitting all of the even offsets within the struct. Yikes!
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c1711890c002fe359bd6c3fdf4092b35d464c6d9
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Dec 8 21:07:17 2013 -0800
+
+ altosui: When flashing to TeleDongle or TeleBT, match any .ihx file
+
+ Let the user pick any .ihx file when using a device which can only be
+ used as a pair programmer. Note that 'telemetrum' can be either, and
+ we'll assume that it's a self-programmed device (v2) for now.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 710343a23c7e6e9c079eafdf3aeea8a40cc2ce61
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Dec 8 20:34:11 2013 -0800
+
+ altosui: Match directories in hex file matcher
+
+ This makes it possible to navigate around the file system
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit fd92bb8ff3be257925bf6e969d93a7f9dd941fb8
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Dec 8 20:33:22 2013 -0800
+
+ altoslib: Don't require radio_cal or usb_descriptors in AltosRomconfig
+
+ Not all products will have these values, so allow them to be missing
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 68adbf5bf08ed8af2f34c0d95d9c3d457574372d
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Dec 8 20:11:46 2013 -0800
+
+ Add new tools to .gitignore
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2cdb90d9214f8e66b3574cbd9c5ed073a7861681
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Dec 8 20:09:10 2013 -0800
+
+ altoslib: Add self-flashing code
+
+ This adds the ability to use the AltOS flash-loader on both STM and
+ NXP processors.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 70d0841b4017e7580c893c7033c04fb2964adab6
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Dec 8 20:07:23 2013 -0800
+
+ altoslib: Add AltosNoSymbol exception
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 4e1b134e29313a1bdac18de57fe547299e5ded2a
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Dec 8 20:04:43 2013 -0800
+
+ altoslib: Use symbols in AltosRomconfig instead of fixed offsets
+
+ The new Hexfile symbol code automatically adds the needed romconfig
+ symbols for cc1111 products, and ARM-based products have symbols in
+ the .ihx files. This means that we can rely on using symbols when
+ finding config values in memory.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 1183417145de549b9281f9e210d216facf3a94ef
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Dec 8 19:59:37 2013 -0800
+
+ altosuilib: Don't match product_altusmetrum for product_basestation or product_altimeter
+
+ It's been years since we've shipped boards configured with
+ product_altusmetrum, but now we've repurposed that code for the flash
+ loader. When matching an explicit product, go ahead and also match
+ altusmetrum so that the flash loader will fit, but when matching
+ basestation or altimeter, don't as that will avoid popping up the
+ flight monitor UI at startup when a board is running the boot loader.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e0af4569446b12c026aa0ffd52c55839d69af0e1
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Dec 8 19:48:27 2013 -0800
+
+ altoslib: Publish mapping from product name back to USB id
+
+ This lets us choose which device to flash based on the filename
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 88fa5fa6acbdd66d1338ca73cbbac219d62b5136
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Dec 8 19:47:44 2013 -0800
+
+ altoslib: Create AltosProgrammer class
+
+ This provides an abstract interface to flashing boards, for
+ dongle-based and self-programming boards.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 7b0c1fbccb4ef1ae2ed356292cc8762360532b7f
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Dec 8 19:46:30 2013 -0800
+
+ altoslib: Add symbols to .ihx files
+
+ Create a new 0xfe record type to hold the symbols, and append them
+ after the EOF record so that other tools might continue to work.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit b1ffdaf1f5e9b6e8ff0d4e08d8c504f8dfacd3a4
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Dec 8 19:43:13 2013 -0800
+
+ altoslib: Support binary reading/writing in AltosLink
+
+ Binary reads require an explicit length, and do not work while
+ telemetry is running.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2cb7a96567e1302a699f78290fab5e29693940ab
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Dec 8 19:05:01 2013 -0800
+
+ altos/stm: arm-none-eabi-binutils now puts 'main' into .text.startup
+
+ Change name of .text.ram to .ramtext, then load .text* into flash and
+ .ramtext into ram. This ensures that 'main' and anything else in a
+ random .text.* segment will get loaded into flash as appropriate.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3e22a0dce4248cce862147c985078de44c427b12
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Dec 8 19:04:11 2013 -0800
+
+ ao-tools: build ao-usbload by default
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit b1f3525afa801038f7087a3a2caf369f2460a5db
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Dec 8 11:41:09 2013 -0800
+
+ altoslib: AltosEepromMonitor had false import of altosuilib
+
+ Not needed, and breaks the build
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit eded084c6caa1f9423d690c8b45c8042f8355987
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Dec 8 11:17:28 2013 -0800
+
+ altos: remove all versions of stm-demo executable
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit bb72b4018dd6a422afe1916d9538bb9ff1e45353
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Dec 8 11:15:37 2013 -0800
+
+ altos: Change flash loader name to just AltosFlash
+
+ Remove the software version string from the product name
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 52b19511222980138faddb2047707baceff0a596
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Dec 8 11:14:29 2013 -0800
+
+ altos: Build .ihx files for all arm projects
+
+ The .ihx version can be processed by the java loader
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a1e4750a7d4af72e8e9086735885f48c9b56c18e
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Dec 8 11:11:41 2013 -0800
+
+ altos: Allow products to override default 100mA USB current
+
+ This will allow products to specify their own current limit.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 25aaf6122cbddcbc6a80460dac8ccb9f45743ae0
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Dec 8 11:10:00 2013 -0800
+
+ ao-tools: Clean up ao-stmload and ao-usbload options. Add --raw
+
+ ao-stmload only uses stlink, ao-usbload only uses self-flashing, so
+ clear up the options in the two programs. The new --raw option skips
+ the serial and radio cal rewriting when flashing the boot loader.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ebb36d56c732ffe9cdb8d2ea53d00e1d4ece8f97
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Dec 8 11:07:46 2013 -0800
+
+ ao-tools: Allow building without stlink and readline
+
+ This adds --without-stlink and --without-readline options to configure
+ to disable these features, and adjusts the build process and code to
+ handle that.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 5fd0dc6f69e7614ba71bbc215b32260a11595af3
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat Dec 7 23:27:30 2013 -0800
+
+ ao-tools: Add ao-flash-stm and ao-flash-lpc scripts
+
+ These use openocd to download boot loaders to the arm-based products
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit eee9b3ce1e5adae5aa4566050b6d6048344e92c4
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat Dec 7 09:54:17 2013 -0800
+
+ altosuilib: Deal with AltosUnits API change
+
+ The abstract methods in AltosUnits now pass the 'imperial_units' flag
+ explicitly, so deal with that in AltosUnits itself
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 407696f11ac1736e840c9b702592c46197d14c2c
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat Dec 7 09:53:10 2013 -0800
+
+ altosui: Clean up serial close handling
+
+ Unify serial close processing in a single function (close_serial),
+ make everyone else call that. This avoids a couple of cases where the
+ device would be closed and not removed from the devices_opened list,
+ leading to 'device is already in use' messages.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 1a47532f411488f003726aa9365ede5dc90c5b78
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat Dec 7 09:51:58 2013 -0800
+
+ altosui: Don't try to report bearing/elevation without GPS
+
+ If the distance from the pad cannot be computed (due to lacking GPS),
+ then don't try to report it.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 44249a9262a16ed103aedf30a300003fc2a17579
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat Dec 7 09:49:00 2013 -0800
+
+ altos: Nothing in altos uses AES decryption, so don't compile it
+
+ Saves a bit of space where AES is used, and avoids some compiler warnings.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit cdb32b1717db4e8cb8cf94d810e74ce2b569566b
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat Dec 7 09:47:45 2013 -0800
+
+ altos/test: Compute and plot tilt based on GPS track
+
+ This lets us compare the gyro-computed tilt angle against the actual
+ flight path.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6fbf4829569d5edb476654f4e383b834af527dc6
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat Dec 7 09:40:53 2013 -0800
+
+ altos: Telemega uses eeprom, include it in main file
+
+ ao_telemega.c didn't include ao_eeprom.h leaving a function undefined
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2a9b0cdff5db03dc11b6ef69cf5436c834c3acc4
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat Dec 7 09:39:41 2013 -0800
+
+ altos: Add lots more GPS data to mega log
+
+ There's plenty of space in the GPS log packets to hold course, speed,
+ climb and DOP values, so just stick them in.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit de2e812b02a99a2f6d85f15a9600265931f6f6b0
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat Dec 7 09:38:50 2013 -0800
+
+ src/cc1111: Turn off RC osc after xtal is running
+
+ There's no reason to keep running the RC oscillator after we switch to
+ the crystal, so turn it off.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 473ae38ade0552c5ff3ca088b21345ed5dfad5d0
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Nov 28 15:21:26 2013 -0800
+
+ doc: First pass for 1.3 finished; docs have most major sections updated.
+
+ Final edits and corrections still required.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6d9b93bfd637eb690159fc5efda0390eb602c6a7
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Nov 28 10:44:07 2013 -0800
+
+ ao-tools: Split out USB loader to ao-usbload
+
+ Leave ao-stmload using just stlinkv2
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit f27dff090c8f3a63bd932715643980703160bde6
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Nov 28 10:31:32 2013 -0800
+
+ ao-tools: Split out altos symbol editing from ao-stmload
+
+ to be shared with ao-usbload
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 5ef287723f8d8bfbfb3582d22bfb5c2a3129414a
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Nov 28 09:52:38 2013 -0800
+
+ ao-tools: Missing ao-selfload.h
+
+commit e6c9ca218d944443c86555e513534d82713af936
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Nov 28 09:52:01 2013 -0800
+
+ ao-tools: move 16/32-bit readers from ao-stmload to lib
+
+commit d93a65a90f19e4816231e03b1f399af6e3742aee
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Nov 28 09:46:13 2013 -0800
+
+ ao-tools: Move ao-selfload into library
+
+ This needs to be shared between ao-stmload and ao-usbload
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 14204e3d147ad99cc249ad8de254809180fe5c38
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Nov 28 09:31:02 2013 -0800
+
+ ao-tools: Add ao-elftohex and .ihx symbol support
+
+ ao-elftohex converts an elf file into a hex file so that we can load
+ it with java.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ee07f1a0f8e431bebb3b948f6249f5f33413e966
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Nov 28 09:29:52 2013 -0800
+
+ ao-tools: Add debug printf support
+
+commit 95a8180f3d7929dbad65c80421f99c925f245af0
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Nov 27 13:59:06 2013 -0800
+
+ ao-tools: Create general elf and hex library routines
+
+ Pulls the elf stuff out of ao-stmload, change the hex stuff into ao_
+ routines.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 73b1a7e644e255558378ab66de6426a7dfd8a7dc
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Nov 25 01:15:36 2013 -0800
+
+ doc: Work on AltosUI Pyro config docs a bit more.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 82b42935d047d2f7c2f7a63a3efb72a3f1d5594e
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Nov 25 00:02:06 2013 -0800
+
+ altosui: Handle units in pyro config.
+
+ This lets you edit the pyro configuration using imperial units if
+ desired.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8da565bbafa2925aa889cf9249497a709a814b7f
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Nov 25 00:01:20 2013 -0800
+
+ doc: Add telemetry enable and APRS interval config docs
+
+ Also starts working on the pyro channel config window docs
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit f743934ebd1a7c7c8b6db0223f0309e590aa15cd
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Nov 24 21:55:20 2013 -0800
+
+ doc: use correct quotes in altusmetrum.xsl
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6f4abc14065aebceaac9313e4dcd4300e19999cf
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Nov 24 21:50:27 2013 -0800
+
+ doc: "rocketry electronics" instead of listing products
+
+commit 31a1c701bfaea97225e12ea0688b934790e3737e
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Nov 24 21:28:26 2013 -0800
+
+ Use more 1/4 single characters
+
+commit 96f33e780958adaaa4a9cc127caecaeb3f4c978c
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Nov 24 21:25:06 2013 -0800
+
+ Remove duplicate log description. Describe pyro config.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3eaaefe6d746a2f53995a2470c5024f37c87c393
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Nov 24 20:05:52 2013 -0800
+
+ Extend the hardware overview chapter. Edit System Operations
+
+ Extend the overview chapter to include tables describing the
+ electronic and physical board characteristics of each board.
+
+ Finish most of the System Operation stuff, still need to add pyro
+ channel configuration
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ceed62fd97972b35f4cf6560625135723cb8610f
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Nov 18 13:48:18 2013 -0800
+
+ debian: Build now depends on 'xmlto' for docs
+
+ This wraps xsltproc, fop and xmllint for formatting pdf files
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 92753d4b8d6b17ebc7a9b65680abd46648726393
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Nov 18 12:43:33 2013 -0800
+
+ doc: Use system fo docbool.xsl instead of network one
+
+ Instead of reading the master stylesheet from the network, just use
+ the one installed on the system.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 89fc38f2cf143bed1fe8c4a4972267b15c9aa467
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Nov 18 12:42:38 2013 -0800
+
+ doc: Make pdf files depend on local stylesheet
+
+ Now that we're using our own, rebuild the docs when it changes
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit f9bbca59a9034cf7e6df4577e627d7447f3a9d51
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Nov 18 12:42:20 2013 -0800
+
+ doc: Make micropeak.xsl validate
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 0a3e27e3a392be4cfe03d200068a7e69bb2f3fdb
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Nov 18 12:38:52 2013 -0800
+
+ Make companion.xsl validate
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d212d782bff977d609a9da1b805de4a2615fb474
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Nov 18 12:37:23 2013 -0800
+
+ doc: Make telemetry.xsl validate
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 87fbe12bdaf10c9ba7ba43608b1e980cdc09d496
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Nov 18 12:29:42 2013 -0800
+
+ doc: Make altos.xsl validate
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 963a61986ea4b48fdca0989479e9c50acb0f1a9d
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Nov 18 12:12:54 2013 -0800
+
+ doc: Switch to xorg style to generate index
+
+ This style sheet generates a nice PDF index
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9953a5f0440b269dac5c675f120e6a31dde8ec69
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Nov 18 12:06:31 2013 -0800
+
+ doc: Get altusmetrum.xsl to validate
+
+ Mostly involved getting the listitem contents into para elements.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 152d978dc4be49b6b764e5e1966bd860c46054ea
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Nov 18 12:05:10 2013 -0800
+
+ doc: Start work on 1.3 doc updates
+
+ Add 1.3 release notes.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 71705532374f222e51c66e2f1214dd01b3efc8bd
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Nov 12 15:02:50 2013 +0900
+
+ Bump to version 1.2.9.4
+
+commit 12481415c2e5fb03b003343c9499df711eb14f91
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Nov 12 16:26:02 2013 +0900
+
+ altos: include ao_eeprom.h in ao_telemetrum.c to define ao_eeprom_init
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit bf893a4149b05b97f18f9f487af805adef859d74
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Nov 12 16:22:49 2013 +0900
+
+ altos: Make sure flight erase log comes after config blog
+
+ Oops. When converting from ao_storage to ao_config, I accidentally had
+ the flight erase log overwriting the config block.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 92eafd01f2809f39c5bc4058977c790d94a99df1
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Nov 12 16:08:50 2013 +0900
+
+ altos: Move telemega to using internal eeprom for config
+
+ And crank up the default per-flight storage to 1MB
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9c53ad6f8222878a26efecebd3bb1d1fe054a4b6
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Nov 12 16:06:59 2013 +0900
+
+ altos: Move TeleMetrum v2.0 to using internal eeprom for config
+
+ This leaves the whole 8MB of flash for flight storage
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 83437b2fe304599e22d0a98b5410808bcb67dc97
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Nov 12 15:45:32 2013 +0900
+
+ altos: Allow use of internal EEPROM for config storage
+
+ This stops exposing eeprom as 'storage' and instead exposes it with a
+ separate eeprom API so that it can be used for config storage without
+ also using it for flight log storage.
+
+ The config code has been changed to allow it to either use storage for
+ configuration data or eeprom.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit b57f1cabfe5052306cb4c28793bea477f4aeb2d2
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Nov 12 15:18:58 2013 +0900
+
+ altos: Don't hold GPS mutex while waiting in TM v2.0 report
+
+ Holding the GPS mutex while waiting for the GPS code to dump data into
+ the GPS variables is rather counter-productive.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 0951b1ef83d8d741d65811fa23bde43ee843a939
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Nov 12 15:18:53 2013 +0900
+
+ altos: Build TM v2.0 firmware by default
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3c40272713d93e79bb0989eefe191cd2bfe56a44
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Nov 12 15:01:13 2013 +0900
+
+ ignore "compile" script
+
+commit 28327883d377896caddbad0f9efded56a227edd1
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Nov 12 14:59:40 2013 +0900
+
+ Add TeleMini v2.0 turnon script
+
+commit cffbc025532487bbd9b467476be05d0997b5133e
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Nov 12 14:56:47 2013 +0900
+
+ ao-tools: add ao-mega man page, ignore executable
+
+commit 40d3575a9365d77ca507ebee226d51d081e1ecc6
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Nov 12 14:54:57 2013 +0900
+
+ altos: Clean up .gitignore and add a few random files
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9d2eb0b00a5a0faefce95bce949be7206b0aad37
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Nov 12 14:48:21 2013 +0900
+
+ Add ublox checksum generating program
+
+commit d5367f20fa1ae71496fde071953c2cda89654071
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Nov 12 14:45:51 2013 +0900
+
+ Ignore mac .dmg files
+
+commit 0093d5b368669e0c324f8d9dfcd2f004de85ee5c
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Nov 12 14:37:57 2013 +0900
+
+ altosui, altoslib: Move eeprom download code to altoslib
+
+ This should make adding eeprom downloading to altosdroid easier
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 45db3076b257adcf2c9f69ed0927f09d94af7a50
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Nov 12 14:28:30 2013 +0900
+
+ altosui: Make AltosEepromDownload not swing-dependent
+
+ Will move to altoslib
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6aa99c160f0695eb25ccc0598e4c36224c89dab4
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Nov 12 14:06:20 2013 +0900
+
+ altoslib: Start moving eeprom download logic to altoslib
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 74d73a2cd0b6a228eb396552e1d16685669349c0
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Nov 12 14:03:42 2013 +0900
+
+ altoslib: Raise ParseException on invalid eeprom format
+
+ Make sure the user knows when data are not downloaded successfully
+ because the UI doesn't understand the eeprom format.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit bdd6244d8b4a55c9aa4fb79b0cb1a0727afbc2ac
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Nov 12 14:01:55 2013 +0900
+
+ altos: Add orientation tracking to ao_flight_test
+
+ Shows calculated offset from vertical in ao_flight_test output
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 29b48b63305881471d9b97ef3fb236af03cb79f5
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Oct 28 00:36:13 2013 -0700
+
+ altos: Don't hold GPS mutex while waiting for GPS data in report code
+
+ Oops. This kinda breaks anyone else waiting for GPS data
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d3628bd2dd3612065792aef6c7ae5bc967b4f081
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Oct 28 00:24:59 2013 -0700
+
+ altos: sample profile address range was too narrow
+
+ The range was cranked down at some point to diagnose issues within the
+ task scheduler. Unfortunately, that change got merged, which meant
+ that general profiling lost information outside of the lower 4kB of code.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 7c1c6728bce4237ca3a8f6fde01356697a465dfd
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Oct 27 23:47:27 2013 -0700
+
+ altos: Make telemega v0.3 compile with new quaternion code
+
+ Adds lots more math code
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e838bd2847e5684ce93b6f7cbe736ebed681c3c6
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Oct 27 23:46:54 2013 -0700
+
+ altos: Make telemega v0.1 compile with new quaternion code
+
+ Adds the necessary math code
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9b0ce8ca65d76b9cf55dfff002e13ce2fbb5f7fc
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Oct 27 23:45:48 2013 -0700
+
+ altos: Add orientation test when HAS_FLIGHT_DEBUG is set
+
+ This just dumps the current orientation to stdout so you can monitor
+ it in real time
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 5d9e715d570b24ac124c30772b11923bd26ed670
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Oct 27 23:44:47 2013 -0700
+
+ altos: Update quaternion tests to check vectors_to_rotation
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 195fd70cdc7f519cd8d4ac323088ed0b6c188280
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Oct 27 23:42:58 2013 -0700
+
+ altos: Change ao_mpu6000_gyro arg to float
+
+ This lets callers pass more precision than just the original sensor value
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3d3fe7e9b6502432868f4430befac871dfea4869
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Oct 27 23:42:26 2013 -0700
+
+ altos: Fixup for 32-bit gyro averages
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 4bebade9e9004bad81df1a423687f3e3f356f1c2
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Oct 27 23:37:55 2013 -0700
+
+ altos: Correct incremental rotation computation
+
+ Trying to compute the combined rotation by taking the x/y/z rotations
+ as a vector is a good approximation, but not accurate enough for our
+ application given the large angles we sometimes see.
+
+ Instead, use a correct-but-expensive function with a pile of
+ transcendental function calls. The STM32L seems to be fast enough at least...
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 06b0c1b768a7d3eae57e66bc9aea25db49f9ea8a
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Oct 27 23:35:54 2013 -0700
+
+ altos: Compute initial rotation from vertical
+
+ This initializes the rotation with the angle from vertical, rather
+ than simply recording the off-angle vector. Doing this allows us to
+ accurately track the true orientation of the rocket, instead of just
+ the offset from the initial non-vertical orientation.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit cdbe8ce33e4a75e85caf07538ed7e997f462b758
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Oct 27 23:33:11 2013 -0700
+
+ altos: Fixup for ao_sample_orient rename
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d96fd33aa8a220d547512eb43c88fc8f5651e39e
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Oct 27 23:28:50 2013 -0700
+
+ altos: Add sinf to math code
+
+ Needed for the quaternion gyro tracking code
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit fa7d0ba0efdde3ac9fb4df0589f9ead07b7ffff5
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Oct 27 23:26:28 2013 -0700
+
+ altos: Keep 9 more bits of average pad IMU gyro data
+
+ This reduces the offset error by a bit, minimizing gyro drift.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 58f08c4b3cb9049d0c9cb02cde0d8dbdc3d33920
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Oct 27 23:23:59 2013 -0700
+
+ altos: Rename ao_orient to ao_sample_orient
+
+ Keeps it clear where this name comes from.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c10cb9d31765e6ef0ba737bc484c5aed22a332f9
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Oct 27 23:11:37 2013 -0700
+
+ altos: Add functions to init quaternions from vector pairs and euler angles
+
+ Our low sampling rate means that the "cheap" hack for
+ integrating quaternion rotations by using sin(x) ≃ x doesn't work, so
+ instead we have to compute the partial rotation the hard way.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3b25860b5b3b69642928dd9c30dec4b4b937a88c
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Oct 27 23:11:09 2013 -0700
+
+ altos: Add some comments describing quaternion multiplication
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 616977d2955da13383a1869b9ccdb07338172109
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Oct 27 23:10:13 2013 -0700
+
+ altos: Mark arguments to quaternion functions as const
+
+ Lets us pass constants without the compile whinging
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e923e11e185fd42d2a83e18b3d13bd839a72b1aa
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Oct 27 22:44:49 2013 -0700
+
+ altos: IMU accel calibration values need to be signed
+
+ The MPU6000 reports signed values.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 351d53836e201834a2d89773a08ab7c2dab2b2f4
+Author: Keith Packard <keithp@keithp.com>
+Date: Fri Oct 25 04:34:16 2013 -0700
+
+ altos: Calibrate IMU accelerometers too
+
+ Average the IMU accelerometer values pointing up and down so that we
+ have a zero-g offset for all three axes. This can then be used to
+ compute which direction the rocket is pointing while sitting on the pad.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 08143a922fe27bc50a19924f46538f9476ab5fd1
+Author: Keith Packard <keithp@keithp.com>
+Date: Fri Oct 25 04:05:09 2013 -0700
+
+ altos: Add gyro-based orientation tracking
+
+ This tracks the angle-from-vertical as an additional input to the pyro
+ channels.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ba99630f33440b993c69830856d2a7741ffdef71
+Author: Keith Packard <keithp@keithp.com>
+Date: Fri Oct 25 04:03:39 2013 -0700
+
+ altos: Fix GPS test frameworks to handle shared ao_gps_new variable
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit b83876718b1a535ee04ca0351ad57814454ec646
+Author: Keith Packard <keithp@keithp.com>
+Date: Fri Oct 25 04:00:49 2013 -0700
+
+ altos: Add floating point math functions from newlib
+
+ These are all BSD licensed, so we can simply include them directly
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 039446f54ef6968a3f0b37ce32ca6bdcdbe62546
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Oct 14 22:41:43 2013 -0700
+
+ altos: Merge GPS logging into a single function
+
+ Create a new global, ao_gps_new, which indicates new GPS position and
+ satellite data.
+
+ Use ao_gps_new as the new sleep/wakeup address.
+
+ Merge the separate gps position/satellite logging tasks into a single
+ function which waits for new data and writes out the changed values.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 5c4b3658a96f1a64ccebf7bddda06b15b4ac4a6f
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Oct 14 21:49:39 2013 -0700
+
+ altos: Use #define values for ublox packet types
+
+ One case was using hex values instead of the #define equivalents.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit db4cd8b3838d27bebdeb6a085a739a36f7634a91
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Oct 14 20:42:14 2013 -0700
+
+ altoslib,altosui: Be more robust when graphing bogus .telem files
+
+ Deal with files containing multiple serial number/flight number values
+ by preserving the boost_tick value across state resets.
+
+ Check for invalid state when computing actual boost time for the stats
+ window.
+
+ Ignore invalid speed/accel values when computing averages.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 1bd9786802751391cca3b83ac3045029e00e39ee
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Oct 13 22:05:20 2013 -0700
+
+ altos/micropeak: Increase boost detect to 30m
+
+ This meant increasing the data buffering as well so that we could
+ reliably capture the flight data back to the ground, even for slow
+ flights.
+
+ And, with the buffer extra large, we work backwards from the current
+ buffer location to find the last ground location rather than working
+ forwards from the first buffered location. This ensures that we don't
+ capture noise before boost and instead capture a nice flight curve instead.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e0e98597887a970f31b33895adb77d35e06b34ff
+Author: Bdale Garbee <bdale@gag.com>
+Date: Thu Oct 10 14:35:54 2013 -0700
+
+ updated turn-on script for telebt 1.1
+
+commit 8af5dd05fe56768f225251bbc66831494d80048e
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Oct 10 10:02:03 2013 -0700
+
+ Another try at skipping broken avr-gcc
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2296175eff9e4286eaf44451690701a46595987e
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Oct 10 09:47:52 2013 -0700
+
+ Make sure the AVR compiler can actually link stuff
+
+ avr-gcc was broken for a while, causing all linking to fail. Check for
+ that and don't try to build avr bits in that case.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit aa169b80039728e35b0dec3be66a8483d48a3458
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Oct 10 08:04:22 2013 -0700
+
+ altos: Fix stm-bringup demo build to use installed pdclib
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d8d3835fedf9b7c4d203f321e72c2b086ebb3b97
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Oct 10 00:00:05 2013 -0700
+
+ altos: Use installed pdclib
+
+ Switch over to the installed pdclib everywhere
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 7f6cbfac7c1965add91ebfc28ca3eac4561b4fb6
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Oct 9 12:04:14 2013 -0700
+
+ Bump version to 1.2.9.3
+
+ Rocketober, 2013
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e947bc5e1abcd054a584d69240f91123bad2178e
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Oct 9 12:06:30 2013 -0700
+
+ doc: Add easymini outline to distribution
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 18cb5f0b8f0917cbd4ff80f0920e8e5b35c822a1
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Oct 9 10:14:16 2013 -0700
+
+ doc: Add EasyMini outline drawing
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c584b5fc1128c7bfd7fb921ddc3a8ec498803b53
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Oct 9 12:37:30 2013 -0700
+
+ altos: Messed up the ifeq syntax a bit so ARM bits weren't getting built
+
+ $(x) is not the same as ($x)
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 74885d75621dad04984d8309c2618202f4d2b35e
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Oct 8 10:03:50 2013 -0700
+
+ altosui: Binaries to package are only in per-product dirs now
+
+ Each cc1111 project used to stick the binary in src/, but I got rid of
+ that when we ended up with so much stuff in src that it was a mess.
+
+ Building the release now requires looking in the appropriate directory
+ for each binary to ship.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 0e5d1f3ce39495e3702ecd22cb45972e13a5c986
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Oct 8 09:50:21 2013 -0700
+
+ altos: avr-gcc appears to find the loader scripts without help now
+
+ At some point, avr-gcc lost its ability to find the loader scripts
+ necessary to link programs. That appears to be fixed now, at least on
+ my machine.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit f7cccbb7a624a2a47b21682f416a135a28319b41
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Oct 8 09:39:29 2013 -0700
+
+ altos: Broken test for M0 compiler in src/Makefile
+
+ Was causing it to try to compiler M0 progs only when *no* compiler was found.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 488a527267decece48e6682e0e0c7fc29cbed329
+Merge: 6a1e398 f6661cc
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Oct 8 09:26:41 2013 -0700
+
+ Merge remote-tracking branch 'origin/master'
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+ Conflicts:
+ configure.ac
+
+commit 6a1e398e590121458176758858bb4210f3eb5a55
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Oct 8 09:22:03 2013 -0700
+
+ Add --with parameters to configure for compiler selection
+
+ This allows the user to specify which compiler to use for each target
+ CPU. Also checks to make sure the arm compiler supports -m0 and -m3
+ cpu type flags. The build now actually uses the specified compilers too.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 16965716c02eb79b449d9d3b264814d775660134
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Oct 8 09:20:12 2013 -0700
+
+ altos/stm: New GAS version requires flags in APSR assignment
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 258d225df1f4afe1cfdc9c43208bcd75d18cdf2d
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Oct 7 22:00:15 2013 -0700
+
+ altos: Rename easymini-v0.1 to easymini-v1.0
+
+ The production boards are the same as the modified v0.1 boards
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8f7edcee2db30652ce0b147f282de3396c3786ad
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Oct 7 21:53:53 2013 -0700
+
+ altos/lpc, altos/stm: ARM requires ISB after switching stack pointers
+
+ This sticks a barrier in the CPU to prevent using the wrong stack
+ register past the change.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 4254de22864de2ed7ae5928c6b8bfd9df1c8a3fb
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Oct 7 21:51:30 2013 -0700
+
+ altos: Don't require an LED for ao_flight
+
+ EasyMini has no LEDs. Deal with it.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 71666409624bf544e8a55fa5ee91d2f8514a03ca
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Oct 7 21:49:55 2013 -0700
+
+ Change differentiation filter constants and limits
+
+ Larger limits avoids clipping legit data. Using the same filter time
+ for both ascent and descent makes the results look a bit cleaner.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit f6661cc015e1a92450dc3eede97d66005f69cc72
+Author: Bdale Garbee <bdale@gag.com>
+Date: Mon Oct 7 21:56:46 2013 -0600
+
+ new toolchain for STM32L is in /usr/bin, not /opt/cortex/bin
+
+commit 8bd218854e968d2b9407489359be0c4a1aefd2c8
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Sep 19 00:29:25 2013 -0500
+
+ altos: Set TeleMini v2.0 USB ID correctly
+
+ Uses 0x0027
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3bf7ed1761e08d0cb43b0ed330226ec38c844591
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Sep 19 00:28:55 2013 -0500
+
+ Add TeleMini v2.0 telemetry support
+
+ Includes AltosLib and ao-telem
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit be7f56b86478ef4a23a2af77338c580b9c9e5e3b
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Sep 19 00:26:24 2013 -0500
+
+ altoslib: Prefer averaged ground pres for ground alt computation
+
+ If ground pressure is recorded (as from an eeprom file), then prefer
+ that value to the average of the pre-boost ground pressures when
+ computing the ground altitude.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 56b577e55c264c8e3152bb2b2cca02fa8836ac1e
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Sep 15 14:29:46 2013 -0700
+
+ altos/telemetrum-v2.0: Use red LED during boot time
+
+ If the LED is stuck on, then the board has failed to initialize,
+ so use red instead of green as a warning indicator.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 1fa3ff9ba6d04303b3de6952675532492c85182f
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Sep 15 14:29:09 2013 -0700
+
+ altos/telemini-v2.0: Change initialization order
+
+ Make sure busses are running before devices are initialized
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 0ff5f0fbc4900ad45bb7910ffc0c5a4e4cc4b857
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Sep 15 14:21:08 2013 -0700
+
+ altos: Stop copying cc1111 binaries to the altos/src dir
+
+ Just clutters up that directory.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit b86c69d56261da54745076b1f5a9c8e8e44787c2
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Sep 15 14:13:59 2013 -0700
+
+ altos: Add nanopeak-v0.1
+
+ The same as micropeak, just a few different pins
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 690094e2d7d9cfe5eb4edb478fd79e5d133c6b4b
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Sep 15 14:11:50 2013 -0700
+
+ altos: Move micropeak sources around
+
+ This sticks the micropeak sources in appropriate directories, rather
+ than in the micropeak product directory so that they can be shared
+ with future micropeak-style products.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2449d123690746d0d0d5d66dfc4d3a05b9f5dc0c
+Author: Keith Packard <keithp@keithp.com>
+Date: Fri Sep 6 18:24:46 2013 -0700
+
+ altosui: Include device name in Table view
+
+ It's part of the telemetry, so we might as well display it
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ae675c66594d366774d8f7f9c78f1236d3810eed
+Author: Keith Packard <keithp@keithp.com>
+Date: Fri Sep 6 18:23:06 2013 -0700
+
+ altoslib: TeleMetrum v2 telemetry includes computes Pa/°C, not raw values
+
+ Telemetry sends converted pressure/temp values as it doesn't include the
+ MS5607 calibration data.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 4e22b34bde421a9df090c9196fd4347468c8176a
+Author: Keith Packard <keithp@keithp.com>
+Date: Fri Sep 6 16:54:07 2013 -0700
+
+ altoslib: Add receiver serial to telem file names
+
+ Makes it easy to record telemetry from multiple sites and compare them later.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 0ad95614685a73856bb26a94866909e5fc025434
+Author: Keith Packard <keithp@keithp.com>
+Date: Fri Sep 6 16:52:51 2013 -0700
+
+ altosui: Set 'flight' value in AltosEepromMonitor window during download
+
+ This feature was lost in the AltosState updates
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit b66e0d4c107a0727279d03d1d0e1e40a9eaaa3bc
+Author: Keith Packard <keithp@keithp.com>
+Date: Fri Sep 6 16:52:06 2013 -0700
+
+ altosui: Load Telem files in AltosDataChooser too
+
+ Telem file loading was stubbed out from AltosState changes
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a1512255d20c8a395f30ed4914ddd3295842312b
+Author: Keith Packard <keithp@keithp.com>
+Date: Fri Sep 6 16:51:44 2013 -0700
+
+ altoslib: Add TeleMini eeprom file to Makefile.am
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 1e52d34137626ca756ea01f317ef7c359e464a5b
+Author: Keith Packard <keithp@keithp.com>
+Date: Fri Sep 6 16:50:46 2013 -0700
+
+ altoslib: Lock access to AltosLink config_data
+
+ Prevents multiple callers from trying to get config data at the same
+ time and messing up the serial line
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 29bb16397f14ed617ca3fbf48f2a7b726fd627d8
+Author: Keith Packard <keithp@keithp.com>
+Date: Fri Sep 6 16:49:36 2013 -0700
+
+ altoslib: Set 'valid' for valid TeleMetrum eeprom download
+
+ Had separate 'tick_valid' value, which wasn't useful as the supertype
+ didn't look there.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a299a5a9a1b89c7ebc00ebd33a789793a6835181
+Author: Keith Packard <keithp@keithp.com>
+Date: Fri Sep 6 16:48:52 2013 -0700
+
+ altoslib/altosui: Add TeleMini-v1.0 eeprom support
+
+ Got lost in the AltosState transition
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 82b3e3e4889aa5d4d157df1ad82e28068fda9e2a
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Sep 5 23:31:22 2013 -0700
+
+ altosui: Remove debugging printf from InfoTable
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 7f4650990e8a7cfcf8461e8928dfc426c9a563cc
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Sep 5 22:57:19 2013 -0700
+
+ altos: Set tick value in new TeleMetrum v2 sensor packets
+
+ Was getting left with the old value, which wasn't very useful
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 7314bf807544eecf2fd970e93c752ff15688bb42
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Sep 5 22:56:57 2013 -0700
+
+ ao-tools/ao-telem: Parse new TM v2 packets
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ffdf82445817d1c97699f7de82534420b87d0ea7
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Sep 5 22:56:11 2013 -0700
+
+ altosui: Fix 'Graph Flight' button in landed dialog
+
+ Telemetry file reading was broken (oops!)
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 0e3edacceb169326b8f5727bb5737d8238e9e40b
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Sep 5 22:55:43 2013 -0700
+
+ altoslib: Remove debug printf from AltosTelemetryMetrumSensor
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 59f0deff6d7bae22fb1b9a0649f3481b3d287d8e
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Sep 5 22:55:09 2013 -0700
+
+ altoslib: Rewrite AltosTelemetryIterable
+
+ Sort while reading instead of sorting separately.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit effc62354fc82bb937c6f445a147fc92153a0731
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Sep 5 22:54:02 2013 -0700
+
+ altoslib: Record time_change in AltosState correctly
+
+ time_change is used to make real-time playback work.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit b9ee58a7af839462680a0bdf1c1721017269986f
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Sep 5 22:53:14 2013 -0700
+
+ altoslib: Update received time when replaying flights
+
+ Received time is otherwise recorded as the time when the packets were
+ read from the file, which doesn't work in real-time playback
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e17e3691d93636eebbd7381f2df1303dc46ea96c
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Sep 5 22:52:22 2013 -0700
+
+ altoslib: Only open log file when both flight and serial are known
+
+ Some telemetry formats include serial and flight in different packets,
+ so wait for both before creating the file
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a9c495c7ca1e08b7ac76b0dab8b3bd9bd3a7edfc
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Sep 5 15:03:07 2013 -0700
+
+ altoslib: Use AltosTelemetry.parse to pull telem lines apart
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9f017b4837b106e8c422955a95762f1bf3c78016
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Sep 5 15:02:47 2013 -0700
+
+ altoslib: Remove more AltosRecord based files
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 984515452f9ab56dad112d725469acfa54e2233b
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Sep 5 11:55:24 2013 -0700
+
+ altoslib: remove AltosRecord based eeprom code
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3325df306933f080619f13ba1db45de484613d5a
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Sep 5 11:50:41 2013 -0700
+
+ altoslib: Remove AltosRecord-based telemetry code
+
+ All of this is now AltosState based
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e9e9c6592c49109288a4e02e780b130fadb97db7
+Author: Mike Beattie <mike@ethernal.org>
+Date: Tue Sep 3 15:11:33 2013 +1200
+
+ altosdroid: convert rogue files to unix line endings
+
+ Signed-off-by: Mike Beattie <mike@ethernal.org>
+
+commit 93e66b4911b7285f9095712ef746571153c3f088
+Author: Mike Beattie <mike@ethernal.org>
+Date: Thu Sep 5 03:11:42 2013 +1200
+
+ altosdroid: more updates for new AltosState
+
+ Signed-off-by: Mike Beattie <mike@ethernal.org>
+
+ Conflicts:
+ altosdroid/src/org/altusmetrum/AltosDroid/AltosVoice.java
+
+commit ee14ad16c242e8bd7a9d33ebf569211d1490b8e1
+Author: Mike Beattie <mike@ethernal.org>
+Date: Tue Sep 3 15:10:23 2013 +1200
+
+ altosdroid: update to support new state code
+
+ Signed-off-by: Mike Beattie <mike@ethernal.org>
+
+ Conflicts:
+ altosdroid/src/org/altusmetrum/AltosDroid/TabAscent.java
+ altosdroid/src/org/altusmetrum/AltosDroid/TabDescent.java
+ altosdroid/src/org/altusmetrum/AltosDroid/TabPad.java
+
+commit 5b976a6651f4eb05d30afc08b9e1f27c7e52ae00
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Sep 5 11:33:48 2013 -0700
+
+ altoslib: Finish AltosState changes. Update version number.
+
+ Removes all of the AltosRecord bits, changes the monitor idle bits to
+ have per-object state updaters.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit b984ff81d6b8979574e0248ffe8876634b8e1942
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Sep 3 17:42:42 2013 -0600
+
+ altoslib: Set measured acceleration for measured acceleration
+
+ Was setting computed acceleration even for measured data
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 96a651cc1b81b30f4cbde454e34cf80ed8825945
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Sep 3 17:42:00 2013 -0600
+
+ altoslib: Clear sat data when tick changes
+
+ Sat data comes in multiple records, but the tick is always the same,
+ so use that to tell when the set of sats is new
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 4de934c283a839fcbb246b36aa15362f3cf8629c
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Sep 3 17:41:12 2013 -0600
+
+ altoslib: Start integrated value at 0 by default
+
+ Check for MISSING and start at zero in that case
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit cfd8e4ebb3cb63937a71537095adb911d6211817
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Sep 3 17:40:04 2013 -0600
+
+ altoslib: Use first few baro samples for ground pressure on TM
+
+ TM didn't record the ground baro reading in the log file, so pull out
+ the first few measured baro samples and use those instead.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6ee99c1861ef1898a77aead41d80383e697bd248
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Sep 3 17:38:20 2013 -0600
+
+ altoslib: Make Ascent/descent use different filter values. Always filter.
+
+ In derivative code, use a shorter filter during ascent as the baro
+ sensor is cleaner then. Then, make sure to always filter the values as
+ the very first few baro samples can be noisy, which generates a bad
+ starting speed.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 70e67925cff98984d49fbc3f60e880c91e6d5079
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Sep 3 17:36:16 2013 -0600
+
+ altoslib: Remove duplicate cmd/tick from TM eeprom file code
+
+ Also replace tick setting with super call (which does that)
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit bc54014cfd4dbca67fa9db66e906ab8212a2eaa2
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Sep 3 17:35:23 2013 -0600
+
+ altoslib: Clean up metrum eeprom file reading
+
+ Spurious tick setting, fix some local variable names
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d203a2da2641bec21a4257c8a7b03d9a1eba53a5
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Sep 3 17:34:41 2013 -0600
+
+ altoslib: Correct mega/metrum eeprom years by adding 2000
+
+ The files contain a single byte for year, which is always years since 2000.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 999c3c7866613e658a6c26374499bc516bbc944d
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Sep 3 17:32:37 2013 -0600
+
+ altoslib: Correct tick wrapping in eeprom file reading
+
+ Just need to signal that at least one record has been read to know
+ when to start checking for wrap
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 7d3af3d74f70a0933829be91ad3e3be04b1f1023
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Sep 3 17:31:58 2013 -0600
+
+ altoslib: Ensure eeprom file body always exists
+
+ Create an empty list of body elements if none were read from the file
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 528e2e41112cad8a81bccbb89c3bd202b818a506
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Sep 2 23:10:23 2013 -0600
+
+ altoslib: More AltosState hacking
+
+ EasyMini graphs are looking good now.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 224a1e01bacb7db0076129906ed58e1c785e1b14
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Sep 2 23:08:34 2013 -0600
+
+ altos: Not all products have pins to control flash loader
+
+ TeleGPS has no exposed pins for this function
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 77dc89ed5b7bf8f5b3fa3b6131660f1a98f583ea
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat Aug 31 23:11:39 2013 -0500
+
+ altoslib/altosui: Further AltosState transition work
+
+ Parses most eeprom and telem records now; altosui updated to show from
+ AltosState info.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c781469ff907a32bd43a5d781391b6859b14cd32
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat Aug 31 23:10:56 2013 -0500
+
+ altos/telegps: Initialize logging system
+
+ Otherwise, very little logging works
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 7ec1b97d278c7aec3199fb7270f0dcf9484c879f
+Merge: 017ed54 4188153
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat Aug 31 08:22:09 2013 -0500
+
+ Merge branch 'master' into new-state
+
+commit 4188153548fca104bb49cda2d502c708fe4b49d7
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat Aug 31 08:20:48 2013 -0500
+
+ altos/lpc: Add bits for building flash loaders
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 017ed54ff69ef2f7740ea2578e22bf72e88deafb
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat Aug 31 08:19:28 2013 -0500
+
+ altoslib/altosui: Fixes for state changes
+
+ Format for gps alt (now double).
+ Use new code for csv file loading.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit f07f6d55edf5b97020680b3ce1d9e00bb3df64a6
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat Aug 31 01:48:02 2013 -0500
+
+ altoslib/altosui: Get legacy telem working with new AltosState structure
+
+ Make AltosTelemetry work without AltosRecord
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit de8d9c5630ae46378c50faf97f7d2e97fe139e30
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Aug 29 19:24:51 2013 -0500
+
+ altoslib, altosui: Restructured state management now does TM eeprom files
+
+ Removed uses of AltosRecord from AltosState, now just need to rewrite
+ the other AltosState changing code to match
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ce1378385ef273010498e81c205f42d8e32c7dc1
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Aug 29 19:22:18 2013 -0500
+
+ altos: Split EasyMini and TeleMini log formats
+
+ Same data, but EasyMini uses a 3.0V supply while TeleMini uses 3.3V,
+ which changes the intepretation of all of the ADC values
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 04d7d0f829ba953ffeca8ad9887a4b6b2b5d5087
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Aug 27 21:28:07 2013 -0600
+
+ altoslib: Start restructuring AltosState harder
+
+ Make per-packet code update state itself rather than having all state
+ updates done centrally. Will make adding new packet types easier.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit dcc51bb18985c24fa35bce0dd42ea3d847b960bf
+Merge: 7c82acc a73b025
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Aug 28 22:52:58 2013 -0600
+
+ Merge remote-tracking branch 'origin/telemini'
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+ Conflicts:
+ src/core/ao_telemetry.c
+ src/core/ao_telemetry.h
+
+ Added both Mini and Metrum telemetry defines
+
+commit 7c82acc1c1c5b7b4da7c7ecb3b2fd90140e4c703
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Aug 28 22:12:25 2013 -0600
+
+ altos/stm: Make sure we switch to MSI during timer init
+
+ Need to ensure that the CPU is actually using the MSI during timer
+ init or all of the other clock changes won't work
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6802b6a65b1fec06c2c873282be792c40b3c8f5e
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Aug 28 22:10:58 2013 -0600
+
+ altos/stm: Remove stale timer defines
+
+ Stuff from when we weren't using systick
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8e9ed70f50e3f535c2580820771bb1bc3cd055fe
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Aug 28 22:08:51 2013 -0600
+
+ altos/stm: Make sampling profiler work again
+
+ Disable the separate stack as that means we can't figure out the PC
+ from the timer interrupt. Move ao_idle_loc after the interrupt release
+ so that we see idle tasks correctly.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2fa87754c5c11bb86e9b1878580c3d4f4b2463f5
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Aug 28 22:08:04 2013 -0600
+
+ altos/stm: New compiler doesn't correctly build flash bits yet
+
+ Use /opt/cortex until we make the packaged one work
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 4887af0bf90661a3fdca76f1797a704888edab06
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Aug 28 22:04:18 2013 -0600
+
+ altos: Force u-blox to 9600 baud for now
+
+ The Max-7 parts just aren't happy switching baud rates, managing only
+ about half the time. Someday I'll figure out why, but until then, make
+ things work by just leaving the chips at 9600 baud
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 61163980f096d555a843e25cd9fe1aec93bbbbba
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Aug 28 22:02:48 2013 -0600
+
+ altos: Add debugging to ublox GPS driver
+
+ The new max 7 parts seem to be unhappy about switching baud rates, so
+ I've added a pile of debugging to help out. Some day, I'll figure out
+ how to make them work, this code is being left in place to help with that.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 44d4c66b21d6b5a0c656fdff6d01ef1d125c1101
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Aug 28 21:54:31 2013 -0600
+
+ altos: Update time for next alarm each time a task is added
+
+ Adding a task with a sooner timeout than existing alarm tasks was not
+ correctly updating the time to fire the next alarm, causing tasks to
+ be delayed by the wrong amount.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 39475c7b8da4f29936f73ffa2bff112f50ee9328
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Aug 28 21:52:29 2013 -0600
+
+ altos: TM v2 places the MMA6555 upside down compared to Tmega
+
+ Means we need to invert the data coming out to make it work
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit f222e8504bfd01027e3c380c239a2cde2c367d74
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Aug 27 22:00:29 2013 -0600
+
+ altos/telemetrum-v2.0: Use 9600 baud for ublox
+
+ Something is up with the Max 7
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit abde595116f6e8b60ec9ce81554c05de11fd456e
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Aug 27 21:36:02 2013 -0600
+
+ altos/telemetrum-v2.0: Fix MMA6555 SPI pin assignment
+
+ For TM v2.0, it's on PB 3-5, not PE13-15
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 454a41359b94e9bcf8582420abc359bbab9d8176
+Author: Keith Packard <keithp@keithp.com>
+Date: Fri Aug 23 11:25:56 2013 -0700
+
+ altos: Rename TeleMetrum v2.0 ADC sense members
+
+ Use sense_a and sense_m instead of sense[2]
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6aade70be0a7669d65a8606753d21e4eef5592cd
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Aug 20 14:20:56 2013 -0700
+
+ altos: Add TeleMetrum v2.0 boot loader
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 7b0f9b25a56fa8b4aa1c2e9d79c43e6a97cab0c0
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Aug 20 11:40:17 2013 -0700
+
+ altos: Initial TeleMetrum v2.0 bits
+
+ Adds new telemetry and logging formats along with code for TeleMetrum
+ v2.0 design.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a73b02518fcbc9fc0807ed8e141d3a06e8ad8214
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Aug 26 18:46:02 2013 -0700
+
+ altos: Don't use ao_data on cc1111 projects
+
+ cc1111 ao_adc.c supplies the needed globals at this point, and linking
+ both into the program leads to two different versions of each at
+ different addresses (yay SDCC linker!)
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d54156caf856ab5570f050692b333a2c5d991265
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Aug 26 18:44:23 2013 -0700
+
+ altos: Make ao_wakeup reentrant
+
+ In case we end up invoking it from two places at once.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 7e941695aa27e5eaf453ca1128b8d835472410a4
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Aug 26 18:43:20 2013 -0700
+
+ altos: Check for MS5607 MISO low before sleeping
+
+ If the MISO line goes low before we manage to configure the
+ interrupts, we'll miss it entirely unless we check the pin explicitly.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9b9acb88aa97e8565cdf9342fc59a5aee08e3d34
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Aug 26 17:18:57 2013 -0700
+
+ altos/telemini-v2.0: Add ao_exti.h depend. Init beeper and usb.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 7274b77666df9d2cab2854ec1a403d80e5fce73b
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Aug 26 17:18:17 2013 -0700
+
+ altos: Use %ld and %lu for MS5607 debug output
+
+ The value are 'long', so use the right printf format.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 4e3955a5b0ac125bd807920c467f959618449fbc
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Aug 26 17:17:47 2013 -0700
+
+ altos/cc1111: Wake up non-ADC sensor code each timer tick
+
+ Make sure the MS5607 code gets told to sample every tick
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3b2f83a7d686b5fbc0aaa56d48cb734f353631c8
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Aug 26 17:16:54 2013 -0700
+
+ altos/cc1111: Leave pin interrupts completely disabled at init time
+
+ Don't even turn in the PICTL bits as that seems to cause the chip to
+ be unhappy.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8ca98dc8c868c47c372d6b666c36e691fa402824
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Aug 26 17:15:55 2013 -0700
+
+ altos: Get telemini to copy current MS5607 state to ring.
+
+ The ADC code is responsible for actually inserting the non-ADC data
+ into the ring, so do the copy there.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit af9f9cf0c21630562c74fae41773319229bf44d3
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Aug 26 16:42:45 2013 -0700
+
+ cc1111: Hacky pin interrupt support. Only useful for TeleMini v2
+
+ This code is designed to support the MS5607 MISO interrupt bits.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2380a4b9bd69629c78eec0a87ff8681a0524d8d2
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Aug 26 16:41:33 2013 -0700
+
+ cc1111: Rework ADC configuration a bit, fix Tm V2 ADC usage
+
+ The Tm v2 ADC code was not actually fetching and storing the ADC
+ conversion values.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit aeb1c8a2aa533cb2805f0dbe848e098c8cae2b39
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Aug 26 16:39:47 2013 -0700
+
+ ao-tools: Use TeleDongle for default ao-dbg target
+
+ Makes more sense than assuming we're still using the old TI developer board.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 377a44cbfd5c8a659d2fecabb154726717a41900
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Aug 25 22:34:09 2013 -0700
+
+ altos: Build more products by default
+
+ We keep creating more hardware...
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e72147e215a982ce701099626424b9a856ac9d09
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Aug 25 22:33:30 2013 -0700
+
+ altos: Changes required by cc1111 multi-spi support
+
+ These drivers got missed
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit af6f4205b00669af40acffc528cc8093b0236cf6
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Aug 25 22:29:46 2013 -0700
+
+ Bump version to 1.2.9.2
+
+ Set version for Airfest testing
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 312f6194a4bc75473cb0d61a6d58b66fb1f7c068
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Jun 12 00:43:31 2013 -0700
+
+ altos/teletiny-v2.0: Support multiple SPI busses on CC1111
+
+ Needed for TeleMini v2.0
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2c2bbfd9a1a4b9de42cf566f21f179ff5ede0419
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu May 23 16:52:59 2013 -0600
+
+ altos: Add exti and spi to telemini-v2.0
+
+ No longer builds like this
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 56911f27376b0fe91a464e369bb8aa1531b3c7dc
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu May 23 02:17:51 2013 -0600
+
+ altos: Make TeleMini v2.0 fit
+
+ Mash lots of storage locations and code around to shrink stuff down to size
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit cb844328322fd7d9f4dafb58b322257a70b347e6
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed May 22 19:20:54 2013 -0600
+
+ altos: Add 64-bit subtraction
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 5ccd902d0fd2adc40c72982babb60fac4da6a087
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed May 22 17:08:55 2013 -0700
+
+ altos: Add 64x64 multiply. Test 64 ops for dest same as either source
+
+ The test change is to ensure that the destination may be one of the 64
+ bit sources.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit f7602ae566a5cbf2d2cbb1d68bad7e2d1177a33a
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed May 22 14:38:19 2013 -0700
+
+ altos: Make 64x16 mul a bit faster
+
+ the unsigned 32x32 multiply really does work, just use it
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3114baef45803250a2e5cdd2ee4a9171f2045b0c
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed May 22 14:32:50 2013 -0700
+
+ altos: Add 64-bit add/mul/shift for SDCC
+
+ SDCC doeesn't provide a native 64-bit type (sigh), so
+ implement the minimal operations necessary for the MS5607 conversion
+ routine.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d0b4e926ecececa7499a301b6135189be119512e
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed May 22 13:03:06 2013 -0700
+
+ Initial TeleMini bits
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3ded57394f6dfd7beb9526c031a5c6c6c9926917
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Aug 25 22:22:55 2013 -0700
+
+ altos: Explicitly list the linker script needed for AVR targets.
+
+ Something changed in the binutils-avr package which makes the linker
+ fail to find the script in the default location.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 203951f6e049ec7e95489849a2bfaa01aa19c0c9
+Merge: 4babe73 b363a62
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Aug 25 22:00:27 2013 -0700
+
+ Merge branch 'master' into telegps-v0.3
+
+commit b363a628fc6137c3395a48ef13de7a799ec3e2c3
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed May 22 19:31:15 2013 -0600
+
+ altos: MS5607 pressure computation for low temperatures was wrong
+
+ Second correction only applies to temps < -15°C, not 15°C.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit aa2948803d33dbee6f1eab30370178252df2b56d
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat Aug 17 17:45:06 2013 +0200
+
+ altos: Wake up on LPC usart ISR only once
+
+ Instead of waking up after every character, wait until the FIFO is
+ empty to reduce overhead
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 10f88c46df9a266f62452dc25275c79a3bb0653d
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat Aug 17 17:43:18 2013 +0200
+
+ altos: Set default LPC stack to 512 bytes, Em to 384 bytes
+
+ The default for lpc has been raised to 512 bytes, but Em doesn't have
+ enough RAM for that.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 41428d1e1e44a17eea5fda2b34cabafbdebf1464
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat Aug 17 17:35:08 2013 +0200
+
+ altosdroid: Add note to report TeleBT battery level
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e908eb090fc2aaa03b35dc37c3e008b05ad44d80
+Author: Keith Packard <keithp@keithp.com>
+Date: Fri Aug 23 11:24:18 2013 -0700
+
+ altos: Use installed arm compiler for LPC
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 1aed2eb5c7d477a2f3d4fada22980041aba97cb8
+Author: Keith Packard <keithp@keithp.com>
+Date: Fri Aug 23 11:22:10 2013 -0700
+
+ altos/lpc: Stop using burst mode for LPC ADC
+
+ Burst mode doesn't stop after one round of conversions, so we end up
+ getting incorrect values in whatever the last conversion register is.
+
+ Just use single conversions and take an interrupt per channel.
+
+ Also, slow down the ADC so that our values are more stable -- just
+ need to make sure we get the whole conversion sequence done 100 times
+ a second.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 4babe7310f78338ca36ab9d31ac833eada27485f
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat Aug 24 23:22:18 2013 -0700
+
+ altos: Allow products to disable RDF entirely
+
+ TeleGPS doesn't ever want RDF
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a1ec15f4585e23eb67affbe7d9d97261576b198d
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat Aug 24 23:21:53 2013 -0700
+
+ altos: Add telegps v0.3 product
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e2f385946132690ca6dc141d7c7830ae0cfe3458
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Aug 20 08:54:44 2013 -0700
+
+ altos: various cc115l driver hacks
+
+ Try to recover from TX_FIFO_UNDERFLOW by resetting the chip at idle
+ time.
+
+ Do a calibration phase during setup.
+
+ Program power to ramp up to limit key down noise.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 0dd55f66d79f54b450fd8122aecd84d68b810bf4
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat Aug 17 17:45:06 2013 +0200
+
+ altos: Wake up on LPC usart ISR only once
+
+ Instead of waking up after every character, wait until the FIFO is
+ empty to reduce overhead
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a0dd93ccf0920260b41c4003955617fd0cd1c8b4
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat Aug 17 17:43:18 2013 +0200
+
+ altos: Set default LPC stack to 512 bytes, Em to 384 bytes
+
+ The default for lpc has been raised to 512 bytes, but Em doesn't have
+ enough RAM for that.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9a22a300009679a14d66214a5d61e9e6a177279f
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat Aug 17 17:40:33 2013 +0200
+
+ altos: Allow ublox to run at other baud rates
+
+ Provides a configuration option to set the ublox serial baud rate to
+ something other than 57600 baud
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e0a0a747624c2df66ca4a73b5a0de014ea204dca
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat Aug 17 17:36:35 2013 +0200
+
+ altos: allow projects to override default config values
+
+ Override default radio power and APRS interval
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit bed68ef5a6999b2e23853958502a689a7dbc15b3
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat Aug 17 17:35:08 2013 +0200
+
+ altosdroid: Add note to report TeleBT battery level
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit f0e126251360f050b7121f167771c057bda8747e
+Merge: d95a2c5 4fe47ad
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat Aug 17 17:33:31 2013 +0200
+
+ Merge branch 'master' into telegps-v0.3
+
+commit 4fe47adc7aca54951a50b1c1ae95cb02e46f8d3d
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat Aug 17 17:30:52 2013 +0200
+
+ altosui: AltosDbm class was missing somehow
+
+ This doesn't appear to have been added?
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 4ff54bb96f6c00c0c2c7dd32f81403bac331621a
+Merge: fa0859a 01f8df0
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat Aug 17 16:03:26 2013 +0200
+
+ Merge remote-tracking branch 'origin/master'
+
+commit fa0859a51576efe231effcb5995f325f9e7e0fcb
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat Aug 17 16:01:44 2013 +0200
+
+ altos: Make FAT test program link explicitly against libcrypto
+
+ For some reason, the MD5_Final symbol isn't resolved when linking only
+ against libssl.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 01f8df088759ee7e6bc3900a013e0ea4fafaf984
+Merge: e2ebe60 15063cb
+Author: Bdale Garbee <bdale@gag.com>
+Date: Tue Jul 30 00:15:06 2013 -0600
+
+ Merge branch 'master' of ssh://git.gag.com/scm/git/fw/altos
+
+commit e2ebe60adf061479a1259a5c68b9cd5f5bacf644
+Author: Bdale Garbee <bdale@gag.com>
+Date: Tue Jul 30 00:14:41 2013 -0600
+
+ add a note about callsign matching and case sensitivity to the manual
+
+commit d95a2c5d1ddce913dcb1d1ab5dc59f6a588ab599
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Jun 24 14:29:43 2013 -0700
+
+ altos: Remove ao_radio_gpio_bits from normal build
+
+ Only needed for the CC115L_TRACE code, and it only builds on STM
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c542a2ed0f222bd0ec84e4a9651585d441dd7ccf
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Jun 24 14:29:01 2013 -0700
+
+ altos/lpc: Rename serial port to 'serial0'
+
+ This lets existing serial port users find the right function.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 324ceea43c115f4bed3a5276e57559c6c76b07c1
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Jul 2 17:54:38 2013 -0700
+
+ micropeak: Add Download button to menu bar
+
+ It's the most common activity, after all
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 156e60954fae15bc090984f79cd5594f910ca913
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Jul 2 17:53:51 2013 -0700
+
+ altosdroid: Just use GPS location provider to build on 4.2
+
+ Attempts to use the network provider cause the app to crash
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e148582217d6e02ac90a68e2bb2532947378d36f
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Jun 24 14:28:06 2013 -0700
+
+ altos: Support mega-style logging without ADC
+
+ Used for TeleGPS, just exposes the necessary log writing function
+ without also including the ADC writing code.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 261ec8fc7043e9314469e919aa96acc461f7e5f2
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Jun 24 14:26:23 2013 -0700
+
+ altosui: Add EasyMini USB ids
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 0dd148e388944d8d265da51d62806c4a00b2c13d
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Jun 24 14:23:53 2013 -0700
+
+ altos/lpc: Add boot loader
+
+ Support the USB boot loader, add USB pull-up support.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2568b36ae9d38ae1607ec08b84b06e0fe84bd3ba
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat Jun 22 00:53:38 2013 -0700
+
+ altos/telefire-v0.1: Use same LED selection as the v0.2 setup
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 58eda6f873f5d6e8e219f769bdf67ce4dbc96fd7
+Author: Keith Packard <keithp@keithp.com>
+Date: Fri Jun 21 19:40:59 2013 -0700
+
+ altos/lpc: Don't disable all interrupts when disabling one interrupt
+
+ The nvic iser and icer registers read value indicates all enabled
+ interrupts, icer writes disable the set interrupts. Re-writing icer
+ with the current value ends up disabling all interrupts, not exactly
+ what we wanted.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9081d881bc48bf7fdce617d300ac02c1a5962239
+Author: Keith Packard <keithp@keithp.com>
+Date: Fri Jun 21 19:40:03 2013 -0700
+
+ altos/lpc: Remove ao_usb_task structure
+
+ It's not used
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 23f11b188fc6aacd29e7f01a7d8a40853b7655df
+Author: Keith Packard <keithp@keithp.com>
+Date: Fri Jun 21 19:39:27 2013 -0700
+
+ altos/lpc: Enable brown-out-detector
+
+ Make sure the processor does something sensible when the power disappears.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e9e713bc8ab2080d5c1c38570b112f13c886bd11
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Jun 19 22:45:54 2013 -0700
+
+ altos/telefire: Radio status (no data, weak data, good data) on LEDs
+
+ Instead of blinking RX/TX, report the radio status on the telefire
+ nodes, just like telelco does. This makes the LEDs on telefire
+ *exactly the same* as the LEDs on telelco, which seems like a good idea.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d90c2fa650de4cdb008d5e2559463c08da8db934
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Jun 19 22:44:16 2013 -0700
+
+ altos: PCA9922 LED driver needs Enable driven low to latch values
+
+ Driving Enable high means anything going past on the clock and data
+ pair is reflected on the LEDs, which isn't terribly useful
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 572faa19b9a496866e3b589d5eb9f37a680206ab
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Jun 19 22:42:58 2013 -0700
+
+ altos/cc1111: Fetch RSSI for TeleFire from correct byte
+
+ Reading the status byte doesn't provide very useful RSSI info
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 025beb0fea011d0e3dab59b5d16e7ffae97c613c
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Jun 17 14:52:32 2013 -0700
+
+ altos/lpc: Get rid of ADC filter
+
+ Now that the source of the Vcc noise has been identified, remove the
+ unnecessary ADC filtering.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 10f3d0084ff1c0b3dbf28c5d44727b514caeee20
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Jun 17 14:00:43 2013 -0700
+
+ altosui: Add raw pressure to the AltosUI graph
+
+ A nice addition, and useful when diagnosing baro sensor issues
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 298e54856b5f8809b43f24407caa4a6be60822f3
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Jun 17 14:00:11 2013 -0700
+
+ altos/lpc: Get the IRC turned off after boot time
+
+ This involved carefully moving the USB away from the IRC before
+ turning it off.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit b3ad488477def157e277e239e81f164b49725925
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Jun 17 13:58:41 2013 -0700
+
+ altos: Disable USB on all flight computers when in flight mode
+
+ There was a check to only disable USB on boards with radios, but for
+ EasyMini, we want to disable USB too for flight mode.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2e2f3f2556e714833d8b7d0f65877b07b3dc2cb5
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Jun 16 22:32:16 2013 -0700
+
+ altos: Declare m25 write-in-progress as 'ao_port_t'
+
+ This lets us use port bits greater than 7 for M25 chip selects
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit dcf769198863c1b0f1b05f41d0c052a3dbfef247
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Jun 16 22:31:58 2013 -0700
+
+ altos/lpc: Remove spurious semicolon
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d040adeef9df4cda31dce603db81dc7ce19ec0d1
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Jun 16 22:31:31 2013 -0700
+
+ altos/lpc: Don't disable all of the clocks just yet, USB doesn't work
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 1676c7dbc3dcce2962be9ef9a58d37c7b48e3c0f
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Jun 16 15:07:54 2013 -0700
+
+ altos/lpc: Turn off more clocks, disable USART for easymini
+
+ Try to reduce noise on the power supply.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit be9ee9ed2d041c4ab4e77ee2010fe3c7a1ca6597
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat Jun 15 01:20:49 2013 -0700
+
+ altos/lpc: Filter ADC inputs
+
+ They're amazingly noisy on EasyMini, so just filter them as the only
+ thing we use them for is battery and pyro numbers.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 7361371190bf3805b6d0414e61f697aca7c7cff1
+Author: Keith Packard <keithp@keithp.com>
+Date: Fri Jun 14 04:38:11 2013 -0700
+
+ altos/lpc: Make ADC inputs work
+
+ They're still very unstable (bouncing around a lot), but at least they
+ seem to report useful stuff now.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6827d0a7c59d606ea05387465f1ad4d914babd49
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Jun 11 16:31:20 2013 -0700
+
+ altosui: Use preferred units for main deployment height configuration
+
+ Show and accept values in the preferred units; create a separate list
+ of preferred values for each set of units
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 15063cbb8f76bffea71575d295ca87b7ceca36d8
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Jun 9 23:18:09 2013 -0700
+
+ altos/telelco: Add 30ms delay in search after finding a box
+
+ This gives the remote boxes time to get back to listening for messages
+ after receiving the packet from the found box.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 988924b51980ad43e39bc4785a625ff25eb16449
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Jun 9 22:09:13 2013 -0700
+
+ altos: Add fast-timer API. Use for quadrature and button drivers
+
+ This splits the fast-timer portion out of the debounce helper code and
+ shares that with the quadrature driver which now uses it directly.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 72b6c699d355fcd41addb9919d846e63105b9db7
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon May 13 22:34:19 2013 -0700
+
+ altos: Add debounce helper. Use in button and quadrature drivers for TeleLCO
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 47b7e1d819e48aaebf6ffda49effbee041ce8750
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Jun 9 12:13:06 2013 -0700
+
+ altos/telefire: Leave siren on all the time. Add siren/strobe debugging.
+
+ The 50% duty cycle wasn't actually loud enough outside.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 187f661c2512e4260d0ca64134de8fad199f5944
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Jun 9 10:00:54 2013 -0700
+
+ altos: Add telefire v0.2 support
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8ba2035c78293bc312804722249df76dd4692d71
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Jun 9 09:53:07 2013 -0700
+
+ altos: Add driver for 74hc165 shift register
+
+ Just reads one byte from the shift register using the SPI driver and returns it
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3e8b72a9dc5b6c3a0f6132dc2dec04f8c08a1deb
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun May 26 22:38:56 2013 -0600
+
+ altos: Add pyro operations to regular ignite commands
+
+ Instead of having separate commands, just mix the two sets together.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 4bc1f3390b9ebbe07af4bc0f0a1c0915193ddf42
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun May 26 19:41:22 2013 -0600
+
+ Set version to 1.2.9.1
+
+ Mark bits to be used on Monday of NSL 2013
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6f131e740477d29b6623fa336da79e53f765a55b
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun May 26 19:48:03 2013 -0600
+
+ altos: Make manual pyro firing command work again
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 5ca472333a3587f0e47d54f5edc287494262ef98
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun May 26 19:47:02 2013 -0600
+
+ altos: write pyro fired to correct log field
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 956f4dff1cc521059434743624b1271fb92b96ae
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun May 26 19:39:13 2013 -0600
+
+ altos: Light pyro charges simultaneously if so configured
+
+ Don't try to be nice to the battery, just let the pyro circuit deal
+ with it and try to get all of the specified circuits going at the same
+ time if they're configured to do so.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 62547a042d042fadec652c5081f96816a8e66970
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun May 26 19:03:12 2013 -0600
+
+ altos,altosui: Add pyro state logging for TeleMega
+
+ Only in the log file (no obvious space in the telem packets), but at
+ least we should be able to check for pyro failures.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 277577fecc71e3c52b823938f396cf42be403ebe
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun May 26 19:01:58 2013 -0600
+
+ altos: Add pyro code testing to ao_flight_test for TeleMega
+
+ This parses the pyro settings and signals when the pyro channels are
+ fired in the output.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit b1408c13f176f3f021e9face48c4cd33528ee96c
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun May 26 18:58:41 2013 -0600
+
+ ao-tools/ao-mega: Dump 'pyro' state from mega log
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8083aa731c99d09bdd4a8c216bb11f846734d7df
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun May 26 18:57:58 2013 -0600
+
+ ao-tools: Add ao-mega tool to parse TeleMega eeprom files
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 21689ef744ddf43965ccad89dc1133a905011d7f
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun May 26 18:54:02 2013 -0600
+
+ altosui: Missing 'break' after selecting 'mega' format detection
+
+ Caused 'mega' logs to be dumped in 'mini' format which didn't work well.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 17e0ccccc8619f96d2cf56bd98d63a7e59f5301d
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun May 26 18:50:10 2013 -0600
+
+ altosui: Stop downloading mega eeprom on empty block
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 013cba5ed1fde72240a68ec648bd14977f5e48a4
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon May 20 21:41:01 2013 -0700
+
+ doc: Update description of graph window to note new tabs (config and map)
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e711c708b0d2c8d8c2d72e34a795ad8e9b5ab5de
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon May 20 21:37:20 2013 -0700
+
+ Create release notes for 1.2.1
+
+ Move most of the 1.2 content to the 1.2.1 block
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2344ba81fa51215471099e56518112478bdf2e73
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue May 21 11:31:05 2013 -0700
+
+ Separate out cortex-m0 compiler tests in configure
+
+ The summon arm toolchain doesn't work for cortex-m0 parts, but the
+ linaro toolchain does. Look in /usr/bin for the -m0 compiler but
+ continue to use /opt/cortex/bin for the -m3 compiler
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 85eb75c3251d8e141d7269fc7ffa6197174ea8c3
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue May 21 11:30:44 2013 -0700
+
+ altos: Can't use inline functions because SDCC doesn't do that
+
+ Sigh.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit fd5567882b732f8947b44b217552077c82a3d28e
+Merge: fd55c1f 57b4d82
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue May 21 11:16:54 2013 -0700
+
+ Merge branch 'lpc'
+
+commit fd55c1fe53adf5c50dcd3ce8296f80871cec73e9
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue May 21 11:16:33 2013 -0700
+
+ Bump master version to 1.2.9 to avoid confusion with 1.2 releases
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 1bffe8caf0294e9cfef2dab1c6b5a8d1d87ac3a2
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue May 21 11:08:15 2013 -0700
+
+ altos: Set the path for the STM32L compiler explicitly
+
+ This makes sure we use the known toolchain for STM32L builds
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 7282fab337dc48d32606276e5f51c057a3bff8cb
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue May 21 11:04:25 2013 -0700
+
+ altosui: Add TeleBT firmware to release
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 57b4d82dee10b142b820aa306028a288a85214f6
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun May 19 23:07:54 2013 -0700
+
+ Add Mini logging format. Use in EasyMini
+
+ This is a 16-byte record that includes all of the sensor data in each
+ sensor record, along with records for flight state changes.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 27e9b93f3d35890a49575b2ead1983ce3c2fc213
+Merge: a4df257 d9cbef8
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun May 19 20:40:42 2013 -0700
+
+ Merge branch 'master' into lpc
+
+commit d9cbef8cd364aae54855cc5bc64fb8c2b22057b0
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun May 19 20:35:42 2013 -0700
+
+ altos/telemega: The last two igniters are apogee and main
+
+ Not the first two. TeleMega v0.3 has these marked on the silk
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a4df2575b4e782e83cc4e9b1d2e5cd2397a97dd8
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun May 19 20:33:35 2013 -0700
+
+ altos/easymini: Initialize beep and ADC. Declare use of igniter bits.
+
+ This makes easymini actually work!
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a87a8e8067d7b2d0ff3a3274af9f1e919b5b7793
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun May 19 20:32:34 2013 -0700
+
+ altos/easymini: Use different pins for igniter outputs
+
+ Was using the I2C outputs which are open drain, which makes it
+ impossible to force them high as needed to driver our igniters.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 16eb0b04df3d1db65bd40717133abe94db0f2a15
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun May 19 20:31:48 2013 -0700
+
+ altos/easymini: MS5607 chip select bits were defined wrong
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 455802b7e853956180799c058e9561876d98d831
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun May 19 20:30:49 2013 -0700
+
+ altos/easymini: Easymini doesn't have USB connect or VBUS wiring
+
+ Disable these in ao_pins.h
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 35b120c4154df0351c3a802f86dda224a7643068
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun May 19 20:27:53 2013 -0700
+
+ altos/lpc: Force idle mode if USB gets an address during boot time
+
+ This lets EasyMini be booted to idle mode by simply plugging it into USB.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c1f01cd4406063191a51cb68fc4634eabfc60fc2
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun May 19 20:27:05 2013 -0700
+
+ altos/lpc: Reset SPI device at startup time
+
+ Wasn't doing the reset sequence correctly (write 0, then write 1).
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e0ad8b5b5e1b4c7a9ffba9d25f3c32ce708c3ec5
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun May 19 20:26:07 2013 -0700
+
+ altos/lpc: Configuring wrong pin for SPI1 MOSI
+
+ Was setting configuration for PIO1_21 instead of PIO0_21.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit b9bb088a36fd351809f4c378356327ffa663c974
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun May 19 20:25:13 2013 -0700
+
+ altos/lpc: Allow for alternate SPI SCLK0 pin usage
+
+ SPI SCLK0 can appear on three different pins; let the application
+ configure which one it wants.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 397109139fb9ff27ec7cfb0cafa65d1dbea053bd
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun May 19 20:24:11 2013 -0700
+
+ altos/lpc: Leave SPI enabled all the time
+
+ Might be able to turn it off with some care; more experimentation required.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e383d7a28d01729c50f933ceda77ea767d1b8087
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun May 19 20:22:20 2013 -0700
+
+ altos/lpc: Create TX/RX busy macros for SPI driver
+
+ Check for both fifo status *and* device busy to make sure the device
+ is idle before we touch any registers.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 07d261c08214837b5d5cac4d2be43e51a0c47868
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun May 19 20:19:15 2013 -0700
+
+ altos/lpc: Fix beeper driver
+
+ Set prescale limit, not current prescale value (pr instead of pc).
+ Flip output 1 on PWM match (set emc toggle for channel 1).
+ Don't hold counter in reset (turn off CRST bit).
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3fe11b277dd7268eb445d120c8f9537f95148891
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun May 19 20:18:44 2013 -0700
+
+ altos/lpc: Missing parens around ao_gpio_set macro
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a78012782c779de3433b91e6b854b2fdbd7230fd
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun May 19 20:17:48 2013 -0700
+
+ altos/lpc: SPI runs off main clock (48MHz), not sysclk (24MHz)
+
+ Update SPI speed definitions to match
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d51c9fda3478f205e4bcdf1b7bf21eb1e0a516bc
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun May 19 20:07:52 2013 -0700
+
+ altos/lpc: Pull ADC data from the correct registers
+
+ Was just stepping through register space arbitrarily, which would have
+ worked for EasyMini, but might have failed later if the ADC pin usage
+ wasn't consecutive.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
- Merge branch 'branch-1.2' of ssh://git.gag.com/scm/git/fw/altos into branch-1.2
+commit 6343bd774f542a4f915cf1fca2053d03e93bf2c3
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun May 19 20:06:03 2013 -0700
-commit 9b138221283f0b8e8df5a799f75d73fd456028a0
-Author: Bdale Garbee <bdale@gag.com>
-Date: Tue May 21 09:29:30 2013 -0600
+ altos/lpc: Don't use loader to place USB endpoint data in USB ram
+
+ Instead, just assign a fixed address in registers.ld. This avoids a
+ confusing section in the elf file.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
- update changelog for 1.2.1 release
+commit 35a05041d3ca3e69a146bd3bf8038c0f1cbc1b42
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun May 19 20:04:29 2013 -0700
-commit 6f51726b1c04940c5be3b6f320d6aa529afff9ca
-Author: Bdale Garbee <bdale@gag.com>
-Date: Tue May 21 09:28:53 2013 -0600
+ altos: Add EXTI_PIN_NOCONFIGURE to exti interface, use for MS5607
+
+ This asks the EXTI code to not mess with the pin configuration so that
+ the MS5607 driver can get interrupts on the MISO pin while still using
+ it for SPI.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 098fd43a740ee2a782f82b6b71965b60cdba2d62
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun May 19 20:00:24 2013 -0700
- update configure.ac to reflect version 1.2.1
+ altos/lpc: Make EXTI code work.
+
+ Clear rise/fall bits in ISR to avoid re-entering.
+ Block interrupts around enable/disable bits.
+ Create shared _ao_exti_set_enable function to control mask changes.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
-commit 03fe10efd307da10e35c5f6a46f0c8b1a3888c57
+commit f794e6c95697b034be315632fddb3a5475c43b5b
Author: Keith Packard <keithp@keithp.com>
-Date: Mon May 20 21:41:01 2013 -0700
+Date: Sun May 19 19:57:23 2013 -0700
- doc: Update description of graph window to note new tabs (config and map)
+ altos: Use ao_spi_get/put_bit in MS5607 driver
+
+ Replace open-coded ao_spi_get/put and ao_gpio_set sequences
Signed-off-by: Keith Packard <keithp@keithp.com>
-commit db9ea188aebe5299f46bbd4fca5317c1bc95f3f5
+commit b7ab41e4dc92dcd382f4c05459088d8df8b70075
Author: Keith Packard <keithp@keithp.com>
-Date: Mon May 20 21:37:20 2013 -0700
+Date: Sun May 19 19:51:32 2013 -0700
- Create release notes for 1.2.1
+ altos/attiny: Fix ao_spi_get_bit/ao_spi_put_bit macros
- Move most of the 1.2 content to the 1.2.1 block
+ These were never written, so just use ao_spi_get/put_mask.
+
+ A precursor to changing how the MS5607 drives the SPI bus
Signed-off-by: Keith Packard <keithp@keithp.com>
-commit 51f2c4ce2692ee3e898b4e94232c45a608932c15
+commit 49f9cdda5f1812687b82915acc78a9d9136255bf
Author: Keith Packard <keithp@keithp.com>
-Date: Sun May 19 20:35:42 2013 -0700
+Date: Sat May 18 03:54:30 2013 -0700
- altos/telemega: The last two igniters are apogee and main
+ altos: ignore built files in easymini-v0.1
- Not the first two. TeleMega v0.3 has these marked on the silk
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c57e1630002c921739ff22395497d93027d381b6
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat May 18 03:53:32 2013 -0700
+
+ altos: Build easymini-v0.1
Signed-off-by: Keith Packard <keithp@keithp.com>
-commit 8d40c37bae0c58037f267e54de40071cd19c931d
+commit 278300b2bc98b92cc71ec016ab0fc93eb3696435
Author: Keith Packard <keithp@keithp.com>
-Date: Fri May 17 03:27:20 2013 -0700
+Date: Sat May 18 03:52:59 2013 -0700
- libaltos: Build the linux library targets when doing a 'fat' build
+ altos: Initialize SPI for easymini
- These are necessary for the fat release, so make sure they're built then.
+ Doesn't work very well without this
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit cbe5eee76faf386eefe69539935ab318944ac452
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat May 18 03:52:14 2013 -0700
+
+ altos/lpc: Stick USB control structure in USB memory
+
+ No reason to have that in regular ram, and it means we've got space
+ for large enough stacks now
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3587bfd248e115bb1abb28f71b263575b4e8e367
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat May 18 03:22:10 2013 -0700
+
+ altos: Add easymini-v0.1 product
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c4991db4809ae547fdb245e3cb42517fa7524de5
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat May 18 03:21:43 2013 -0700
+
+ altos/lpc: Use separate interrupt stack
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 5311720525ac73e9d42067b68adf25fc2e054af5
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat May 18 03:21:20 2013 -0700
+
+ altos/lpc: Try a smaller stack.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit f5218e2544dcb659aec6c3adee50d61cab1bba3a
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat May 18 03:19:41 2013 -0700
+
+ altos/lpc: Add pin interrupt driver
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c0d0147251bfcebd753196b74c22c00c3116fd22
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat May 18 03:18:55 2013 -0700
+
+ altos/lpc: Add beep driver
+
+ Hardwired to our current beeper pin
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 166977c65bddb50d600a3c1e1f278c425b673697
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat May 18 03:18:19 2013 -0700
+
+ altos/lpc: Add ADC driver
+
+ Uses burst mode to get the whole set of values in one interrupt
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ed25a46571d988ccf37ae915dff97b5f00bcf9cf
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat May 18 03:16:41 2013 -0700
+
+ altos/lpc: add gpio int, spi, adc and ct32b defines to lpc.h
+
+ Lots more devices
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2b0b7bf1462341718e582223a880f2dfcd79e2ad
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat May 18 03:15:58 2013 -0700
+
+ altos/lpc: Clean up broken IOCONF defines
+
+ Missing comment closes
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 08887678f900adae81dcb1a7f5353d98d127aafd
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat May 18 03:14:57 2013 -0700
+
+ altos/lpc: Fix ao_enable_input, add ao_enable_analog
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 15ca452b60271e3a0f7327216df04eef5b985240
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat May 18 03:14:16 2013 -0700
+
+ altos: LPC interrupt priorities are just 0-3
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 935a7ff38010ec4ad19f315f8a2a1557c01ae554
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat May 18 03:13:17 2013 -0700
+
+ altos: Add LPC spi driver
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d9b42470e8889b44bb08858a610285410a200ab9
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat May 18 03:02:38 2013 -0700
+
+ altos: Use ao_port_t in m25 driver
+
+ This uses ao_port_t for all of the chip select masks
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 28890aa5893898cd0bb0ac033e491eb307a84ca5
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat May 18 03:02:01 2013 -0700
+
+ altos: Use ao_data_pres macro in ao_log_tiny
+
+ Now it works on easymini too
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 82afe3a3b737c43dbeaad41ea5af1841357297a6
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat May 18 02:54:55 2013 -0700
+
+ altos: Check for packet mode before trying to disable it in flight code
+
+ This is only relevant for telemini
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 52063c2679752033135fff928c7686e368d2a825
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat May 18 02:54:30 2013 -0700
+
+ altos: ao_data_get is in ao_data.c now, not ao_adc.c
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e4385d29fc1b233b3ad56d4af68a175e760c1751
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat May 18 02:53:32 2013 -0700
+
+ altos: Allow architecture to define the type of port registers
+
+ LPC11U14 has 32-bit ports, STM32 has 16 bit ports.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ca4f3161258356c06fe1270f7ccdf0d6939e2d34
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat May 18 02:52:49 2013 -0700
+
+ altos: Move ao_data.c from stm to core
+
+ This should be used on every processor
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ac089d4fb930b7dbc4161259fd9bddba94395ebc
+Author: Keith Packard <keithp@keithp.com>
+Date: Fri May 17 03:36:47 2013 -0700
+
+ altos/lpc: Get USB working
+
+ The lpc demo now has a USB command line.
+ Also allocates system stack so we know when ram is tight at build time
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 185e6d15bcda229949a984910d7394203d301db9
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu May 16 18:58:24 2013 -0700
+
+ altos: Allow target-specific USB endpoint specifications
+
+ The LPC has only a small number of endpoints, and those are not
+ configurable. Let the LPC USB driver pick the IN and OUT endpoints by itself.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6c35e21a86ab32bc91eb10a60c071b702fc0f963
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue May 7 19:27:17 2013 -0700
+
+ altos: Finish off LPC USB register definitions
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 918342016705303baa1630c62c290aaf2dcc2801
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Apr 25 20:38:32 2013 -0700
+
+ altos/lpc: Start adding USB register defines
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 91d201abcbe9373360919406427b7e4fb9e1b42e
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Apr 22 17:10:24 2013 -0500
+
+ altos/lpc: Start adding USB register definitions
+
+ Just the bare struct, no defines yet.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9bf67798b134ad796c2f4bc9240ee450722148ec
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat Apr 20 00:40:38 2013 -0500
+
+ altos/lpc: Take advantage of USART TX fifo
+
+ The USART has a 16-byte TX fifo; keep rough track of how full it is to
+ avoid waiting for an interrupt after every TX byte.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9e8f6ba8b779cd9635f82d6da5f113715c3ee4c7
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat Apr 20 00:20:55 2013 -0500
+
+ altos/lpc: Get USART running
+
+ Adds a simple demo thread that spews data to the serial port
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit f9d0eb3f3154f98abb0c8952d7171f3e7d3de9b2
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Apr 18 16:15:52 2013 -0500
+
+ altos/lpc: Get 100Hz timer running
+
+ Use systick, which is built into the ARM core
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 04b243e6ef212f54ed284cfbde6d5abb637bf60e
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Apr 18 15:55:26 2013 -0500
+
+ lpcxpresso: Add ao_demo.c
+
+ Kinda necessary for the demo to build
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit bcc65597d3d20f1d58df784100af766cee5f0f20
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Apr 18 15:54:13 2013 -0500
+
+ lpc: Initial lpcxpresso bits
+
+ This gets the LPC11U14 clock set to the PLL and blinks the LED.
Signed-off-by: Keith Packard <keithp@keithp.com>
-commit fbe7857e371fa8ffa726fda2b43d4eddd551eaa4
+commit 6735a391c2a1e3be01ac9e68b44ec0974592c11c
Author: Keith Packard <keithp@keithp.com>
Date: Fri May 17 03:34:50 2013 -0700
Signed-off-by: Keith Packard <keithp@keithp.com>
-commit 3b457ff8d43630c04e0cb22bb3a2765be5e188bd
+commit bd8d061d0f63158b5b03814d77cb76fdf5a0abad
+Author: Keith Packard <keithp@keithp.com>
+Date: Fri May 17 03:27:20 2013 -0700
+
+ libaltos: Build the linux library targets when doing a 'fat' build
+
+ These are necessary for the fat release, so make sure they're built then.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8a19805a6b079450b5afd5fa2334cede8495ae4a
Author: Keith Packard <keithp@keithp.com>
Date: Fri May 17 03:21:08 2013 -0700
Signed-off-by: Keith Packard <keithp@keithp.com>
-commit 7699a55aed3a9a7daeb4c6a5a9a280f43edf455f
-Author: Bdale Garbee <bdale@gag.com>
-Date: Thu May 16 00:34:26 2013 -0600
+commit 4ef0136c27e8f47a1eb38f9cbcd2c61288732d78
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed May 15 15:32:59 2013 -0700
+
+ altos: Generate unmodulated carrier for CC1120 test mode
+
+ This sets the deviation to 0, enables the preamble and turns on the
+ transmitter. It will sit there happily sending a bare carrier forever
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 1931e028bebc3cd8df9392e30eb0e888d0799768
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue May 14 22:29:06 2013 -0700
+
+ altos: Move MS5607 info from 'v' to 'c s'
+
+ Makes more sense there.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 69b9f613ad36b8039f223ed30f8c75913916d82c
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue May 14 22:19:07 2013 -0700
+
+ altos: Remove some MMA655x debugging printfs
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 0571531066918fdefe9447f3b4192d0c6c477afa
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue May 14 10:48:24 2013 -0700
+
+ altos: Grab SPI mutex until MPU6000 I2C mode is disabled
+
+ If other drivers use the SPI bus, the MPU6000 gets confused as its
+ sitting on the bus looking for I2C messages. Just grab the mutex
+ before the OS is running and hold onto it until the MPU6000 has been initialized.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9beacd77b3e8106e036e50a67312dfee414fbc51
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue May 14 09:01:49 2013 -0700
+
+ altos: Initialize MPU6000 CS pin for SPI mode
+
+ Without this, we can't talk to the chip very well
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6d553230903ddd0ec522c07be0df975b38ef23d3
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue May 14 09:56:16 2013 -0700
+
+ altos: Fix telemega v0.3 igniter order (drogue/main moved). Label ADC dump
+
+ telemega moves the igniters around so that E/F are now drogue/main.
+ Add custom labels for ADC values to make parsing possible
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a4e4eec827d61a05fda52ddb68b55f17b6028d5e
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue May 14 09:25:08 2013 -0700
+
+ altos: gps serial routines are called ao_gps_*, not ao_ublox_*
+
+ This caused the u-blox driver to use serial port 1 instead of the
+ project-specified serial port.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 461215eea72ff9d64748304e76b08da37ee3dfe9
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue May 14 09:21:54 2013 -0700
+
+ altos: Give u-blox 3 seconds after boot before we bug it
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 5e9193f6375be27e5f7a0321fd34b6acfe81247f
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue May 14 09:12:29 2013 -0700
- update ChangeLog for release
+ altos: Add 'g' command to ublox GPS code.
+
+ Take the gps_dump function from ao_gps_skytraq.c and move it to a new
+ file so it can be shared with the u-blox driver. That affects every
+ skytraq and u-blox user as they need to include the new file.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit cdad289a0803babecd30cbc0a95be99c5caadeb5
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed May 15 01:24:56 2013 -0700
+
+ altos: Add flash-loader for telescience-v0.2
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+>>>>>>> branch-1.3
commit 116d8570766fbd3ef529111171935637a2e466af
Author: Keith Packard <keithp@keithp.com>
-SUBDIRS=src doc altoslib libaltos altosuilib altosui micropeak ao-tools ao-utils altosdroid
+SUBDIRS=ao-tools src doc altoslib libaltos altosuilib altosui micropeak ao-utils altosdroid
EXTRA_DIST = ChangeLog
These are Bdale's notes on how to do a release.
- - make sure there's a suitable ARM Cortex toolchain in /opt/cortex!
-
git checkout master
- make sure there is a doc/release-notes-<version>.xsl
- update the version in configure.ac
git log > ChangeLog
git commit -a
+
- make absolutely sure checked-out tree is "clean"
+ - make absolutely sure the pdclib/ submodule is on the master branch,
+ up to date, and "clean"
+
- if this is an x.y release, then:
git checkout -b branch-<version>
git tag -a <version>
git commit -n debian/changelog -m "update changelog for Debian build"
- if this is a -1 release, then
- git-buildpackage --git-no-pristine-tar
+ git-buildpackage --git-no-pristine-tar --git-submodules
pristine-tar commit \
../build-area/altos/altos_<version>.orig.tar.gz \
branch-<version>
else if this is not a -1 release
- git-buildpackage
+ git-buildpackage --git-submodules
git tag debian/<version>
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.altusmetrum.AltosDroid"
- android:versionCode="3"
- android:versionName="1.2">
+ android:versionCode="4"
+ android:versionName="1.3">
<uses-sdk android:targetSdkVersion="10" android:minSdkVersion="10"/>
<!-- Google Maps -->
<uses-feature android:glEsVersion="0x00020000" android:required="true"/>
'find my rocket' mode after shutting down the application.
*) Imperial Units mode
+
+ *) TeleBT battery voltage
//import android.os.Message;
import android.util.Log;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
public class AltosBluetooth extends AltosLink {
}
}
+ public void putchar(byte c) {
+ byte[] bytes = { c };
+ if (D) Log.d(TAG, "print(): begin");
+ try {
+ wait_connected();
+ output.write(bytes);
+ if (D) Log.d(TAG, "print(): Wrote byte: '" + c + "'");
+ } catch (IOException e) {
+ connection_lost();
+ } catch (InterruptedException e) {
+ connection_lost();
+ }
+ }
+
public int getchar() {
try {
wait_connected();
import android.app.AlertDialog;
import android.location.Location;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
public class AltosDroid extends FragmentActivity {
// Debugging
case MSG_CRC_ERROR:
case MSG_UPDATE_AGE:
if (ad.saved_state != null) {
- ad.mAgeView.setText(String.format("%d", (System.currentTimeMillis() - ad.saved_state.report_time + 500) / 1000));
+ ad.mAgeView.setText(String.format("%d", (System.currentTimeMillis() - ad.saved_state.received_time + 500) / 1000));
}
break;
}
}
if (state != null) {
- mCallsignView.setText(state.data.callsign);
- mSerialView.setText(String.format("%d", state.data.serial));
- mFlightView.setText(String.format("%d", state.data.flight));
- mStateView.setText(state.data.state());
- mRSSIView.setText(String.format("%d", state.data.rssi));
+ mCallsignView.setText(state.callsign);
+ mSerialView.setText(String.format("%d", state.serial));
+ mFlightView.setText(String.format("%d", state.flight));
+ mStateView.setText(state.state_name());
+ mRSSIView.setText(String.format("%d", state.rssi));
}
for (AltosDroidTab mTab : mTabs)
static String pos(double p, String pos, String neg) {
String h = pos;
- if (p == AltosRecord.MISSING)
+ if (p == AltosLib.MISSING)
return "";
if (p < 0) {
h = neg;
}
static String number(String format, double value) {
- if (value == AltosRecord.MISSING)
+ if (value == AltosLib.MISSING)
return "";
return String.format(format, value);
}
static String integer(String format, int value) {
- if (value == AltosRecord.MISSING)
+ if (value == AltosLib.MISSING)
return "";
return String.format(format, value);
}
import android.content.SharedPreferences;
import android.os.Environment;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
public class AltosDroidPreferences implements AltosPreferencesBackend {
public final static String NAME = "org.altusmetrum.AltosDroid";
package org.altusmetrum.AltosDroid;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
import android.location.Location;
public interface AltosDroidTab {
-/*\r
- * Copyright © 2011 Keith Packard <keithp@keithp.com>\r
- * Copyright © 2012 Mike Beattie <mike@ethernal.org>\r
- *\r
- * This program is free software; you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation; version 2 of the License.\r
- *\r
- * This program is distributed in the hope that it will be useful, but\r
- * WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
- * General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License along\r
- * with this program; if not, write to the Free Software Foundation, Inc.,\r
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.\r
- */\r
-\r
-package org.altusmetrum.AltosDroid;\r
-\r
-import android.speech.tts.TextToSpeech;\r
-import android.speech.tts.TextToSpeech.OnInitListener;\r
-\r
-import org.altusmetrum.altoslib_1.*;\r
-\r
-public class AltosVoice {\r
-\r
- private TextToSpeech tts = null;\r
- private boolean tts_enabled = false;\r
-\r
- private IdleThread idle_thread = null;\r
-\r
- private AltosState old_state = null;\r
-\r
- public AltosVoice(AltosDroid a) {\r
-\r
- tts = new TextToSpeech(a, new OnInitListener() {\r
- public void onInit(int status) {\r
- if (status == TextToSpeech.SUCCESS) tts_enabled = true;\r
- if (tts_enabled) {\r
- idle_thread = new IdleThread();\r
- }\r
- }\r
- });\r
-\r
- }\r
-\r
- public void speak(String s) {\r
- if (!tts_enabled) return;\r
- tts.speak(s, TextToSpeech.QUEUE_ADD, null);\r
- }\r
-\r
- public void stop() {\r
- if (tts != null) tts.shutdown();\r
- if (idle_thread != null) {\r
- idle_thread.interrupt();\r
- idle_thread = null;\r
- }\r
- }\r
-\r
- public void tell(AltosState state) {\r
- if (!tts_enabled) return;\r
-\r
- boolean spoke = false;\r
- if (old_state == null || old_state.state != state.state) {\r
- speak(state.data.state());\r
- if ((old_state == null || old_state.state <= AltosLib.ao_flight_boost) &&\r
- state.state > AltosLib.ao_flight_boost) {\r
- speak(String.format("max speed: %d meters per second.", (int) (state.max_speed() + 0.5)));\r
- spoke = true;\r
- } else if ((old_state == null || old_state.state < AltosLib.ao_flight_drogue) &&\r
- state.state >= AltosLib.ao_flight_drogue) {\r
- speak(String.format("max height: %d meters.", (int) (state.max_height + 0.5)));\r
- spoke = true;\r
- }\r
- }\r
- if (old_state == null || old_state.gps_ready != state.gps_ready) {\r
- if (state.gps_ready) {\r
- speak("GPS ready");\r
- spoke = true;\r
- } else if (old_state != null) {\r
- speak("GPS lost");\r
- spoke = true;\r
- }\r
- }\r
- old_state = state;\r
- idle_thread.notice(state, spoke);\r
- }\r
-\r
-\r
- class IdleThread extends Thread {\r
- boolean started;\r
- private AltosState state;\r
- int reported_landing;\r
- int report_interval;\r
- long report_time;\r
-\r
- public synchronized void report(boolean last) {\r
- if (state == null)\r
- return;\r
-\r
- /* reset the landing count once we hear about a new flight */\r
- if (state.state < AltosLib.ao_flight_drogue)\r
- reported_landing = 0;\r
-\r
- /* Shut up once the rocket is on the ground */\r
- if (reported_landing > 2) {\r
- return;\r
- }\r
-\r
- /* If the rocket isn't on the pad, then report height */\r
- if (AltosLib.ao_flight_drogue <= state.state &&\r
- state.state < AltosLib.ao_flight_landed &&\r
- state.range >= 0)\r
- {\r
- speak(String.format("Height %d, bearing %s %d, elevation %d, range %d.\n",\r
- (int) (state.height + 0.5),\r
- state.from_pad.bearing_words(\r
- AltosGreatCircle.BEARING_VOICE),\r
- (int) (state.from_pad.bearing + 0.5),\r
- (int) (state.elevation + 0.5),\r
- (int) (state.range + 0.5)));\r
- } else if (state.state > AltosLib.ao_flight_pad) {\r
- speak(String.format("%d meters", (int) (state.height + 0.5)));\r
- } else {\r
- reported_landing = 0;\r
- }\r
-\r
- /* If the rocket is coming down, check to see if it has landed;\r
- * either we've got a landed report or we haven't heard from it in\r
- * a long time\r
- */\r
- if (state.state >= AltosLib.ao_flight_drogue &&\r
- (last ||\r
- System.currentTimeMillis() - state.report_time >= 15000 ||\r
- state.state == AltosLib.ao_flight_landed))\r
- {\r
- if (Math.abs(state.baro_speed) < 20 && state.height < 100)\r
- speak("rocket landed safely");\r
- else\r
- speak("rocket may have crashed");\r
- if (state.from_pad != null)\r
- speak(String.format("Bearing %d degrees, range %d meters.",\r
- (int) (state.from_pad.bearing + 0.5),\r
- (int) (state.from_pad.distance + 0.5)));\r
- ++reported_landing;\r
- }\r
- }\r
-\r
- long now () {\r
- return System.currentTimeMillis();\r
- }\r
-\r
- void set_report_time() {\r
- report_time = now() + report_interval;\r
- }\r
-\r
- public void run () {\r
- try {\r
- for (;;) {\r
- set_report_time();\r
- for (;;) {\r
- synchronized (this) {\r
- long sleep_time = report_time - now();\r
- if (sleep_time <= 0)\r
- break;\r
- wait(sleep_time);\r
- }\r
- }\r
- report(false);\r
- }\r
- } catch (InterruptedException ie) {\r
- }\r
- }\r
-\r
- public synchronized void notice(AltosState new_state, boolean spoken) {\r
- AltosState old_state = state;\r
- state = new_state;\r
- if (!started && state.state > AltosLib.ao_flight_pad) {\r
- started = true;\r
- start();\r
- }\r
-\r
- if (state.state < AltosLib.ao_flight_drogue)\r
- report_interval = 10000;\r
- else\r
- report_interval = 20000;\r
- if (old_state != null && old_state.state != state.state) {\r
- report_time = now();\r
- this.notify();\r
- } else if (spoken)\r
- set_report_time();\r
- }\r
-\r
- public IdleThread() {\r
- state = null;\r
- reported_landing = 0;\r
- report_interval = 10000;\r
- }\r
- }\r
-\r
-}\r
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ * Copyright © 2012 Mike Beattie <mike@ethernal.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.AltosDroid;
+
+import android.speech.tts.TextToSpeech;
+import android.speech.tts.TextToSpeech.OnInitListener;
+
+import org.altusmetrum.altoslib_2.*;
+
+public class AltosVoice {
+
+ private TextToSpeech tts = null;
+ private boolean tts_enabled = false;
+
+ private IdleThread idle_thread = null;
+
+ private AltosState old_state = null;
+
+ public AltosVoice(AltosDroid a) {
+
+ tts = new TextToSpeech(a, new OnInitListener() {
+ public void onInit(int status) {
+ if (status == TextToSpeech.SUCCESS) tts_enabled = true;
+ if (tts_enabled) {
+ idle_thread = new IdleThread();
+ }
+ }
+ });
+
+ }
+
+ public void speak(String s) {
+ if (!tts_enabled) return;
+ tts.speak(s, TextToSpeech.QUEUE_ADD, null);
+ }
+
+ public void stop() {
+ if (tts != null) tts.shutdown();
+ if (idle_thread != null) {
+ idle_thread.interrupt();
+ idle_thread = null;
+ }
+ }
+
+ public void tell(AltosState state) {
+ if (!tts_enabled) return;
+
+ boolean spoke = false;
+ if (old_state == null || old_state.state != state.state) {
+ speak(state.state_name());
+ if ((old_state == null || old_state.state <= AltosLib.ao_flight_boost) &&
+ state.state > AltosLib.ao_flight_boost) {
+ speak(String.format("max speed: %d meters per second.", (int) (state.max_speed() + 0.5)));
+ spoke = true;
+ } else if ((old_state == null || old_state.state < AltosLib.ao_flight_drogue) &&
+ state.state >= AltosLib.ao_flight_drogue) {
+ speak(String.format("max height: %d meters.", (int) (state.max_height() + 0.5)));
+ spoke = true;
+ }
+ }
+ if (old_state == null || old_state.gps_ready != state.gps_ready) {
+ if (state.gps_ready) {
+ speak("GPS ready");
+ spoke = true;
+ } else if (old_state != null) {
+ speak("GPS lost");
+ spoke = true;
+ }
+ }
+ old_state = state;
+ idle_thread.notice(state, spoke);
+ }
+
+
+ class IdleThread extends Thread {
+ boolean started;
+ private AltosState state;
+ int reported_landing;
+ int report_interval;
+ long report_time;
+
+ public synchronized void report(boolean last) {
+ if (state == null)
+ return;
+
+ /* reset the landing count once we hear about a new flight */
+ if (state.state < AltosLib.ao_flight_drogue)
+ reported_landing = 0;
+
+ /* Shut up once the rocket is on the ground */
+ if (reported_landing > 2) {
+ return;
+ }
+
+ /* If the rocket isn't on the pad, then report height */
+ if (AltosLib.ao_flight_drogue <= state.state &&
+ state.state < AltosLib.ao_flight_landed &&
+ state.range >= 0)
+ {
+ speak(String.format("Height %d, bearing %s %d, elevation %d, range %d.\n",
+ (int) (state.height() + 0.5),
+ state.from_pad.bearing_words(
+ AltosGreatCircle.BEARING_VOICE),
+ (int) (state.from_pad.bearing + 0.5),
+ (int) (state.elevation + 0.5),
+ (int) (state.range + 0.5)));
+ } else if (state.state > AltosLib.ao_flight_pad) {
+ speak(String.format("%d meters", (int) (state.height() + 0.5)));
+ } else {
+ reported_landing = 0;
+ }
+
+ /* If the rocket is coming down, check to see if it has landed;
+ * either we've got a landed report or we haven't heard from it in
+ * a long time
+ */
+ if (state.state >= AltosLib.ao_flight_drogue &&
+ (last ||
+ System.currentTimeMillis() - state.received_time >= 15000 ||
+ state.state == AltosLib.ao_flight_landed))
+ {
+ if (Math.abs(state.speed()) < 20 && state.height() < 100)
+ speak("rocket landed safely");
+ else
+ speak("rocket may have crashed");
+ if (state.from_pad != null)
+ speak(String.format("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 () {
+ try {
+ for (;;) {
+ set_report_time();
+ for (;;) {
+ synchronized (this) {
+ long sleep_time = report_time - now();
+ if (sleep_time <= 0)
+ break;
+ wait(sleep_time);
+ }
+ }
+ report(false);
+ }
+ } catch (InterruptedException ie) {
+ }
+ }
+
+ public synchronized void notice(AltosState new_state, boolean spoken) {
+ AltosState old_state = state;
+ state = new_state;
+ if (!started && state.state > AltosLib.ao_flight_pad) {
+ started = true;
+ start();
+ }
+
+ if (state.state < AltosLib.ao_flight_drogue)
+ report_interval = 10000;
+ else
+ report_interval = 20000;
+ if (old_state != null && old_state.state != state.state) {
+ report_time = now();
+ this.notify();
+ } else if (spoken)
+ set_report_time();
+ }
+
+ public IdleThread() {
+ state = null;
+ reported_landing = 0;
+ report_interval = 10000;
+ }
+ }
+
+}
-package org.altusmetrum.AltosDroid;\r
-\r
- import java.lang.reflect.Array;\r
- import java.lang.reflect.Field;\r
- import java.util.HashMap;\r
-\r
- public class Dumper {\r
- private static Dumper instance = new Dumper();\r
-\r
- protected static Dumper getInstance() {\r
- return instance;\r
- }\r
-\r
- class DumpContext {\r
- int maxDepth = 0;\r
- int maxArrayElements = 0;\r
- int callCount = 0;\r
- HashMap<String, String> ignoreList = new HashMap<String, String>();\r
- HashMap<Object, Integer> visited = new HashMap<Object, Integer>();\r
- }\r
-\r
- public static String dump(Object o) {\r
- return dump(o, 0, 0, null);\r
- }\r
-\r
- public static String dump(Object o, int maxDepth, int maxArrayElements, String[] ignoreList) {\r
- DumpContext ctx = Dumper.getInstance().new DumpContext();\r
- ctx.maxDepth = maxDepth;\r
- ctx.maxArrayElements = maxArrayElements;\r
-\r
- if (ignoreList != null) {\r
- for (int i = 0; i < Array.getLength(ignoreList); i++) {\r
- int colonIdx = ignoreList[i].indexOf(':');\r
- if (colonIdx == -1)\r
- ignoreList[i] = ignoreList[i] + ":";\r
- ctx.ignoreList.put(ignoreList[i], ignoreList[i]);\r
- }\r
- }\r
-\r
- return dump(o, ctx);\r
- }\r
-\r
- protected static String dump(Object o, DumpContext ctx) {\r
- if (o == null) {\r
- return "<null>";\r
- }\r
-\r
- ctx.callCount++;\r
- StringBuffer tabs = new StringBuffer();\r
- for (int k = 0; k < ctx.callCount; k++) {\r
- tabs.append("\t");\r
- }\r
- StringBuffer buffer = new StringBuffer();\r
- @SuppressWarnings("rawtypes")\r
- Class oClass = o.getClass();\r
-\r
- String oSimpleName = getSimpleNameWithoutArrayQualifier(oClass);\r
-\r
- if (ctx.ignoreList.get(oSimpleName + ":") != null)\r
- return "<Ignored>";\r
-\r
- if (oClass.isArray()) {\r
- buffer.append("\n");\r
- buffer.append(tabs.toString().substring(1));\r
- buffer.append("[\n");\r
- int rowCount = ctx.maxArrayElements == 0 ? Array.getLength(o) : Math.min(ctx.maxArrayElements, Array.getLength(o));\r
- for (int i = 0; i < rowCount; i++) {\r
- buffer.append(tabs.toString());\r
- try {\r
- Object value = Array.get(o, i);\r
- buffer.append(dumpValue(value, ctx));\r
- } catch (Exception e) {\r
- buffer.append(e.getMessage());\r
- }\r
- if (i < Array.getLength(o) - 1)\r
- buffer.append(",");\r
- buffer.append("\n");\r
- }\r
- if (rowCount < Array.getLength(o)) {\r
- buffer.append(tabs.toString());\r
- buffer.append(Array.getLength(o) - rowCount + " more array elements...");\r
- buffer.append("\n");\r
- }\r
- buffer.append(tabs.toString().substring(1));\r
- buffer.append("]");\r
- } else {\r
- buffer.append("\n");\r
- buffer.append(tabs.toString().substring(1));\r
- buffer.append("{\n");\r
- buffer.append(tabs.toString());\r
- buffer.append("hashCode: " + o.hashCode());\r
- buffer.append("\n");\r
- while (oClass != null && oClass != Object.class) {\r
- Field[] fields = oClass.getDeclaredFields();\r
-\r
- if (ctx.ignoreList.get(oClass.getSimpleName()) == null) {\r
- if (oClass != o.getClass()) {\r
- buffer.append(tabs.toString().substring(1));\r
- buffer.append(" Inherited from superclass " + oSimpleName + ":\n");\r
- }\r
-\r
- for (int i = 0; i < fields.length; i++) {\r
-\r
- String fSimpleName = getSimpleNameWithoutArrayQualifier(fields[i].getType());\r
- String fName = fields[i].getName();\r
-\r
- fields[i].setAccessible(true);\r
- buffer.append(tabs.toString());\r
- buffer.append(fName + "(" + fSimpleName + ")");\r
- buffer.append("=");\r
-\r
- if (ctx.ignoreList.get(":" + fName) == null &&\r
- ctx.ignoreList.get(fSimpleName + ":" + fName) == null &&\r
- ctx.ignoreList.get(fSimpleName + ":") == null) {\r
-\r
- try {\r
- Object value = fields[i].get(o);\r
- buffer.append(dumpValue(value, ctx));\r
- } catch (Exception e) {\r
- buffer.append(e.getMessage());\r
- }\r
- buffer.append("\n");\r
- } else {\r
- buffer.append("<Ignored>");\r
- buffer.append("\n");\r
- }\r
- }\r
- oClass = oClass.getSuperclass();\r
- oSimpleName = oClass.getSimpleName();\r
- } else {\r
- oClass = null;\r
- oSimpleName = "";\r
- }\r
- }\r
- buffer.append(tabs.toString().substring(1));\r
- buffer.append("}");\r
- }\r
- ctx.callCount--;\r
- return buffer.toString();\r
- }\r
-\r
- protected static String dumpValue(Object value, DumpContext ctx) {\r
- if (value == null) {\r
- return "<null>";\r
- }\r
- if (value.getClass().isPrimitive() ||\r
- value.getClass() == java.lang.Short.class ||\r
- value.getClass() == java.lang.Long.class ||\r
- value.getClass() == java.lang.String.class ||\r
- value.getClass() == java.lang.Integer.class ||\r
- value.getClass() == java.lang.Float.class ||\r
- value.getClass() == java.lang.Byte.class ||\r
- value.getClass() == java.lang.Character.class ||\r
- value.getClass() == java.lang.Double.class ||\r
- value.getClass() == java.lang.Boolean.class) {\r
-\r
- return value.toString();\r
-\r
- } else {\r
-\r
- Integer visitedIndex = ctx.visited.get(value);\r
- if (visitedIndex == null) {\r
- ctx.visited.put(value, ctx.callCount);\r
- if (ctx.maxDepth == 0 || ctx.callCount < ctx.maxDepth) {\r
- return dump(value, ctx);\r
- } else {\r
- return "<Reached max recursion depth>";\r
- }\r
- } else {\r
- return "<Previously visited - see hashCode " + value.hashCode() + ">";\r
- }\r
- }\r
- }\r
-\r
-\r
- private static String getSimpleNameWithoutArrayQualifier(@SuppressWarnings("rawtypes") Class clazz) {\r
- String simpleName = clazz.getSimpleName();\r
- int indexOfBracket = simpleName.indexOf('['); \r
- if (indexOfBracket != -1)\r
- return simpleName.substring(0, indexOfBracket);\r
- return simpleName;\r
- }\r
-}\r
+package org.altusmetrum.AltosDroid;
+
+ import java.lang.reflect.Array;
+ import java.lang.reflect.Field;
+ import java.util.HashMap;
+
+ public class Dumper {
+ private static Dumper instance = new Dumper();
+
+ protected static Dumper getInstance() {
+ return instance;
+ }
+
+ class DumpContext {
+ int maxDepth = 0;
+ int maxArrayElements = 0;
+ int callCount = 0;
+ HashMap<String, String> ignoreList = new HashMap<String, String>();
+ HashMap<Object, Integer> visited = new HashMap<Object, Integer>();
+ }
+
+ public static String dump(Object o) {
+ return dump(o, 0, 0, null);
+ }
+
+ public static String dump(Object o, int maxDepth, int maxArrayElements, String[] ignoreList) {
+ DumpContext ctx = Dumper.getInstance().new DumpContext();
+ ctx.maxDepth = maxDepth;
+ ctx.maxArrayElements = maxArrayElements;
+
+ if (ignoreList != null) {
+ for (int i = 0; i < Array.getLength(ignoreList); i++) {
+ int colonIdx = ignoreList[i].indexOf(':');
+ if (colonIdx == -1)
+ ignoreList[i] = ignoreList[i] + ":";
+ ctx.ignoreList.put(ignoreList[i], ignoreList[i]);
+ }
+ }
+
+ return dump(o, ctx);
+ }
+
+ protected static String dump(Object o, DumpContext ctx) {
+ if (o == null) {
+ return "<null>";
+ }
+
+ ctx.callCount++;
+ StringBuffer tabs = new StringBuffer();
+ for (int k = 0; k < ctx.callCount; k++) {
+ tabs.append("\t");
+ }
+ StringBuffer buffer = new StringBuffer();
+ @SuppressWarnings("rawtypes")
+ Class oClass = o.getClass();
+
+ String oSimpleName = getSimpleNameWithoutArrayQualifier(oClass);
+
+ if (ctx.ignoreList.get(oSimpleName + ":") != null)
+ return "<Ignored>";
+
+ if (oClass.isArray()) {
+ buffer.append("\n");
+ buffer.append(tabs.toString().substring(1));
+ buffer.append("[\n");
+ int rowCount = ctx.maxArrayElements == 0 ? Array.getLength(o) : Math.min(ctx.maxArrayElements, Array.getLength(o));
+ for (int i = 0; i < rowCount; i++) {
+ buffer.append(tabs.toString());
+ try {
+ Object value = Array.get(o, i);
+ buffer.append(dumpValue(value, ctx));
+ } catch (Exception e) {
+ buffer.append(e.getMessage());
+ }
+ if (i < Array.getLength(o) - 1)
+ buffer.append(",");
+ buffer.append("\n");
+ }
+ if (rowCount < Array.getLength(o)) {
+ buffer.append(tabs.toString());
+ buffer.append(Array.getLength(o) - rowCount + " more array elements...");
+ buffer.append("\n");
+ }
+ buffer.append(tabs.toString().substring(1));
+ buffer.append("]");
+ } else {
+ buffer.append("\n");
+ buffer.append(tabs.toString().substring(1));
+ buffer.append("{\n");
+ buffer.append(tabs.toString());
+ buffer.append("hashCode: " + o.hashCode());
+ buffer.append("\n");
+ while (oClass != null && oClass != Object.class) {
+ Field[] fields = oClass.getDeclaredFields();
+
+ if (ctx.ignoreList.get(oClass.getSimpleName()) == null) {
+ if (oClass != o.getClass()) {
+ buffer.append(tabs.toString().substring(1));
+ buffer.append(" Inherited from superclass " + oSimpleName + ":\n");
+ }
+
+ for (int i = 0; i < fields.length; i++) {
+
+ String fSimpleName = getSimpleNameWithoutArrayQualifier(fields[i].getType());
+ String fName = fields[i].getName();
+
+ fields[i].setAccessible(true);
+ buffer.append(tabs.toString());
+ buffer.append(fName + "(" + fSimpleName + ")");
+ buffer.append("=");
+
+ if (ctx.ignoreList.get(":" + fName) == null &&
+ ctx.ignoreList.get(fSimpleName + ":" + fName) == null &&
+ ctx.ignoreList.get(fSimpleName + ":") == null) {
+
+ try {
+ Object value = fields[i].get(o);
+ buffer.append(dumpValue(value, ctx));
+ } catch (Exception e) {
+ buffer.append(e.getMessage());
+ }
+ buffer.append("\n");
+ } else {
+ buffer.append("<Ignored>");
+ buffer.append("\n");
+ }
+ }
+ oClass = oClass.getSuperclass();
+ oSimpleName = oClass.getSimpleName();
+ } else {
+ oClass = null;
+ oSimpleName = "";
+ }
+ }
+ buffer.append(tabs.toString().substring(1));
+ buffer.append("}");
+ }
+ ctx.callCount--;
+ return buffer.toString();
+ }
+
+ protected static String dumpValue(Object value, DumpContext ctx) {
+ if (value == null) {
+ return "<null>";
+ }
+ if (value.getClass().isPrimitive() ||
+ value.getClass() == java.lang.Short.class ||
+ value.getClass() == java.lang.Long.class ||
+ value.getClass() == java.lang.String.class ||
+ value.getClass() == java.lang.Integer.class ||
+ value.getClass() == java.lang.Float.class ||
+ value.getClass() == java.lang.Byte.class ||
+ value.getClass() == java.lang.Character.class ||
+ value.getClass() == java.lang.Double.class ||
+ value.getClass() == java.lang.Boolean.class) {
+
+ return value.toString();
+
+ } else {
+
+ Integer visitedIndex = ctx.visited.get(value);
+ if (visitedIndex == null) {
+ ctx.visited.put(value, ctx.callCount);
+ if (ctx.maxDepth == 0 || ctx.callCount < ctx.maxDepth) {
+ return dump(value, ctx);
+ } else {
+ return "<Reached max recursion depth>";
+ }
+ } else {
+ return "<Previously visited - see hashCode " + value.hashCode() + ">";
+ }
+ }
+ }
+
+
+ private static String getSimpleNameWithoutArrayQualifier(@SuppressWarnings("rawtypes") Class clazz) {
+ String simpleName = clazz.getSimpleName();
+ int indexOfBracket = simpleName.indexOf('[');
+ if (indexOfBracket != -1)
+ return simpleName.substring(0, indexOfBracket);
+ return simpleName;
+ }
+}
package org.altusmetrum.AltosDroid;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
import android.app.Activity;
import android.os.Bundle;
public void update_ui(AltosState state, AltosGreatCircle from_receiver, Location receiver) {
if (state != null) {
- mHeightView.setText(AltosDroid.number("%6.0f m", state.height));
- mMaxHeightView.setText(AltosDroid.number("%6.0f m", state.max_height));
+ mHeightView.setText(AltosDroid.number("%6.0f m", state.height()));
+ mMaxHeightView.setText(AltosDroid.number("%6.0f m", state.max_height()));
mSpeedView.setText(AltosDroid.number("%6.0f m/s", state.speed()));
mMaxSpeedView.setText(AltosDroid.number("%6.0f m/s", state.max_speed()));
- mAccelView.setText(AltosDroid.number("%6.0f m/s²", state.acceleration));
- mMaxAccelView.setText(AltosDroid.number("%6.0f m/s²", state.max_acceleration));
+ mAccelView.setText(AltosDroid.number("%6.0f m/s²", state.acceleration()));
+ mMaxAccelView.setText(AltosDroid.number("%6.0f m/s²", state.max_acceleration()));
if (state.gps != null) {
mLatitudeView.setText(AltosDroid.pos(state.gps.lat, "N", "S"));
mLongitudeView.setText("");
}
- mApogeeVoltageView.setText(AltosDroid.number("%4.2f V", state.drogue_sense));
- mApogeeLights.set(state.drogue_sense > 3.2, state.drogue_sense == AltosRecord.MISSING);
+ mApogeeVoltageView.setText(AltosDroid.number("%4.2f V", state.apogee_voltage));
+ mApogeeLights.set(state.apogee_voltage > 3.2, state.apogee_voltage == AltosLib.MISSING);
- mMainVoltageView.setText(AltosDroid.number("%4.2f V", state.main_sense));
- mMainLights.set(state.main_sense > 3.2, state.main_sense == AltosRecord.MISSING);
+ mMainVoltageView.setText(AltosDroid.number("%4.2f V", state.main_voltage));
+ mMainLights.set(state.main_voltage > 3.2, state.main_voltage == AltosLib.MISSING);
}
}
}
package org.altusmetrum.AltosDroid;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
import android.app.Activity;
import android.os.Bundle;
public void update_ui(AltosState state, AltosGreatCircle from_receiver, Location receiver) {
if (state != null) {
mSpeedView.setText(AltosDroid.number("%6.0f m/s", state.speed()));
- mHeightView.setText(AltosDroid.number("%6.0f m", state.height));
+ mHeightView.setText(AltosDroid.number("%6.0f m", state.height()));
if (from_receiver != null) {
mElevationView.setText(AltosDroid.number("%3.0f°", from_receiver.elevation));
mRangeView.setText(AltosDroid.number("%6.0f m", from_receiver.range));
mLongitudeView.setText(AltosDroid.pos(state.gps.lon, "W", "E"));
}
- mApogeeVoltageView.setText(AltosDroid.number("%4.2f V", state.drogue_sense));
- mApogeeLights.set(state.drogue_sense > 3.2, state.drogue_sense == AltosRecord.MISSING);
+ mApogeeVoltageView.setText(AltosDroid.number("%4.2f V", state.apogee_voltage));
+ mApogeeLights.set(state.apogee_voltage > 3.2, state.apogee_voltage == AltosLib.MISSING);
- mMainVoltageView.setText(AltosDroid.number("%4.2f V", state.main_sense));
- mMainLights.set(state.main_sense > 3.2, state.main_sense == AltosRecord.MISSING);
+ mMainVoltageView.setText(AltosDroid.number("%4.2f V", state.main_voltage));
+ mMainLights.set(state.main_voltage > 3.2, state.main_voltage == AltosLib.MISSING);
}
}
package org.altusmetrum.AltosDroid;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
import android.app.Activity;
import android.os.Bundle;
}
if (state != null) {
- mMaxHeightView.setText(String.format("%6.0f m", state.max_height));
- mMaxAccelView.setText(String.format("%6.0f m/s²", state.max_acceleration));
+ mMaxHeightView.setText(String.format("%6.0f m", state.max_height()));
+ mMaxAccelView.setText(String.format("%6.0f m/s²", state.max_acceleration()));
mMaxSpeedView.setText(String.format("%6.0f m/s", state.max_speed()));
}
}
import java.util.Arrays;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
package org.altusmetrum.AltosDroid;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
import android.app.Activity;
import android.os.Bundle;
public void update_ui(AltosState state, AltosGreatCircle from_receiver, Location receiver) {
if (state != null) {
- mBatteryVoltageView.setText(AltosDroid.number("%4.2f V", state.battery));
- mBatteryLights.set(state.battery > 3.7, state.battery == AltosRecord.MISSING);
+ mBatteryVoltageView.setText(AltosDroid.number("%4.2f V", state.battery_voltage));
+ mBatteryLights.set(state.battery_voltage >= AltosLib.ao_battery_good, state.battery_voltage == AltosLib.MISSING);
- mApogeeVoltageView.setText(AltosDroid.number("%4.2f V", state.drogue_sense));
- mApogeeLights.set(state.drogue_sense > 3.2, state.drogue_sense == AltosRecord.MISSING);
+ mApogeeVoltageView.setText(AltosDroid.number("%4.2f V", state.apogee_voltage));
+ mApogeeLights.set(state.apogee_voltage >= AltosLib.ao_igniter_good, state.apogee_voltage == AltosLib.MISSING);
- mMainVoltageView.setText(AltosDroid.number("%4.2f V", state.main_sense));
- mMainLights.set(state.main_sense > 3.2, state.main_sense == AltosRecord.MISSING);
+ mMainVoltageView.setText(AltosDroid.number("%4.2f V", state.main_voltage));
+ mMainLights.set(state.main_voltage >= AltosLib.ao_igniter_good, state.main_voltage == AltosLib.MISSING);
- if (state.data.flight != 0) {
- if (state.data.state <= AltosLib.ao_flight_pad)
+ if (state.flight != 0) {
+ if (state.state <= AltosLib.ao_flight_pad)
mDataLoggingView.setText("Ready to record");
- else if (state.data.state < AltosLib.ao_flight_landed)
+ else if (state.state < AltosLib.ao_flight_landed)
mDataLoggingView.setText("Recording data");
else
mDataLoggingView.setText("Recorded data");
} else {
mDataLoggingView.setText("Storage full");
}
- mDataLoggingLights.set(state.data.flight != 0, state.data.flight == AltosRecord.MISSING);
+ mDataLoggingLights.set(state.flight != 0, state.flight == AltosLib.MISSING);
if (state.gps != null) {
mGPSLockedView.setText(AltosDroid.integer("%4d sats", state.gps.nsat));
package org.altusmetrum.AltosDroid;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
import android.content.BroadcastReceiver;
import android.content.Context;
-/*\r
- * Copyright © 2011 Keith Packard <keithp@keithp.com>\r
- * Copyright © 2012 Mike Beattie <mike@ethernal.org>\r
- *\r
- * This program is free software; you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation; version 2 of the License.\r
- *\r
- * This program is distributed in the hope that it will be useful, but\r
- * WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
- * General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License along\r
- * with this program; if not, write to the Free Software Foundation, Inc.,\r
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.\r
- */\r
-\r
-\r
-package org.altusmetrum.AltosDroid;\r
-\r
-import java.text.*;\r
-import java.io.*;\r
-import java.util.concurrent.*;\r
-import android.util.Log;\r
-import android.os.Handler;\r
-\r
-import org.altusmetrum.altoslib_1.*;\r
-\r
-\r
-public class TelemetryReader extends Thread {\r
-\r
- private static final String TAG = "TelemetryReader";\r
-\r
- int crc_errors;\r
-\r
- Handler handler;\r
-\r
- AltosLink link;\r
- AltosRecord previous;\r
-\r
- LinkedBlockingQueue<AltosLine> telem;\r
-\r
- public AltosRecord read() throws ParseException, AltosCRCException, InterruptedException, IOException {\r
- AltosLine l = telem.take();\r
- if (l.line == null)\r
- throw new IOException("IO error");\r
- AltosRecord next = AltosTelemetry.parse(l.line, previous);\r
- previous = next;\r
- return next;\r
- }\r
-\r
- public void close() {\r
- previous = null;\r
- link.remove_monitor(telem);\r
- link = null;\r
- telem.clear();\r
- telem = null;\r
- }\r
-\r
- public void run() {\r
- AltosState state = null;\r
-\r
- try {\r
- for (;;) {\r
- try {\r
- AltosRecord record = read();\r
- if (record == null)\r
- break;\r
- state = new AltosState(record, state);\r
- handler.obtainMessage(TelemetryService.MSG_TELEMETRY, state).sendToTarget();\r
- } catch (ParseException pp) {\r
- Log.e(TAG, String.format("Parse error: %d \"%s\"", pp.getErrorOffset(), pp.getMessage()));\r
- } catch (AltosCRCException ce) {\r
- ++crc_errors;\r
- handler.obtainMessage(TelemetryService.MSG_CRC_ERROR, new Integer(crc_errors)).sendToTarget();\r
- }\r
- }\r
- } catch (InterruptedException ee) {\r
- } catch (IOException ie) {\r
- } finally {\r
- close();\r
- }\r
- }\r
-\r
- public TelemetryReader (AltosLink in_link, Handler in_handler) {\r
- link = in_link;\r
- handler = in_handler;\r
-\r
- previous = null;\r
- telem = new LinkedBlockingQueue<AltosLine>();\r
- link.add_monitor(telem);\r
- }\r
-}\r
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ * Copyright © 2012 Mike Beattie <mike@ethernal.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+
+package org.altusmetrum.AltosDroid;
+
+import java.text.*;
+import java.io.*;
+import java.util.concurrent.*;
+import android.util.Log;
+import android.os.Handler;
+
+import org.altusmetrum.altoslib_2.*;
+
+
+public class TelemetryReader extends Thread {
+
+ private static final String TAG = "TelemetryReader";
+
+ int crc_errors;
+
+ Handler handler;
+
+ AltosLink link;
+ AltosState state = null;
+
+ LinkedBlockingQueue<AltosLine> telemQueue;
+
+ public AltosState read() throws ParseException, AltosCRCException, InterruptedException, IOException {
+ AltosLine l = telemQueue.take();
+ if (l.line == null)
+ throw new IOException("IO error");
+ AltosTelemetry telem = AltosTelemetryLegacy.parse(l.line);
+ if (state == null)
+ state = new AltosState();
+ else
+ state = state.clone();
+ telem.update_state(state);
+ return state;
+ }
+
+ public void close() {
+ state = null;
+ link.remove_monitor(telemQueue);
+ link = null;
+ telemQueue.clear();
+ telemQueue = null;
+ }
+
+ public void run() {
+ AltosState state = null;
+
+ try {
+ for (;;) {
+ try {
+ state = read();
+ handler.obtainMessage(TelemetryService.MSG_TELEMETRY, state).sendToTarget();
+ } catch (ParseException pp) {
+ Log.e(TAG, String.format("Parse error: %d \"%s\"", pp.getErrorOffset(), pp.getMessage()));
+ } catch (AltosCRCException ce) {
+ ++crc_errors;
+ handler.obtainMessage(TelemetryService.MSG_CRC_ERROR, new Integer(crc_errors)).sendToTarget();
+ }
+ }
+ } catch (InterruptedException ee) {
+ } catch (IOException ie) {
+ } finally {
+ close();
+ }
+ }
+
+ public TelemetryReader (AltosLink in_link, Handler in_handler) {
+ link = in_link;
+ handler = in_handler;
+
+ state = null;
+ telemQueue = new LinkedBlockingQueue<AltosLine>();
+ link.add_monitor(telemQueue);
+ }
+}
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
+import android.os.Looper;
import android.util.Log;
import android.widget.Toast;
import android.location.Location;
import android.location.LocationManager;
import android.location.LocationListener;
+import android.location.Criteria;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
public class TelemetryService extends Service implements LocationListener {
// Listen for GPS and Network position updates
LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
- locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
- locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this);
+ locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 1, this);
+// locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this);
}
@Override
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
public class AltosAccel extends AltosUnits {
- public double value(double v) {
- if (AltosConvert.imperial_units)
+ public double value(double v, boolean imperial_units) {
+ if (imperial_units)
return AltosConvert.meters_to_feet(v);
return v;
}
- public String show_units() {
- if (AltosConvert.imperial_units)
+ public double inverse(double v, boolean imperial_units) {
+ if (imperial_units)
+ return AltosConvert.feet_to_meters(v);
+ return v;
+ }
+
+ public String show_units(boolean imperial_units) {
+ if (imperial_units)
return "ft/s²";
return "m/s²";
}
- public String say_units() {
- if (AltosConvert.imperial_units)
+ public String say_units(boolean imperial_units) {
+ if (imperial_units)
return "feet per second squared";
return "meters per second squared";
}
- public int show_fraction(int width) {
+ public int show_fraction(int width, boolean imperial_units) {
return width / 9;
}
}
\ No newline at end of file
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
public class AltosCRCException extends Exception {
public int rssi;
--- /dev/null
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+public class AltosCompanion {
+ public final static int board_id_telescience = 0x0a;
+ public final static int MAX_CHANNELS = 12;
+
+ public int tick;
+ public int board_id;
+ public int update_period;
+ public int channels;
+ public int[] companion_data;
+
+ public AltosCompanion(int in_channels) {
+ channels = in_channels;
+ if (channels < 0)
+ channels = 0;
+ if (channels > MAX_CHANNELS)
+ channels = MAX_CHANNELS;
+ companion_data = new int[channels];
+ }
+}
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
import java.util.*;
import java.text.*;
public double frequency() {
int channel = radio_channel;
int setting = radio_setting;
+
+ if (radio_frequency < 0 && channel < 0 && setting < 0)
+ return -1;
+
if (channel < 0)
channel = 0;
if (setting < 0)
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
public interface AltosConfigValues {
/* set and get all of the dialog values */
/*
* Sensor data conversion functions
*/
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
public class AltosConvert {
/*
return ignite / 32767 * 15.0;
}
+ public static double
+ barometer_to_pressure(double count)
+ {
+ return ((count / 16.0) / 2047.0 + 0.095) / 0.009 * 1000.0;
+ }
+
+ static double
+ thermometer_to_temperature(double thermo)
+ {
+ return (thermo - 19791.268) / 32728.0 * 1.25 / 0.00247;
+ }
+
+ static double mega_adc(int raw) {
+ return raw / 4095.0;
+ }
+
+ static public double mega_battery_voltage(int v_batt) {
+ if (v_batt != AltosLib.MISSING)
+ return 3.3 * mega_adc(v_batt) * (15.0 + 27.0) / 27.0;
+ return AltosLib.MISSING;
+ }
+
+ static double mega_pyro_voltage(int raw) {
+ if (raw != AltosLib.MISSING)
+ return 3.3 * mega_adc(raw) * (100.0 + 27.0) / 27.0;
+ return AltosLib.MISSING;
+ }
+
+ static double tele_mini_voltage(int sensor) {
+ double supply = 3.3;
+
+ return sensor / 32767.0 * supply * 127/27;
+ }
+
+ static double easy_mini_voltage(int sensor) {
+ double supply = 3.0;
+
+ return sensor / 32767.0 * supply * 127/27;
+ }
+
public static double radio_to_frequency(int freq, int setting, int cal, int channel) {
double f;
return meters * (100 / (2.54 * 12));
}
+ public static double feet_to_meters(double feet) {
+ return feet * 12 * 2.54 / 100.0;
+ }
+
public static double meters_to_miles(double meters) {
return meters_to_feet(meters) / 5280;
}
+ public static double miles_to_meters(double miles) {
+ return feet_to_meters(miles * 5280);
+ }
+
public static double meters_to_mph(double mps) {
return meters_to_miles(mps) * 3600;
}
+ public static double mph_to_meters(double mps) {
+ return miles_to_meters(mps) / 3600;
+ }
+
public static double meters_to_mach(double meters) {
return meters / 343; /* something close to mach at usual rocket sites */
}
return c * 9/5 + 32;
}
+ public static double f_to_c(double c) {
+ return (c - 32) * 5/9;
+ }
+
public static boolean imperial_units = false;
public static AltosDistance distance = new AltosDistance();
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
import java.io.*;
boolean debug_mode;
- void ensure_debug_mode() {
+ void ensure_debug_mode() throws InterruptedException {
if (!debug_mode) {
link.printf("D\n");
- try {
- link.flush_input();
- } catch (InterruptedException ie) {
- }
+ link.flush_input();
debug_mode = true;
}
}
}
public void close() {
- link.close();
+ try {
+ link.close();
+ } catch (InterruptedException ie) {
+ }
}
/*
* Write target memory
*/
- public void write_memory(int address, byte[] bytes, int start, int len) {
+ public void write_memory(int address, byte[] bytes, int start, int len) throws InterruptedException {
ensure_debug_mode();
// dump_memory("write_memory", address, bytes, start, len);
link.printf("O %x %x\n", len, address);
link.printf("%02x", bytes[start + i]);
}
- public void write_memory(int address, byte[] bytes) {
+ public void write_memory(int address, byte[] bytes) throws InterruptedException {
write_memory(address, bytes, 0, bytes.length);
}
/*
* Write raw bytes to the debug link using the 'P' command
*/
- public void write_bytes(byte[] bytes) throws IOException {
+ public void write_bytes(byte[] bytes) throws IOException, InterruptedException {
int i = 0;
ensure_debug_mode();
while (i < bytes.length) {
}
}
- public void write_byte(byte b) throws IOException {
+ public void write_byte(byte b) throws IOException, InterruptedException {
byte[] bytes = { b };
write_bytes(bytes);
}
return true;
}
- public AltosRomconfig romconfig() {
+ public AltosRomconfig romconfig() throws InterruptedException {
try {
byte[] bytes = read_memory(0xa0, 10);
- return new AltosRomconfig(bytes, 0);
+ AltosHexfile hexfile = new AltosHexfile (bytes, 0xa0);
+ return new AltosRomconfig(hexfile);
} catch (IOException ie) {
- } catch (InterruptedException ie) {
}
return new AltosRomconfig();
}
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
public class AltosDistance extends AltosUnits {
- public double value(double v) {
- if (AltosConvert.imperial_units)
+ public double value(double v, boolean imperial_units) {
+ if (imperial_units)
return AltosConvert.meters_to_miles(v);
return v;
}
- public String show_units() {
- if (AltosConvert.imperial_units)
+ public double inverse(double v, boolean imperial_units) {
+ if (imperial_units)
+ return AltosConvert.miles_to_meters(v);
+ return v;
+ }
+
+ public String show_units(boolean imperial_units) {
+ if (imperial_units)
return "miles";
return "m";
}
- public String say_units() {
- if (AltosConvert.imperial_units)
+ public String say_units(boolean imperial_units) {
+ if (imperial_units)
return "miles";
return "meters";
}
- public int show_fraction(int width) {
- if (AltosConvert.imperial_units)
+ public int show_fraction(int width, boolean imperial_units) {
+ if (imperial_units)
return width / 3;
return width / 9;
}
- public int say_fraction() {
- if (AltosConvert.imperial_units)
+ public int say_fraction(boolean imperial_units) {
+ if (imperial_units)
return 1;
return 0;
}
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+import java.io.*;
+import java.util.*;
+import java.text.*;
+
+public abstract class AltosEeprom implements AltosStateUpdate {
+ public int cmd;
+ public int tick;
+ public int data8[];
+ public boolean valid;
+
+ public int data8(int i) {
+ return data8[i];
+ }
+
+ public int data16(int i) {
+ return ((data8[i] | (data8[i+1] << 8)) << 16) >> 16;
+ }
+
+ public int data24(int i) {
+ return data8[i] | (data8[i+1] << 8) | (data8[i+2] << 16);
+ }
+
+ public int data32(int i) {
+ return data8[i] | (data8[i+1] << 8) | (data8[i+2] << 16) | (data8[i+3] << 24);
+ }
+
+ public final static int header_length = 4;
+
+ public abstract int record_length();
+
+ public void update_state(AltosState state) {
+ if (cmd == AltosLib.AO_LOG_FLIGHT)
+ state.set_boost_tick(tick);
+ else
+ state.set_tick(tick);
+ }
+
+ public void write(PrintStream out) {
+ out.printf("%c %04x", cmd, tick);
+ if (data8 != null) {
+ for (int i = 0; i < data8.length; i++)
+ out.printf (" %02x", data8[i]);
+ }
+ out.printf ("\n");
+ }
+
+ public String string() {
+ String s;
+
+ s = String.format("%c %04x", cmd, tick);
+ if (data8 != null) {
+ for (int i = 0; i < data8.length; i++) {
+ String d = String.format(" %02x", data8[i]);
+ s = s.concat(d);
+ }
+ }
+ s = s.concat("\n");
+ return s;
+ }
+
+ void parse_chunk(AltosEepromChunk chunk, int start) throws ParseException {
+ cmd = chunk.data(start);
+
+ int data_length = record_length() - header_length;
+
+ valid = !chunk.erased(start, record_length());
+ if (valid) {
+ if (AltosConvert.checksum(chunk.data, start, record_length()) != 0)
+ throw new ParseException(String.format("invalid checksum at 0x%x",
+ chunk.address + start), 0);
+ } else {
+ cmd = AltosLib.AO_LOG_INVALID;
+ }
+
+ tick = chunk.data16(start+2);
+
+ data8 = new int[data_length];
+ for (int i = 0; i < data_length; i++)
+ data8[i] = chunk.data(start + header_length + i);
+ }
+
+ void parse_string(String line) {
+ valid = false;
+ tick = 0;
+ cmd = AltosLib.AO_LOG_INVALID;
+
+ int data_length = record_length() - header_length;
+
+ if (line == null)
+ return;
+ try {
+ String[] tokens = line.split("\\s+");
+
+ if (tokens[0].length() == 1) {
+ if (tokens.length == 2 + data_length) {
+ cmd = tokens[0].codePointAt(0);
+ tick = Integer.parseInt(tokens[1],16);
+ valid = true;
+ data8 = new int[data_length];
+
+ for (int i = 0; i < data_length; i++)
+ data8[i] = Integer.parseInt(tokens[2 + i],16);
+ }
+ }
+ } catch (NumberFormatException ne) {
+ }
+ }
+}
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
import java.text.*;
import java.util.concurrent.*;
return true;
}
+ public AltosEeprom eeprom(int offset, int log_format, AltosState state) throws ParseException {
+ AltosEeprom eeprom = null;
+ switch (log_format) {
+ case AltosLib.AO_LOG_FORMAT_FULL:
+ eeprom = new AltosEepromTM(this, offset);
+ break;
+ case AltosLib.AO_LOG_FORMAT_TINY:
+ eeprom = new AltosEepromTm(this, offset, state);
+ break;
+ case AltosLib.AO_LOG_FORMAT_TELEMETRY:
+ case AltosLib.AO_LOG_FORMAT_TELESCIENCE:
+ break;
+ case AltosLib.AO_LOG_FORMAT_TELEMEGA:
+ eeprom = new AltosEepromMega(this, offset);
+ break;
+ case AltosLib.AO_LOG_FORMAT_TELEMETRUM:
+ eeprom = new AltosEepromMetrum2(this, offset);
+ break;
+ case AltosLib.AO_LOG_FORMAT_TELEMINI:
+ case AltosLib.AO_LOG_FORMAT_EASYMINI:
+ eeprom = new AltosEepromMini(this, offset);
+ break;
+ default:
+ throw new ParseException("unknown eeprom format " + log_format, 0);
+ }
+ return eeprom;
+ }
+
public AltosEepromChunk(AltosLink link, int block, boolean flush)
throws TimeoutException, InterruptedException {
--- /dev/null
+/*
+ * Copyright © 2010 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+import java.io.*;
+import java.util.*;
+import java.text.*;
+import java.util.concurrent.*;
+
+public class AltosEepromDownload implements Runnable {
+
+ AltosLink link;
+ boolean remote;
+ Thread eeprom_thread;
+ AltosEepromMonitor monitor;
+
+ boolean want_file;
+ FileWriter eeprom_file;
+ LinkedList<String> eeprom_pending;
+
+ AltosEepromList flights;
+ boolean success;
+ ParseException parse_exception;
+ AltosState state;
+
+ private void FlushPending() throws IOException {
+ for (String s : flights.config_data) {
+ eeprom_file.write(s);
+ eeprom_file.write('\n');
+ }
+
+ for (String s : eeprom_pending)
+ eeprom_file.write(s);
+ }
+
+ private void CheckFile(boolean force) throws IOException {
+ if (eeprom_file != null)
+ return;
+ if (force || (state.flight != 0 && want_file)) {
+ AltosFile eeprom_name;
+ AltosGPS gps = state.gps;
+
+ if (gps != null &&
+ gps.year != AltosLib.MISSING &&
+ gps.month != AltosLib.MISSING &&
+ gps.day != AltosLib.MISSING)
+ {
+ eeprom_name = new AltosFile(gps.year, gps.month, gps.day,
+ state.serial, state.flight, "eeprom");
+ } else
+ eeprom_name = new AltosFile(state.serial, state.flight, "eeprom");
+
+ eeprom_file = new FileWriter(eeprom_name);
+ if (eeprom_file != null) {
+ monitor.set_filename(eeprom_name.getName());
+ FlushPending();
+ eeprom_pending = null;
+ }
+ }
+ }
+
+ boolean done;
+ boolean start;
+
+ void LogEeprom(AltosEeprom r) throws IOException {
+ if (r.cmd != AltosLib.AO_LOG_INVALID) {
+ String line = r.string();
+ if (eeprom_file != null)
+ eeprom_file.write(line);
+ else
+ eeprom_pending.add(line);
+ }
+ }
+
+ void CaptureEeprom(AltosEepromChunk eechunk, int log_format) throws IOException, ParseException {
+ boolean any_valid = false;
+ boolean got_flight = false;
+
+ int record_length = 8;
+
+ state.set_serial(flights.config_data.serial);
+ monitor.set_serial(flights.config_data.serial);
+
+ for (int i = 0; i < AltosEepromChunk.chunk_size && !done; i += record_length) {
+ AltosEeprom r = eechunk.eeprom(i, log_format, state);
+
+ if (r == null)
+ continue;
+
+ record_length = r.record_length();
+
+ r.update_state(state);
+
+ if (!got_flight && state.flight != AltosLib.MISSING)
+ monitor.set_flight(state.flight);
+
+ /* Monitor state transitions to update display */
+ if (state.state != AltosLib.ao_flight_invalid &&
+ state.state <= AltosLib.ao_flight_landed)
+ {
+ if (state.state > AltosLib.ao_flight_pad)
+ want_file = true;
+ if (state.state == AltosLib.ao_flight_landed)
+ done = true;
+ }
+
+ if (state.gps != null)
+ want_file = true;
+
+ if (r.valid) {
+ any_valid = true;
+ LogEeprom(r);
+ }
+ }
+ if (!any_valid)
+ done = true;
+
+ CheckFile(false);
+ }
+
+ void CaptureLog(AltosEepromLog log) throws IOException, InterruptedException, TimeoutException, ParseException {
+ int block, state_block = 0;
+ int log_format = flights.config_data.log_format;
+
+ state = new AltosState();
+
+ done = false;
+ start = true;
+
+ if (flights.config_data.serial < 0)
+ throw new IOException("no serial number found");
+
+ /* Reset per-capture variables */
+ want_file = false;
+ eeprom_file = null;
+ eeprom_pending = new LinkedList<String>();
+
+ /* Set serial number in the monitor dialog window */
+ /* Now scan the eeprom, reading blocks of data and converting to .eeprom file form */
+
+ state_block = log.start_block;
+ for (block = log.start_block; !done && block < log.end_block; block++) {
+ monitor.set_value(state.state_name(),
+ state.state,
+ block - state_block,
+ block - log.start_block);
+
+ AltosEepromChunk eechunk = new AltosEepromChunk(link, block, block == log.start_block);
+
+ /*
+ * Guess what kind of data is there if the device
+ * didn't tell us
+ */
+
+ if (log_format == AltosLib.AO_LOG_FORMAT_UNKNOWN) {
+ if (block == log.start_block) {
+ if (eechunk.data(0) == AltosLib.AO_LOG_FLIGHT)
+ log_format = AltosLib.AO_LOG_FORMAT_FULL;
+ else
+ log_format = AltosLib.AO_LOG_FORMAT_TINY;
+ }
+ }
+
+ CaptureEeprom (eechunk, log_format);
+ }
+ CheckFile(true);
+ if (eeprom_file != null) {
+ eeprom_file.flush();
+ eeprom_file.close();
+ }
+ }
+
+ public void run () {
+ try {
+ boolean failed = false;
+ if (remote)
+ link.start_remote();
+
+ for (AltosEepromLog log : flights) {
+ parse_exception = null;
+ if (log.selected) {
+ monitor.reset();
+ try {
+ CaptureLog(log);
+ } catch (ParseException e) {
+ parse_exception = e;
+ }
+ }
+ if (parse_exception != null) {
+ failed = true;
+ monitor.show_message(String.format("Flight %d download error\n%s\nValid log data saved",
+ log.flight,
+ parse_exception.getMessage()),
+ link.name,
+ AltosEepromMonitor.WARNING_MESSAGE);
+ }
+ }
+ success = !failed;
+ } catch (IOException ee) {
+ monitor.show_message(ee.getLocalizedMessage(),
+ link.name,
+ AltosEepromMonitor.ERROR_MESSAGE);
+ } catch (InterruptedException ie) {
+ monitor.show_message(String.format("Connection to \"%s\" interrupted",
+ link.name),
+ "Connection Interrupted",
+ AltosEepromMonitor.ERROR_MESSAGE);
+ } catch (TimeoutException te) {
+ monitor.show_message(String.format("Connection to \"%s\" failed",
+ link.name),
+ "Connection Failed",
+ AltosEepromMonitor.ERROR_MESSAGE);
+ } finally {
+ if (remote) {
+ try {
+ link.stop_remote();
+ } catch (InterruptedException ie) {
+ }
+ }
+ link.flush_output();
+ }
+ monitor.done(success);
+ }
+
+ public void start() {
+ eeprom_thread = new Thread(this);
+ monitor.set_thread(eeprom_thread);
+ eeprom_thread.start();
+ }
+
+ public AltosEepromDownload(AltosEepromMonitor given_monitor,
+ AltosLink given_link,
+ boolean given_remote,
+ AltosEepromList given_flights) {
+
+ monitor = given_monitor;
+ link = given_link;
+ remote = given_remote;
+ flights = given_flights;
+ success = false;
+
+ monitor.set_states(AltosLib.ao_flight_boost, AltosLib.ao_flight_landed);
+
+ monitor.start();
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+import java.io.*;
+import java.util.*;
+import java.text.*;
+
+class AltosEepromIterator implements Iterator<AltosState> {
+ AltosState state;
+ Iterator<AltosEeprom> body;
+ AltosEeprom next;
+ boolean seen;
+
+ public boolean hasNext() {
+ return !seen || body.hasNext();
+ }
+
+ public AltosState next() {
+ if (seen) {
+ AltosState n = state.clone();
+ AltosEeprom e = body.next();
+
+ e.update_state(n);
+ state = n;
+ }
+ seen = true;
+ return state;
+ }
+
+ public void remove () {
+ }
+
+ public AltosEepromIterator(AltosState start, Iterator<AltosEeprom> body) {
+ this.state = start;
+ this.body = body;
+ this.seen = false;
+ }
+}
+
+public class AltosEepromFile extends AltosStateIterable {
+
+ AltosEepromIterable headers;
+ AltosEepromIterable body;
+ AltosState start;
+
+ public void write_comments(PrintStream out) {
+ headers.write(out);
+ }
+
+ public void write(PrintStream out) {
+ headers.write(out);
+ body.write(out);
+ }
+
+ public AltosEepromFile(FileInputStream input) {
+ headers = new AltosEepromIterable(AltosEepromHeader.read(input));
+
+ start = headers.state();
+ start.set_state(AltosLib.ao_flight_pad);
+
+ switch (start.log_format) {
+ case AltosLib.AO_LOG_FORMAT_FULL:
+ body = new AltosEepromIterable(AltosEepromTM.read(input));
+ break;
+ case AltosLib.AO_LOG_FORMAT_TINY:
+ body = new AltosEepromIterable(AltosEepromTm.read(input));
+ break;
+ case AltosLib.AO_LOG_FORMAT_TELEMETRY:
+ case AltosLib.AO_LOG_FORMAT_TELESCIENCE:
+ case AltosLib.AO_LOG_FORMAT_TELEMEGA:
+ body = new AltosEepromIterable(AltosEepromMega.read(input));
+ break;
+ case AltosLib.AO_LOG_FORMAT_TELEMETRUM:
+ body = new AltosEepromIterable(AltosEepromMetrum2.read(input));
+ break;
+ case AltosLib.AO_LOG_FORMAT_TELEMINI:
+ case AltosLib.AO_LOG_FORMAT_EASYMINI:
+ body = new AltosEepromIterable(AltosEepromMini.read(input));
+ break;
+ default:
+ body = new AltosEepromIterable(new LinkedList<AltosEeprom>());
+ break;
+ }
+
+ /* Find boost tick */
+ AltosState state = start.clone();
+ for (AltosEeprom eeprom : body) {
+ eeprom.update_state(state);
+ state.finish_update();
+ if (state.state >= AltosLib.ao_flight_boost) {
+ start.set_boost_tick(state.tick);
+ break;
+ }
+ }
+ }
+
+ public Iterator<AltosState> iterator() {
+ AltosState state = start.clone();
+ Iterator<AltosEeprom> i = body.iterator();
+
+ while (i.hasNext() && !state.valid()) {
+ i.next().update_state(state);
+ state.finish_update();
+ }
+ return new AltosEepromIterator(state, i);
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+import java.io.*;
+import java.util.*;
+import java.text.*;
+
+public class AltosEepromHeader extends AltosEeprom {
+
+ public int cmd;
+ public String data;
+ public int config_a, config_b;
+ public boolean last;
+ public boolean valid;
+
+ public int record_length () { return 0; }
+
+ /* XXX pull rest of config data to state */
+ public void update_state(AltosState state) {
+ switch (cmd) {
+ case AltosLib.AO_LOG_CONFIG_VERSION:
+ break;
+ case AltosLib.AO_LOG_MAIN_DEPLOY:
+ break;
+ case AltosLib.AO_LOG_APOGEE_DELAY:
+ break;
+ case AltosLib.AO_LOG_RADIO_CHANNEL:
+ break;
+ case AltosLib.AO_LOG_CALLSIGN:
+ state.set_callsign(data);
+ break;
+ case AltosLib.AO_LOG_ACCEL_CAL:
+ state.set_accel_g(config_a, config_b);
+ break;
+ case AltosLib.AO_LOG_RADIO_CAL:
+ break;
+ case AltosLib.AO_LOG_MANUFACTURER:
+ break;
+ case AltosLib.AO_LOG_PRODUCT:
+ break;
+ case AltosLib.AO_LOG_LOG_FORMAT:
+ state.log_format = config_a;
+ break;
+ case AltosLib.AO_LOG_SERIAL_NUMBER:
+ state.set_serial(config_a);
+ break;
+ case AltosLib.AO_LOG_BARO_RESERVED:
+ state.make_baro();
+ state.baro.reserved = config_a;
+ break;
+ case AltosLib.AO_LOG_BARO_SENS:
+ state.make_baro();
+ state.baro.sens = config_a;
+ break;
+ case AltosLib.AO_LOG_BARO_OFF:
+ state.make_baro();
+ state.baro.off = config_a;
+ break;
+ case AltosLib.AO_LOG_BARO_TCS:
+ state.make_baro();
+ state.baro.tcs = config_a;
+ break;
+ case AltosLib.AO_LOG_BARO_TCO:
+ state.make_baro();
+ state.baro.tco = config_a;
+ break;
+ case AltosLib.AO_LOG_BARO_TREF:
+ state.make_baro();
+ state.baro.tref = config_a;
+ break;
+ case AltosLib.AO_LOG_BARO_TEMPSENS:
+ state.make_baro();
+ state.baro.tempsens = config_a;
+ break;
+ case AltosLib.AO_LOG_BARO_CRC:
+ state.make_baro();
+ state.baro.crc = config_a;
+ break;
+ case AltosLib.AO_LOG_SOFTWARE_VERSION:
+ state.set_firmware_version(data);
+ break;
+ }
+ }
+
+ public void write(PrintStream out) {
+ switch (cmd) {
+ case AltosLib.AO_LOG_CONFIG_VERSION:
+ out.printf("# Config version: %s\n", data);
+ break;
+ case AltosLib.AO_LOG_MAIN_DEPLOY:
+ out.printf("# Main deploy: %s\n", config_a);
+ break;
+ case AltosLib.AO_LOG_APOGEE_DELAY:
+ out.printf("# Apogee delay: %s\n", config_a);
+ break;
+ case AltosLib.AO_LOG_RADIO_CHANNEL:
+ out.printf("# Radio channel: %s\n", config_a);
+ break;
+ case AltosLib.AO_LOG_CALLSIGN:
+ out.printf("# Callsign: %s\n", data);
+ break;
+ case AltosLib.AO_LOG_ACCEL_CAL:
+ out.printf ("# Accel cal: %d %d\n", config_a, config_b);
+ break;
+ case AltosLib.AO_LOG_RADIO_CAL:
+ out.printf ("# Radio cal: %d\n", config_a);
+ break;
+ case AltosLib.AO_LOG_MAX_FLIGHT_LOG:
+ out.printf ("# Max flight log: %d\n", config_a);
+ break;
+ case AltosLib.AO_LOG_MANUFACTURER:
+ out.printf ("# Manufacturer: %s\n", data);
+ break;
+ case AltosLib.AO_LOG_PRODUCT:
+ out.printf ("# Product: %s\n", data);
+ break;
+ case AltosLib.AO_LOG_SERIAL_NUMBER:
+ out.printf ("# Serial number: %d\n", config_a);
+ break;
+ case AltosLib.AO_LOG_SOFTWARE_VERSION:
+ out.printf ("# Software version: %s\n", data);
+ break;
+ case AltosLib.AO_LOG_BARO_RESERVED:
+ out.printf ("# Baro reserved: %d\n", config_a);
+ break;
+ case AltosLib.AO_LOG_BARO_SENS:
+ out.printf ("# Baro sens: %d\n", config_a);
+ break;
+ case AltosLib.AO_LOG_BARO_OFF:
+ out.printf ("# Baro off: %d\n", config_a);
+ break;
+ case AltosLib.AO_LOG_BARO_TCS:
+ out.printf ("# Baro tcs: %d\n", config_a);
+ break;
+ case AltosLib.AO_LOG_BARO_TCO:
+ out.printf ("# Baro tco: %d\n", config_a);
+ break;
+ case AltosLib.AO_LOG_BARO_TREF:
+ out.printf ("# Baro tref: %d\n", config_a);
+ break;
+ case AltosLib.AO_LOG_BARO_TEMPSENS:
+ out.printf ("# Baro tempsens: %d\n", config_a);
+ break;
+ case AltosLib.AO_LOG_BARO_CRC:
+ out.printf ("# Baro crc: %d\n", config_a);
+ break;
+ }
+ }
+
+ public AltosEepromHeader (String[] tokens) {
+ last = false;
+ valid = true;
+ try {
+ if (tokens[0].equals("Config") && tokens[1].equals("version:")) {
+ cmd = AltosLib.AO_LOG_CONFIG_VERSION;
+ data = tokens[2];
+ } else if (tokens[0].equals("Main") && tokens[1].equals("deploy:")) {
+ cmd = AltosLib.AO_LOG_MAIN_DEPLOY;
+ config_a = Integer.parseInt(tokens[2]);
+ } else if (tokens[0].equals("Apogee") && tokens[1].equals("delay:")) {
+ cmd = AltosLib.AO_LOG_APOGEE_DELAY;
+ config_a = Integer.parseInt(tokens[2]);
+ } else if (tokens[0].equals("Radio") && tokens[1].equals("channel:")) {
+ cmd = AltosLib.AO_LOG_RADIO_CHANNEL;
+ config_a = Integer.parseInt(tokens[2]);
+ } else if (tokens[0].equals("Callsign:")) {
+ cmd = AltosLib.AO_LOG_CALLSIGN;
+ data = tokens[1].replaceAll("\"","");
+ } else if (tokens[0].equals("Accel") && tokens[1].equals("cal")) {
+ cmd = AltosLib.AO_LOG_ACCEL_CAL;
+ config_a = Integer.parseInt(tokens[3]);
+ config_b = Integer.parseInt(tokens[5]);
+ } else if (tokens[0].equals("Radio") && tokens[1].equals("cal:")) {
+ cmd = AltosLib.AO_LOG_RADIO_CAL;
+ config_a = Integer.parseInt(tokens[2]);
+ } else if (tokens[0].equals("Max") && tokens[1].equals("flight") && tokens[2].equals("log:")) {
+ cmd = AltosLib.AO_LOG_MAX_FLIGHT_LOG;
+ config_a = Integer.parseInt(tokens[3]);
+ } else if (tokens[0].equals("manufacturer")) {
+ cmd = AltosLib.AO_LOG_MANUFACTURER;
+ data = tokens[1];
+ } else if (tokens[0].equals("product")) {
+ cmd = AltosLib.AO_LOG_PRODUCT;
+ data = tokens[1];
+ } else if (tokens[0].equals("serial-number")) {
+ cmd = AltosLib.AO_LOG_SERIAL_NUMBER;
+ config_a = Integer.parseInt(tokens[1]);
+ } else if (tokens[0].equals("log-format")) {
+ cmd = AltosLib.AO_LOG_LOG_FORMAT;
+ config_a = Integer.parseInt(tokens[1]);
+ } else if (tokens[0].equals("software-version")) {
+ cmd = AltosLib.AO_LOG_SOFTWARE_VERSION;
+ data = tokens[1];
+ last = true;
+ } else if (tokens[0].equals("ms5607")) {
+ if (tokens[1].equals("reserved:")) {
+ cmd = AltosLib.AO_LOG_BARO_RESERVED;
+ config_a = Integer.parseInt(tokens[2]);
+ } else if (tokens[1].equals("sens:")) {
+ cmd = AltosLib.AO_LOG_BARO_SENS;
+ config_a = Integer.parseInt(tokens[2]);
+ } else if (tokens[1].equals("off:")) {
+ cmd = AltosLib.AO_LOG_BARO_OFF;
+ config_a = Integer.parseInt(tokens[2]);
+ } else if (tokens[1].equals("tcs:")) {
+ cmd = AltosLib.AO_LOG_BARO_TCS;
+ config_a = Integer.parseInt(tokens[2]);
+ } else if (tokens[1].equals("tco:")) {
+ cmd = AltosLib.AO_LOG_BARO_TCO;
+ config_a = Integer.parseInt(tokens[2]);
+ } else if (tokens[1].equals("tref:")) {
+ cmd = AltosLib.AO_LOG_BARO_TREF;
+ config_a = Integer.parseInt(tokens[2]);
+ } else if (tokens[1].equals("tempsens:")) {
+ cmd = AltosLib.AO_LOG_BARO_TEMPSENS;
+ config_a = Integer.parseInt(tokens[2]);
+ } else if (tokens[1].equals("crc:")) {
+ cmd = AltosLib.AO_LOG_BARO_CRC;
+ config_a = Integer.parseInt(tokens[2]);
+ } else {
+ cmd = AltosLib.AO_LOG_INVALID;
+ data = tokens[2];
+ }
+ } else
+ valid = false;
+ } catch (Exception e) {
+ valid = false;
+ }
+ }
+
+ static public LinkedList<AltosEeprom> read(FileInputStream input) {
+ LinkedList<AltosEeprom> headers = new LinkedList<AltosEeprom>();
+
+ for (;;) {
+ try {
+ String line = AltosLib.gets(input);
+ if (line == null)
+ break;
+ AltosEepromHeader header = new AltosEepromHeader(line);
+ headers.add(header);
+ if (header.last)
+ break;
+ } catch (IOException ie) {
+ break;
+ }
+ }
+
+ return headers;
+ }
+
+ static public void write (PrintStream out, LinkedList<AltosEepromHeader> headers) {
+ out.printf("# Comments\n");
+ for (AltosEepromHeader header : headers) {
+ header.write(out);
+ }
+
+ }
+
+ public AltosEepromHeader (String line) {
+ this(line.split("\\s+"));
+ }
+}
/*
- * Copyright © 2010 Keith Packard <keithp@keithp.com>
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
import java.io.*;
import java.util.*;
import java.text.*;
-public class AltosEepromIterable extends AltosRecordIterable {
+class AltosEepromOrdered implements Comparable<AltosEepromOrdered> {
+ AltosEeprom eeprom;
+ int index;
+ int tick;
- static final int seen_basic = AltosRecord.seen_flight|AltosRecord.seen_sensor;
-
- boolean has_accel;
- boolean has_gps;
- boolean has_ignite;
-
- AltosEepromRecord flight_record;
- AltosEepromRecord gps_date_record;
-
- TreeSet<AltosOrderedRecord> records;
-
- LinkedList<AltosRecord> list;
-
- class EepromState {
- int seen;
- int n_pad_samples;
- double ground_pres;
- int gps_tick;
- int boost_tick;
- int sensor_tick;
-
- EepromState() {
- seen = 0;
- n_pad_samples = 0;
- ground_pres = 0.0;
- gps_tick = 0;
- }
+ int cmdi() {
+ if (eeprom.cmd == AltosLib.AO_LOG_FLIGHT)
+ return 0;
+ return 1;
}
- void update_state(AltosRecordTM state, AltosEepromRecord record, EepromState eeprom) {
- state.tick = record.tick;
- switch (record.cmd) {
- case AltosLib.AO_LOG_FLIGHT:
- eeprom.seen |= AltosRecord.seen_flight;
- state.ground_accel = record.a;
- state.flight_accel = record.a;
- state.flight = record.b;
- eeprom.boost_tick = record.tick;
- break;
- case AltosLib.AO_LOG_SENSOR:
- state.accel = record.a;
- state.pres = record.b;
- if (state.state < AltosLib.ao_flight_boost) {
- eeprom.n_pad_samples++;
- eeprom.ground_pres += state.pres;
- state.ground_pres = (int) (eeprom.ground_pres / eeprom.n_pad_samples);
- state.flight_pres = state.ground_pres;
- } else {
- state.flight_pres = (state.flight_pres * 15 + state.pres) / 16;
- }
- state.flight_accel = (state.flight_accel * 15 + state.accel) / 16;
- if ((eeprom.seen & AltosRecord.seen_sensor) == 0)
- eeprom.sensor_tick = record.tick - 1;
- state.flight_vel += (state.accel_plus_g - state.accel) * (record.tick - eeprom.sensor_tick);
- eeprom.seen |= AltosRecord.seen_sensor;
- eeprom.sensor_tick = record.tick;
- has_accel = true;
- break;
- case AltosLib.AO_LOG_PRESSURE:
- state.pres = record.b;
- state.flight_pres = state.pres;
- if (eeprom.n_pad_samples == 0) {
- eeprom.n_pad_samples++;
- state.ground_pres = state.pres;
- }
- eeprom.seen |= AltosRecord.seen_sensor;
- break;
- case AltosLib.AO_LOG_TEMP_VOLT:
- state.temp = record.a;
- state.batt = record.b;
- eeprom.seen |= AltosRecord.seen_temp_volt;
- break;
- case AltosLib.AO_LOG_DEPLOY:
- state.drogue = record.a;
- state.main = record.b;
- eeprom.seen |= AltosRecord.seen_deploy;
- has_ignite = true;
- break;
- case AltosLib.AO_LOG_STATE:
- state.state = record.a;
- break;
- case AltosLib.AO_LOG_GPS_TIME:
- eeprom.gps_tick = state.tick;
- eeprom.seen |= AltosRecord.seen_gps_time;
- AltosGPS old = state.gps;
- state.gps = new AltosGPS();
+ public int compareTo(AltosEepromOrdered o) {
+ int cmd_diff = cmdi() - o.cmdi();
- /* 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);
+ if (cmd_diff != 0)
+ return cmd_diff;
- int flags = (record.b >> 8);
- state.gps.connected = (flags & AltosLib.AO_GPS_RUNNING) != 0;
- state.gps.locked = (flags & AltosLib.AO_GPS_VALID) != 0;
- state.gps.nsat = (flags & AltosLib.AO_GPS_NUM_SAT_MASK) >>
- AltosLib.AO_GPS_NUM_SAT_SHIFT;
- state.gps_sequence++;
- has_gps = true;
- break;
- case AltosLib.AO_LOG_GPS_LAT:
- eeprom.seen |= AltosRecord.seen_gps_lat;
- int lat32 = record.a | (record.b << 16);
- if (state.gps == null)
- state.gps = new AltosGPS();
- state.gps.lat = (double) lat32 / 1e7;
- break;
- case AltosLib.AO_LOG_GPS_LON:
- eeprom.seen |= AltosRecord.seen_gps_lon;
- int lon32 = record.a | (record.b << 16);
- if (state.gps == null)
- state.gps = new AltosGPS();
- state.gps.lon = (double) lon32 / 1e7;
- break;
- case AltosLib.AO_LOG_GPS_ALT:
- if (state.gps == null)
- state.gps = new AltosGPS();
- state.gps.alt = record.a;
- break;
- case AltosLib.AO_LOG_GPS_SAT:
- if (state.tick == eeprom.gps_tick) {
- int svid = record.a;
- int c_n0 = record.b >> 8;
- if (state.gps == null)
- state.gps = new AltosGPS();
- state.gps.add_sat(svid, c_n0);
- }
- break;
- case AltosLib.AO_LOG_GPS_DATE:
- if (state.gps == null)
- state.gps = new AltosGPS();
- state.gps.year = (record.a & 0xff) + 2000;
- state.gps.month = record.a >> 8;
- state.gps.day = record.b & 0xff;
- break;
+ int tick_diff = tick - o.tick;
- case AltosLib.AO_LOG_CONFIG_VERSION:
- break;
- case AltosLib.AO_LOG_MAIN_DEPLOY:
- break;
- case AltosLib.AO_LOG_APOGEE_DELAY:
- break;
- case AltosLib.AO_LOG_RADIO_CHANNEL:
- break;
- case AltosLib.AO_LOG_CALLSIGN:
- state.callsign = record.data;
- break;
- case AltosLib.AO_LOG_ACCEL_CAL:
- state.accel_plus_g = record.a;
- state.accel_minus_g = record.b;
- break;
- case AltosLib.AO_LOG_RADIO_CAL:
- break;
- case AltosLib.AO_LOG_MANUFACTURER:
- break;
- case AltosLib.AO_LOG_PRODUCT:
- break;
- case AltosLib.AO_LOG_SERIAL_NUMBER:
- state.serial = record.a;
- break;
- case AltosLib.AO_LOG_SOFTWARE_VERSION:
- break;
- }
- state.seen |= eeprom.seen;
+ if (tick_diff != 0)
+ return tick_diff;
+ return index - o.index;
}
- LinkedList<AltosRecord> make_list() {
- LinkedList<AltosRecord> list = new LinkedList<AltosRecord>();
- Iterator<AltosOrderedRecord> iterator = records.iterator();
- AltosOrderedRecord record = null;
- AltosRecordTM state = new AltosRecordTM();
- //boolean last_reported = false;
- EepromState eeprom = new EepromState();
-
- state.state = AltosLib.ao_flight_pad;
- state.accel_plus_g = 15758;
- state.accel_minus_g = 16294;
- state.flight_vel = 0;
-
- /* Pull in static data from the flight and gps_date records */
- if (flight_record != null)
- update_state(state, flight_record, eeprom);
- if (gps_date_record != null)
- update_state(state, gps_date_record, eeprom);
+ AltosEepromOrdered (AltosEeprom eeprom, int index, int tick) {
+ this.eeprom = eeprom;
+ this.index = index;
+ this.tick = tick;
+ }
+}
- while (iterator.hasNext()) {
- record = iterator.next();
- if ((eeprom.seen & seen_basic) == seen_basic && record.tick != state.tick) {
- AltosRecordTM r = state.clone();
- r.time = (r.tick - eeprom.boost_tick) / 100.0;
- list.add(r);
+class AltosEepromOrderedIterator implements Iterator<AltosEeprom> {
+ TreeSet<AltosEepromOrdered> olist;
+ Iterator<AltosEepromOrdered> oiterator;
+
+ public AltosEepromOrderedIterator(Iterable<AltosEeprom> eeproms) {
+ olist = new TreeSet<AltosEepromOrdered>();
+
+ int tick = 0;
+ int index = 0;
+ boolean first = true;
+
+ for (AltosEeprom e : eeproms) {
+ int t = e.tick;
+ if (first)
+ tick = t;
+ else {
+ while (t < tick - 32767)
+ t += 65536;
+ tick = t;
}
- update_state(state, record, eeprom);
+ olist.add(new AltosEepromOrdered(e, index++, tick));
+ first = false;
}
- AltosRecordTM r = state.clone();
- r.time = (r.tick - eeprom.boost_tick) / 100.0;
- list.add(r);
- return list;
- }
- public Iterator<AltosRecord> iterator() {
- if (list == null)
- list = make_list();
- return list.iterator();
+ oiterator = olist.iterator();
}
- public boolean has_gps() { return has_gps; }
- public boolean has_accel() { return has_accel; }
- public boolean has_ignite() { return has_ignite; }
-
- public void write_comments(PrintStream out) {
- Iterator<AltosOrderedRecord> iterator = records.iterator();
- out.printf("# Comments\n");
- while (iterator.hasNext()) {
- AltosOrderedRecord record = iterator.next();
- switch (record.cmd) {
- case AltosLib.AO_LOG_CONFIG_VERSION:
- out.printf("# Config version: %s\n", record.data);
- break;
- case AltosLib.AO_LOG_MAIN_DEPLOY:
- out.printf("# Main deploy: %s\n", record.a);
- break;
- case AltosLib.AO_LOG_APOGEE_DELAY:
- out.printf("# Apogee delay: %s\n", record.a);
- break;
- case AltosLib.AO_LOG_RADIO_CHANNEL:
- out.printf("# Radio channel: %s\n", record.a);
- break;
- case AltosLib.AO_LOG_CALLSIGN:
- out.printf("# Callsign: %s\n", record.data);
- break;
- case AltosLib.AO_LOG_ACCEL_CAL:
- out.printf ("# Accel cal: %d %d\n", record.a, record.b);
- break;
- case AltosLib.AO_LOG_RADIO_CAL:
- out.printf ("# Radio cal: %d\n", record.a);
- break;
- case AltosLib.AO_LOG_MAX_FLIGHT_LOG:
- out.printf ("# Max flight log: %d\n", record.a);
- break;
- case AltosLib.AO_LOG_MANUFACTURER:
- out.printf ("# Manufacturer: %s\n", record.data);
- break;
- case AltosLib.AO_LOG_PRODUCT:
- out.printf ("# Product: %s\n", record.data);
- break;
- case AltosLib.AO_LOG_SERIAL_NUMBER:
- out.printf ("# Serial number: %d\n", record.a);
- break;
- case AltosLib.AO_LOG_SOFTWARE_VERSION:
- out.printf ("# Software version: %s\n", record.data);
- break;
- case AltosLib.AO_LOG_BARO_RESERVED:
- out.printf ("# Baro reserved: %d\n", record.a);
- break;
- case AltosLib.AO_LOG_BARO_SENS:
- out.printf ("# Baro sens: %d\n", record.a);
- break;
- case AltosLib.AO_LOG_BARO_OFF:
- out.printf ("# Baro off: %d\n", record.a);
- break;
- case AltosLib.AO_LOG_BARO_TCS:
- out.printf ("# Baro tcs: %d\n", record.a);
- break;
- case AltosLib.AO_LOG_BARO_TCO:
- out.printf ("# Baro tco: %d\n", record.a);
- break;
- case AltosLib.AO_LOG_BARO_TREF:
- out.printf ("# Baro tref: %d\n", record.a);
- break;
- case AltosLib.AO_LOG_BARO_TEMPSENS:
- out.printf ("# Baro tempsens: %d\n", record.a);
- break;
- case AltosLib.AO_LOG_BARO_CRC:
- out.printf ("# Baro crc: %d\n", record.a);
- break;
- }
- }
+ public boolean hasNext() {
+ return oiterator.hasNext();
}
- /*
- * Given an AO_LOG_GPS_TIME record with correct time, and one
- * missing time, rewrite the missing time values with the good
- * ones, assuming that the difference between them is 'diff' seconds
- */
- void update_time(AltosOrderedRecord good, AltosOrderedRecord bad) {
-
- int diff = (bad.tick - good.tick + 50) / 100;
-
- int hour = (good.a & 0xff);
- int minute = (good.a >> 8);
- int second = (good.b & 0xff);
- int flags = (good.b >> 8);
- int seconds = hour * 3600 + minute * 60 + second;
-
- /* Make sure this looks like a good GPS value */
- if ((flags & AltosLib.AO_GPS_NUM_SAT_MASK) >> AltosLib.AO_GPS_NUM_SAT_SHIFT < 4)
- flags = (flags & ~AltosLib.AO_GPS_NUM_SAT_MASK) | (4 << AltosLib.AO_GPS_NUM_SAT_SHIFT);
- flags |= AltosLib.AO_GPS_RUNNING;
- flags |= AltosLib.AO_GPS_VALID;
-
- int new_seconds = seconds + diff;
- if (new_seconds < 0)
- new_seconds += 24 * 3600;
- int new_second = (new_seconds % 60);
- int new_minutes = (new_seconds / 60);
- int new_minute = (new_minutes % 60);
- int new_hours = (new_minutes / 60);
- int new_hour = (new_hours % 24);
-
- bad.a = new_hour + (new_minute << 8);
- bad.b = new_second + (flags << 8);
+ public AltosEeprom next() {
+ return oiterator.next().eeprom;
}
- /*
- * Read the whole file, dumping records into a RB tree so
- * we can enumerate them in time order -- the eeprom data
- * are sometimes out of order with GPS data getting timestamps
- * matching the first packet out of the GPS unit but not
- * written until the final GPS packet has been received.
- */
- public AltosEepromIterable (FileInputStream input) {
- records = new TreeSet<AltosOrderedRecord>();
-
- AltosOrderedRecord last_gps_time = null;
-
- int index = 0;
- int prev_tick = 0;
- boolean prev_tick_valid = false;
- boolean missing_time = false;
+ public void remove () {
+ }
+}
- try {
- for (;;) {
- String line = AltosLib.gets(input);
- if (line == null)
- break;
- AltosOrderedRecord record = new AltosOrderedRecord(line, index++, prev_tick, prev_tick_valid);
- if (record.cmd == AltosLib.AO_LOG_INVALID)
- continue;
- prev_tick = record.tick;
- if (record.cmd < AltosLib.AO_LOG_CONFIG_VERSION)
- prev_tick_valid = true;
- if (record.cmd == AltosLib.AO_LOG_FLIGHT) {
- flight_record = record;
- continue;
- }
+public class AltosEepromIterable implements Iterable<AltosEeprom> {
+ public LinkedList<AltosEeprom> eeproms;
- /* Two firmware bugs caused the loss of some GPS data.
- * The flight date would never be recorded, and often
- * the flight time would get overwritten by another
- * record. Detect the loss of the GPS date and fix up the
- * missing time records
- */
- if (record.cmd == AltosLib.AO_LOG_GPS_DATE) {
- gps_date_record = record;
- continue;
- }
+ public void write(PrintStream out) {
+ for (AltosEeprom eeprom : eeproms)
+ eeprom.write(out);
+ }
- /* go back and fix up any missing time values */
- if (record.cmd == AltosLib.AO_LOG_GPS_TIME) {
- last_gps_time = record;
- if (missing_time) {
- Iterator<AltosOrderedRecord> iterator = records.iterator();
- while (iterator.hasNext()) {
- AltosOrderedRecord old = iterator.next();
- if (old.cmd == AltosLib.AO_LOG_GPS_TIME &&
- old.a == -1 && old.b == -1)
- {
- update_time(record, old);
- }
- }
- missing_time = false;
- }
- }
+ public AltosState state() {
+ AltosState state = new AltosState();
- if (record.cmd == AltosLib.AO_LOG_GPS_LAT) {
- if (last_gps_time == null || last_gps_time.tick != record.tick) {
- AltosOrderedRecord add_gps_time = new AltosOrderedRecord(AltosLib.AO_LOG_GPS_TIME,
- record.tick,
- -1, -1, index-1);
- if (last_gps_time != null)
- update_time(last_gps_time, add_gps_time);
- else
- missing_time = true;
+ for (AltosEeprom header : eeproms)
+ header.update_state(state);
+ return state;
+ }
- records.add(add_gps_time);
- record.index = index++;
- }
- }
- records.add(record);
+ public AltosEepromIterable(LinkedList<AltosEeprom> eeproms) {
+ this.eeproms = eeproms;
+ }
- /* Bail after reading the 'landed' record; we're all done */
- if (record.cmd == AltosLib.AO_LOG_STATE &&
- record.a == AltosLib.ao_flight_landed)
- break;
- }
- } catch (IOException io) {
- } catch (ParseException pe) {
- }
- try {
- input.close();
- } catch (IOException ie) {
- }
+ public Iterator<AltosEeprom> iterator() {
+ if (eeproms == null)
+ eeproms = new LinkedList<AltosEeprom>();
+ return new AltosEepromOrderedIterator(eeproms);
}
-}
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+import java.io.*;
+import java.util.*;
+import java.text.*;
+import java.util.concurrent.*;
+
+/*
+ * Temporary structure to hold the list of stored flights;
+ * each of these will be queried in turn to generate more
+ * complete information
+ */
+
+class AltosEepromFlight {
+ int flight;
+ int start;
+ int end;
+
+ public AltosEepromFlight(int in_flight, int in_start, int in_end) {
+ flight = in_flight;
+ start = in_start;
+ end = in_end;
+ }
+}
+
+/*
+ * Construct a list of flights available in a connected device
+ */
+
+public class AltosEepromList extends ArrayList<AltosEepromLog> {
+ public AltosConfigData config_data;
+
+ public AltosEepromList (AltosLink link, boolean remote)
+ throws IOException, InterruptedException, TimeoutException
+ {
+ try {
+ if (remote)
+ link.start_remote();
+ config_data = new AltosConfigData (link);
+// if (config_data.serial == 0)
+// throw new IOException("no serial number found");
+
+ ArrayList<AltosEepromFlight> flights = new ArrayList<AltosEepromFlight>();
+
+ if (config_data.flight_log_max != 0 || config_data.log_format != 0) {
+
+ /* Devices with newer firmware will support the 'l'
+ * command which will list the region of storage
+ * occupied by each available flight
+ */
+ link.printf("l\n");
+ for (;;) {
+ String line = link.get_reply(5000);
+ if (line == null)
+ throw new TimeoutException();
+ if (line.contains("done"))
+ break;
+ if (line.contains("Syntax"))
+ continue;
+ String[] tokens = line.split("\\s+");
+ if (tokens.length < 6)
+ break;
+
+ int flight = -1, start = -1, end = -1;
+ try {
+ if (tokens[0].equals("flight"))
+ flight = AltosParse.parse_int(tokens[1]);
+ if (tokens[2].equals("start"))
+ start = AltosParse.parse_hex(tokens[3]);
+ if (tokens[4].equals("end"))
+ end = AltosParse.parse_hex(tokens[5]);
+ if (flight > 0 && start >= 0 && end > 0)
+ flights.add(new AltosEepromFlight(flight, start, end));
+ } catch (ParseException pe) { System.out.printf("Parse error %s\n", pe.toString()); }
+ }
+ } else {
+
+ /* Older devices will hold only a single
+ * flight. This also assumes that any older
+ * device will have a 1MB flash device
+ */
+ flights.add(new AltosEepromFlight(0, 0, 0xfff));
+ }
+
+ /* With the list of flights collected, collect more complete
+ * information on them by reading the first block or two of
+ * data. This will add GPS coordinates and a date. For older
+ * firmware, this will also extract the flight number.
+ */
+ for (AltosEepromFlight flight : flights) {
+ add(new AltosEepromLog(config_data, link,
+ flight.flight, flight.start, flight.end));
+ }
+ } finally {
+ if (remote)
+ link.stop_remote();
+ link.flush_output();
+ }
+ }
+}
\ No newline at end of file
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
import java.text.*;
import java.util.concurrent.*;
for (block = in_start_block; block < in_end_block; block++) {
AltosEepromChunk eechunk = new AltosEepromChunk(link, block, block == in_start_block);
- for (int i = 0; i < AltosEepromChunk.chunk_size; i += AltosEepromRecord.record_length) {
+ for (int i = 0; i < AltosEepromChunk.chunk_size; i += AltosEepromTM.record_length) {
try {
- AltosEepromRecord r = new AltosEepromRecord(eechunk, i);
+ AltosEepromTM r = new AltosEepromTM(eechunk, i);
if (r.cmd == AltosLib.AO_LOG_FLIGHT) {
flight = r.b;
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
+import java.io.*;
+import java.util.*;
import java.text.*;
-public class AltosEepromMega {
- public int cmd;
- public int tick;
- public boolean valid;
- public String data;
- public int config_a, config_b;
-
- public int data8[];
-
+public class AltosEepromMega extends AltosEeprom {
public static final int record_length = 32;
- static final int header_length = 4;
- static final int data_length = record_length - header_length;
-
- public int data8(int i) {
- return data8[i];
- }
- public int data16(int i) {
- return ((data8[i] | (data8[i+1] << 8)) << 16) >> 16;
- }
-
- public int data32(int i) {
- return data8[i] | (data8[i+1] << 8) | (data8[i+2] << 16) | (data8[i+3] << 24);
- }
+ public int record_length() { return record_length; }
/* AO_LOG_FLIGHT elements */
public int flight() { return data16(0); }
public int mag_z() { return data16(24); }
public int accel() { return data16(26); }
- /* AO_LOG_VOLT elements */
+ /* AO_LOG_TEMP_VOLT elements */
public int v_batt() { return data16(0); }
public int v_pbatt() { return data16(2); }
public int nsense() { return data16(4); }
public int sense(int i) { return data16(6 + i * 2); }
+ public int pyro() { return data16(26); }
/* AO_LOG_GPS_TIME elements */
public int latitude() { return data32(0); }
public int nsat() { return data16(0); }
public int svid(int n) { return data8(2 + n * 2); }
public int c_n(int n) { return data8(2 + n * 2 + 1); }
+
public AltosEepromMega (AltosEepromChunk chunk, int start) throws ParseException {
- cmd = chunk.data(start);
-
- valid = !chunk.erased(start, record_length);
- if (valid) {
- if (AltosConvert.checksum(chunk.data, start, record_length) != 0)
- throw new ParseException(String.format("invalid checksum at 0x%x",
- chunk.address + start), 0);
- } else {
- cmd = AltosLib.AO_LOG_INVALID;
- }
+ parse_chunk(chunk, start);
+ }
- tick = chunk.data16(start+2);
+ public void update_state(AltosState state) {
+ super.update_state(state);
+
+ AltosGPS gps;
+
+ /* Flush any pending GPS changes */
+ if (state.gps_pending) {
+ switch (cmd) {
+ case AltosLib.AO_LOG_GPS_LAT:
+ case AltosLib.AO_LOG_GPS_LON:
+ case AltosLib.AO_LOG_GPS_ALT:
+ case AltosLib.AO_LOG_GPS_SAT:
+ case AltosLib.AO_LOG_GPS_DATE:
+ break;
+ default:
+ state.set_temp_gps();
+ break;
+ }
+ }
- data8 = new int[data_length];
- for (int i = 0; i < data_length; i++)
- data8[i] = chunk.data(start + header_length + i);
+ switch (cmd) {
+ case AltosLib.AO_LOG_FLIGHT:
+ state.set_boost_tick(tick);
+ state.set_flight(flight());
+ state.set_ground_accel(ground_accel());
+ state.set_ground_pressure(ground_pres());
+ state.set_temperature(ground_temp() / 100.0);
+ break;
+ case AltosLib.AO_LOG_STATE:
+ state.set_tick(tick);
+ state.set_state(state());
+ break;
+ case AltosLib.AO_LOG_SENSOR:
+ state.set_tick(tick);
+ state.set_ms5607(pres(), temp());
+
+ AltosIMU imu = new AltosIMU();
+ imu.accel_x = accel_x();
+ imu.accel_y = accel_y();
+ imu.accel_z = accel_z();
+
+ imu.gyro_x = gyro_x();
+ imu.gyro_y = gyro_y();
+ imu.gyro_z = gyro_z();
+ state.imu = imu;
+
+ AltosMag mag = new AltosMag();
+ mag.x = mag_x();
+ mag.y = mag_y();
+ mag.z = mag_z();
+
+ state.mag = mag;
+
+ state.set_accel(accel());
+
+ break;
+ case AltosLib.AO_LOG_TEMP_VOLT:
+ state.set_battery_voltage(AltosConvert.mega_battery_voltage(v_batt()));
+ state.set_pyro_voltage(AltosConvert.mega_pyro_voltage(v_pbatt()));
+
+ int nsense = nsense();
+
+ state.set_apogee_voltage(AltosConvert.mega_pyro_voltage(sense(nsense-2)));
+ state.set_main_voltage(AltosConvert.mega_pyro_voltage(sense(nsense-1)));
+
+ double voltages[] = new double[nsense-2];
+ for (int i = 0; i < nsense-2; i++)
+ voltages[i] = AltosConvert.mega_pyro_voltage(sense(i));
+
+ state.set_ignitor_voltage(voltages);
+ break;
+ case AltosLib.AO_LOG_GPS_TIME:
+ state.set_tick(tick);
+ gps = state.make_temp_gps(false);
+ gps.lat = latitude() / 1e7;
+ gps.lon = longitude() / 1e7;
+ gps.alt = altitude();
+
+ gps.hour = hour();
+ gps.minute = minute();
+ gps.second = second();
+
+ int flags = flags();
+
+ gps.connected = (flags & AltosLib.AO_GPS_RUNNING) != 0;
+ gps.locked = (flags & AltosLib.AO_GPS_VALID) != 0;
+ gps.nsat = (flags & AltosLib.AO_GPS_NUM_SAT_MASK) >>
+ AltosLib.AO_GPS_NUM_SAT_SHIFT;
+
+ gps.year = 2000 + year();
+ gps.month = month();
+ gps.day = day();
+ break;
+ case AltosLib.AO_LOG_GPS_SAT:
+ state.set_tick(tick);
+ gps = state.make_temp_gps(true);
+
+ int n = nsat();
+ for (int i = 0; i < n; i++)
+ gps.add_sat(svid(i), c_n(i));
+ break;
+ }
}
public AltosEepromMega (String line) {
- valid = false;
- tick = 0;
+ parse_string(line);
+ }
- if (line == null) {
- cmd = AltosLib.AO_LOG_INVALID;
- line = "";
- } else {
+ static public LinkedList<AltosEeprom> read(FileInputStream input) {
+ LinkedList<AltosEeprom> megas = new LinkedList<AltosEeprom>();
+
+ for (;;) {
try {
- String[] tokens = line.split("\\s+");
-
- if (tokens[0].length() == 1) {
- if (tokens.length != 2 + data_length) {
- cmd = AltosLib.AO_LOG_INVALID;
- data = line;
- } else {
- cmd = tokens[0].codePointAt(0);
- tick = Integer.parseInt(tokens[1],16);
- valid = true;
- data8 = new int[data_length];
- for (int i = 0; i < data_length; i++)
- data8[i] = Integer.parseInt(tokens[2 + i],16);
- }
- } else if (tokens[0].equals("Config") && tokens[1].equals("version:")) {
- cmd = AltosLib.AO_LOG_CONFIG_VERSION;
- data = tokens[2];
- } else if (tokens[0].equals("Main") && tokens[1].equals("deploy:")) {
- cmd = AltosLib.AO_LOG_MAIN_DEPLOY;
- config_a = Integer.parseInt(tokens[2]);
- } else if (tokens[0].equals("Apogee") && tokens[1].equals("delay:")) {
- cmd = AltosLib.AO_LOG_APOGEE_DELAY;
- config_a = Integer.parseInt(tokens[2]);
- } else if (tokens[0].equals("Radio") && tokens[1].equals("channel:")) {
- cmd = AltosLib.AO_LOG_RADIO_CHANNEL;
- config_a = Integer.parseInt(tokens[2]);
- } else if (tokens[0].equals("Callsign:")) {
- cmd = AltosLib.AO_LOG_CALLSIGN;
- data = tokens[1].replaceAll("\"","");
- } else if (tokens[0].equals("Accel") && tokens[1].equals("cal")) {
- cmd = AltosLib.AO_LOG_ACCEL_CAL;
- config_a = Integer.parseInt(tokens[3]);
- config_b = Integer.parseInt(tokens[5]);
- } else if (tokens[0].equals("Radio") && tokens[1].equals("cal:")) {
- cmd = AltosLib.AO_LOG_RADIO_CAL;
- config_a = Integer.parseInt(tokens[2]);
- } else if (tokens[0].equals("Max") && tokens[1].equals("flight") && tokens[2].equals("log:")) {
- cmd = AltosLib.AO_LOG_MAX_FLIGHT_LOG;
- config_a = Integer.parseInt(tokens[3]);
- } else if (tokens[0].equals("manufacturer")) {
- cmd = AltosLib.AO_LOG_MANUFACTURER;
- data = tokens[1];
- } else if (tokens[0].equals("product")) {
- cmd = AltosLib.AO_LOG_PRODUCT;
- data = tokens[1];
- } else if (tokens[0].equals("serial-number")) {
- cmd = AltosLib.AO_LOG_SERIAL_NUMBER;
- config_a = Integer.parseInt(tokens[1]);
- } else if (tokens[0].equals("log-format")) {
- cmd = AltosLib.AO_LOG_LOG_FORMAT;
- config_a = Integer.parseInt(tokens[1]);
- } else if (tokens[0].equals("software-version")) {
- cmd = AltosLib.AO_LOG_SOFTWARE_VERSION;
- data = tokens[1];
- } else if (tokens[0].equals("ms5607")) {
- if (tokens[1].equals("reserved:")) {
- cmd = AltosLib.AO_LOG_BARO_RESERVED;
- config_a = Integer.parseInt(tokens[2]);
- } else if (tokens[1].equals("sens:")) {
- cmd = AltosLib.AO_LOG_BARO_SENS;
- config_a = Integer.parseInt(tokens[2]);
- } else if (tokens[1].equals("off:")) {
- cmd = AltosLib.AO_LOG_BARO_OFF;
- config_a = Integer.parseInt(tokens[2]);
- } else if (tokens[1].equals("tcs:")) {
- cmd = AltosLib.AO_LOG_BARO_TCS;
- config_a = Integer.parseInt(tokens[2]);
- } else if (tokens[1].equals("tco:")) {
- cmd = AltosLib.AO_LOG_BARO_TCO;
- config_a = Integer.parseInt(tokens[2]);
- } else if (tokens[1].equals("tref:")) {
- cmd = AltosLib.AO_LOG_BARO_TREF;
- config_a = Integer.parseInt(tokens[2]);
- } else if (tokens[1].equals("tempsens:")) {
- cmd = AltosLib.AO_LOG_BARO_TEMPSENS;
- config_a = Integer.parseInt(tokens[2]);
- } else if (tokens[1].equals("crc:")) {
- cmd = AltosLib.AO_LOG_BARO_CRC;
- config_a = Integer.parseInt(tokens[2]);
- } else {
- cmd = AltosLib.AO_LOG_INVALID;
- data = line;
- }
- } else {
- cmd = AltosLib.AO_LOG_INVALID;
- data = line;
+ String line = AltosLib.gets(input);
+ if (line == null)
+ break;
+ try {
+ AltosEepromMega mega = new AltosEepromMega(line);
+ if (mega.cmd != AltosLib.AO_LOG_INVALID)
+ megas.add(mega);
+ } catch (Exception e) {
+ System.out.printf ("exception\n");
}
- } catch (NumberFormatException ne) {
- cmd = AltosLib.AO_LOG_INVALID;
- data = line;
+ } catch (IOException ie) {
+ break;
}
}
- }
- public AltosEepromMega(int in_cmd, int in_tick) {
- cmd = in_cmd;
- tick = in_tick;
- valid = true;
+ return megas;
}
}
+++ /dev/null
-/*
- * Copyright © 2010 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-package org.altusmetrum.altoslib_1;
-
-import java.io.*;
-import java.util.*;
-import java.text.*;
-
-public class AltosEepromMegaIterable extends AltosRecordIterable {
-
- static final int seen_flight = 1;
- static final int seen_sensor = 2;
- static final int seen_temp_volt = 4;
- static final int seen_deploy = 8;
- static final int seen_gps_time = 16;
- static final int seen_gps_lat = 32;
- static final int seen_gps_lon = 64;
-
- static final int seen_basic = seen_flight|seen_sensor;
-
- boolean has_accel;
- boolean has_gps;
- boolean has_ignite;
-
- AltosEepromMega flight_record;
- AltosEepromMega gps_date_record;
-
- TreeSet<AltosOrderedMegaRecord> records;
-
- AltosMs5607 baro;
-
- LinkedList<AltosRecord> list;
-
- class EepromState {
- int seen;
- int n_pad_samples;
- double ground_pres;
- int gps_tick;
- int boost_tick;
- int sensor_tick;
-
- EepromState() {
- seen = 0;
- n_pad_samples = 0;
- ground_pres = 0.0;
- gps_tick = 0;
- }
- }
-
- void update_state(AltosRecordMM state, AltosEepromMega record, EepromState eeprom) {
- state.tick = record.tick;
- switch (record.cmd) {
- case AltosLib.AO_LOG_FLIGHT:
- eeprom.seen |= seen_flight;
- state.ground_accel = record.ground_accel();
- state.flight_accel = record.ground_accel();
- state.ground_pres = baro.set(record.ground_pres(), record.ground_temp());
- state.flight_pres = state.ground_pres;
- state.flight = record.data16(0);
- eeprom.boost_tick = record.tick;
- break;
- case AltosLib.AO_LOG_SENSOR:
- state.accel = record.accel();
- baro.set(record.pres(), record.temp());
- state.pres = baro.pa;
- state.temp = baro.cc;
- state.imu = new AltosIMU();
- state.imu.accel_x = record.accel_x();
- state.imu.accel_y = record.accel_y();
- state.imu.accel_z = record.accel_z();
- state.imu.gyro_x = record.gyro_x();
- state.imu.gyro_y = record.gyro_y();
- state.imu.gyro_z = record.gyro_z();
- state.mag = new AltosMag();
- state.mag.x = record.mag_x();
- state.mag.y = record.mag_y();
- state.mag.z = record.mag_z();
- if (state.state < AltosLib.ao_flight_boost) {
- eeprom.n_pad_samples++;
- eeprom.ground_pres += state.pres;
- state.ground_pres = (int) (eeprom.ground_pres / eeprom.n_pad_samples);
- state.flight_pres = state.ground_pres;
- } else {
- state.flight_pres = (state.flight_pres * 15 + state.pres) / 16;
- }
- state.flight_accel = (state.flight_accel * 15 + state.accel) / 16;
- if ((eeprom.seen & seen_sensor) == 0)
- eeprom.sensor_tick = record.tick - 1;
- state.flight_vel += (state.accel_plus_g - state.accel) * (record.tick - eeprom.sensor_tick);
- eeprom.seen |= seen_sensor;
- eeprom.sensor_tick = record.tick;
- has_accel = true;
- break;
- case AltosLib.AO_LOG_TEMP_VOLT:
- state.v_batt = record.v_batt();
- state.v_pyro = record.v_pbatt();
- for (int i = 0; i < record.nsense(); i++)
- state.sense[i] = record.sense(i);
- eeprom.seen |= seen_temp_volt;
- break;
- case AltosLib.AO_LOG_STATE:
- state.state = record.state();
- break;
- case AltosLib.AO_LOG_GPS_TIME:
- eeprom.gps_tick = state.tick;
- state.gps = new AltosGPS();
-
- state.gps.lat = record.latitude() / 1e7;
- state.gps.lon = record.longitude() / 1e7;
- state.gps.alt = record.altitude();
- state.gps.year = record.year() + 2000;
- state.gps.month = record.month();
- state.gps.day = record.day();
-
- state.gps.hour = record.hour();
- state.gps.minute = record.minute();
- state.gps.second = record.second();
-
- int flags = record.flags();
- state.gps.connected = (flags & AltosLib.AO_GPS_RUNNING) != 0;
- state.gps.locked = (flags & AltosLib.AO_GPS_VALID) != 0;
- state.gps.nsat = (flags & AltosLib.AO_GPS_NUM_SAT_MASK) >>
- AltosLib.AO_GPS_NUM_SAT_SHIFT;
- state.gps_sequence++;
- has_gps = true;
- eeprom.seen |= seen_gps_time | seen_gps_lat | seen_gps_lon;
- break;
- case AltosLib.AO_LOG_GPS_SAT:
- if (state.tick == eeprom.gps_tick) {
- int nsat = record.nsat();
- for (int i = 0; i < nsat; i++)
- state.gps.add_sat(record.svid(i), record.c_n(i));
- }
- break;
- case AltosLib.AO_LOG_CONFIG_VERSION:
- break;
- case AltosLib.AO_LOG_MAIN_DEPLOY:
- break;
- case AltosLib.AO_LOG_APOGEE_DELAY:
- break;
- case AltosLib.AO_LOG_RADIO_CHANNEL:
- break;
- case AltosLib.AO_LOG_CALLSIGN:
- state.callsign = record.data;
- break;
- case AltosLib.AO_LOG_ACCEL_CAL:
- state.accel_plus_g = record.config_a;
- state.accel_minus_g = record.config_b;
- break;
- case AltosLib.AO_LOG_RADIO_CAL:
- break;
- case AltosLib.AO_LOG_MANUFACTURER:
- break;
- case AltosLib.AO_LOG_PRODUCT:
- break;
- case AltosLib.AO_LOG_SERIAL_NUMBER:
- state.serial = record.config_a;
- break;
- case AltosLib.AO_LOG_SOFTWARE_VERSION:
- break;
- case AltosLib.AO_LOG_BARO_RESERVED:
- baro.reserved = record.config_a;
- break;
- case AltosLib.AO_LOG_BARO_SENS:
- baro.sens =record.config_a;
- break;
- case AltosLib.AO_LOG_BARO_OFF:
- baro.off =record.config_a;
- break;
- case AltosLib.AO_LOG_BARO_TCS:
- baro.tcs =record.config_a;
- break;
- case AltosLib.AO_LOG_BARO_TCO:
- baro.tco =record.config_a;
- break;
- case AltosLib.AO_LOG_BARO_TREF:
- baro.tref =record.config_a;
- break;
- case AltosLib.AO_LOG_BARO_TEMPSENS:
- baro.tempsens =record.config_a;
- break;
- case AltosLib.AO_LOG_BARO_CRC:
- baro.crc =record.config_a;
- break;
- }
- state.seen |= eeprom.seen;
- }
-
- LinkedList<AltosRecord> make_list() {
- LinkedList<AltosRecord> list = new LinkedList<AltosRecord>();
- Iterator<AltosOrderedMegaRecord> iterator = records.iterator();
- AltosOrderedMegaRecord record = null;
- AltosRecordMM state = new AltosRecordMM();
- //boolean last_reported = false;
- EepromState eeprom = new EepromState();
-
- state.state = AltosLib.ao_flight_pad;
- state.accel_plus_g = 15758;
- state.accel_minus_g = 16294;
-
- /* Pull in static data from the flight and gps_date records */
- if (flight_record != null)
- update_state(state, flight_record, eeprom);
- if (gps_date_record != null)
- update_state(state, gps_date_record, eeprom);
-
- while (iterator.hasNext()) {
- record = iterator.next();
- if ((eeprom.seen & seen_basic) == seen_basic && record.tick != state.tick) {
- AltosRecordMM r = state.clone();
- r.time = (r.tick - eeprom.boost_tick) / 100.0;
- list.add(r);
- }
- update_state(state, record, eeprom);
- }
- AltosRecordMM r = state.clone();
- r.time = (r.tick - eeprom.boost_tick) / 100.0;
- list.add(r);
- return list;
- }
-
- public Iterator<AltosRecord> iterator() {
- if (list == null)
- list = make_list();
- return list.iterator();
- }
-
- public boolean has_gps() { return has_gps; }
- public boolean has_accel() { return has_accel; }
- public boolean has_ignite() { return has_ignite; }
-
- public void write_comments(PrintStream out) {
- Iterator<AltosOrderedMegaRecord> iterator = records.iterator();
- out.printf("# Comments\n");
- while (iterator.hasNext()) {
- AltosOrderedMegaRecord record = iterator.next();
- switch (record.cmd) {
- case AltosLib.AO_LOG_CONFIG_VERSION:
- out.printf("# Config version: %s\n", record.data);
- break;
- case AltosLib.AO_LOG_MAIN_DEPLOY:
- out.printf("# Main deploy: %s\n", record.config_a);
- break;
- case AltosLib.AO_LOG_APOGEE_DELAY:
- out.printf("# Apogee delay: %s\n", record.config_a);
- break;
- case AltosLib.AO_LOG_RADIO_CHANNEL:
- out.printf("# Radio channel: %s\n", record.config_a);
- break;
- case AltosLib.AO_LOG_CALLSIGN:
- out.printf("# Callsign: %s\n", record.data);
- break;
- case AltosLib.AO_LOG_ACCEL_CAL:
- out.printf ("# Accel cal: %d %d\n", record.config_a, record.config_b);
- break;
- case AltosLib.AO_LOG_RADIO_CAL:
- out.printf ("# Radio cal: %d\n", record.config_a);
- break;
- case AltosLib.AO_LOG_MAX_FLIGHT_LOG:
- out.printf ("# Max flight log: %d\n", record.config_a);
- break;
- case AltosLib.AO_LOG_MANUFACTURER:
- out.printf ("# Manufacturer: %s\n", record.data);
- break;
- case AltosLib.AO_LOG_PRODUCT:
- out.printf ("# Product: %s\n", record.data);
- break;
- case AltosLib.AO_LOG_SERIAL_NUMBER:
- out.printf ("# Serial number: %d\n", record.config_a);
- break;
- case AltosLib.AO_LOG_SOFTWARE_VERSION:
- out.printf ("# Software version: %s\n", record.data);
- break;
- case AltosLib.AO_LOG_BARO_RESERVED:
- out.printf ("# Baro reserved: %d\n", record.config_a);
- break;
- case AltosLib.AO_LOG_BARO_SENS:
- out.printf ("# Baro sens: %d\n", record.config_a);
- break;
- case AltosLib.AO_LOG_BARO_OFF:
- out.printf ("# Baro off: %d\n", record.config_a);
- break;
- case AltosLib.AO_LOG_BARO_TCS:
- out.printf ("# Baro tcs: %d\n", record.config_a);
- break;
- case AltosLib.AO_LOG_BARO_TCO:
- out.printf ("# Baro tco: %d\n", record.config_a);
- break;
- case AltosLib.AO_LOG_BARO_TREF:
- out.printf ("# Baro tref: %d\n", record.config_a);
- break;
- case AltosLib.AO_LOG_BARO_TEMPSENS:
- out.printf ("# Baro tempsens: %d\n", record.config_a);
- break;
- case AltosLib.AO_LOG_BARO_CRC:
- out.printf ("# Baro crc: %d\n", record.config_a);
- break;
- }
- }
- }
-
- /*
- * Read the whole file, dumping records into a RB tree so
- * we can enumerate them in time order -- the eeprom data
- * are sometimes out of order with GPS data getting timestamps
- * matching the first packet out of the GPS unit but not
- * written until the final GPS packet has been received.
- */
- public AltosEepromMegaIterable (FileInputStream input) {
- records = new TreeSet<AltosOrderedMegaRecord>();
-
- AltosOrderedMegaRecord last_gps_time = null;
-
- baro = new AltosMs5607();
-
- int index = 0;
- int prev_tick = 0;
- boolean prev_tick_valid = false;
- boolean missing_time = false;
-
- try {
- for (;;) {
- String line = AltosLib.gets(input);
- if (line == null)
- break;
- AltosOrderedMegaRecord record = new AltosOrderedMegaRecord(line, index++, prev_tick, prev_tick_valid);
- if (record.cmd == AltosLib.AO_LOG_INVALID)
- continue;
- prev_tick = record.tick;
- if (record.cmd < AltosLib.AO_LOG_CONFIG_VERSION)
- prev_tick_valid = true;
- if (record.cmd == AltosLib.AO_LOG_FLIGHT) {
- flight_record = record;
- continue;
- }
-
- records.add(record);
-
- /* Bail after reading the 'landed' record; we're all done */
- if (record.cmd == AltosLib.AO_LOG_STATE &&
- record.state() == AltosLib.ao_flight_landed)
- break;
- }
- } catch (IOException io) {
- } catch (ParseException pe) {
- }
- try {
- input.close();
- } catch (IOException ie) {
- }
- }
-}
--- /dev/null
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+import java.io.*;
+import java.util.*;
+import java.text.*;
+
+public class AltosEepromMetrum2 extends AltosEeprom {
+ public static final int record_length = 16;
+
+ public int record_length() { return record_length; }
+
+ /* AO_LOG_FLIGHT elements */
+ public int flight() { return data16(0); }
+ public int ground_accel() { return data16(2); }
+ public int ground_pres() { return data32(4); }
+ public int ground_temp() { return data32(8); }
+
+ /* AO_LOG_STATE elements */
+ public int state() { return data16(0); }
+ public int reason() { return data16(2); }
+
+ /* AO_LOG_SENSOR elements */
+ public int pres() { return data32(0); }
+ public int temp() { return data32(4); }
+ public int accel() { return data16(8); }
+
+ /* AO_LOG_TEMP_VOLT elements */
+ public int v_batt() { return data16(0); }
+ public int sense_a() { return data16(2); }
+ public int sense_m() { return data16(4); }
+
+ /* AO_LOG_GPS_POS elements */
+ public int latitude() { return data32(0); }
+ public int longitude() { return data32(4); }
+ public int altitude() { return data16(8); }
+
+ /* AO_LOG_GPS_TIME elements */
+ public int hour() { return data8(0); }
+ public int minute() { return data8(1); }
+ public int second() { return data8(2); }
+ public int flags() { return data8(3); }
+ public int year() { return data8(4); }
+ public int month() { return data8(5); }
+ public int day() { return data8(6); }
+
+ /* AO_LOG_GPS_SAT elements */
+ public int nsat() { return data8(0); }
+ public int more() { return data8(1); }
+ public int svid(int n) { return data8(2 + n * 2); }
+ public int c_n(int n) { return data8(2 + n * 2 + 1); }
+
+ public AltosEepromMetrum2 (AltosEepromChunk chunk, int start) throws ParseException {
+ parse_chunk(chunk, start);
+ }
+
+ public void update_state(AltosState state) {
+ super.update_state(state);
+
+ AltosGPS gps;
+
+ /* Flush any pending GPS changes */
+ if (state.gps_pending) {
+ switch (cmd) {
+ case AltosLib.AO_LOG_GPS_POS:
+ case AltosLib.AO_LOG_GPS_LAT:
+ case AltosLib.AO_LOG_GPS_LON:
+ case AltosLib.AO_LOG_GPS_ALT:
+ case AltosLib.AO_LOG_GPS_SAT:
+ case AltosLib.AO_LOG_GPS_DATE:
+ break;
+ default:
+ state.set_temp_gps();
+ break;
+ }
+ }
+
+ switch (cmd) {
+ case AltosLib.AO_LOG_FLIGHT:
+ state.set_flight(flight());
+ state.set_ground_accel(ground_accel());
+ state.set_ground_pressure(ground_pres());
+// state.set_temperature(ground_temp() / 100.0);
+ break;
+ case AltosLib.AO_LOG_STATE:
+ state.set_state(state());
+ break;
+ case AltosLib.AO_LOG_SENSOR:
+ state.set_ms5607(pres(), temp());
+ state.set_accel(accel());
+
+ break;
+ case AltosLib.AO_LOG_TEMP_VOLT:
+ state.set_battery_voltage(AltosConvert.mega_battery_voltage(v_batt()));
+
+ state.set_apogee_voltage(AltosConvert.mega_pyro_voltage(sense_a()));
+ state.set_main_voltage(AltosConvert.mega_pyro_voltage(sense_m()));
+
+ break;
+ case AltosLib.AO_LOG_GPS_POS:
+ gps = state.make_temp_gps(false);
+ gps.lat = latitude() / 1e7;
+ gps.lon = longitude() / 1e7;
+ gps.alt = altitude();
+ break;
+ case AltosLib.AO_LOG_GPS_TIME:
+ gps = state.make_temp_gps(false);
+
+ gps.hour = hour();
+ gps.minute = minute();
+ gps.second = second();
+
+ int flags = flags();
+
+ gps.connected = (flags & AltosLib.AO_GPS_RUNNING) != 0;
+ gps.locked = (flags & AltosLib.AO_GPS_VALID) != 0;
+ gps.nsat = (flags & AltosLib.AO_GPS_NUM_SAT_MASK) >>
+ AltosLib.AO_GPS_NUM_SAT_SHIFT;
+
+ gps.year = 2000 + year();
+ gps.month = month();
+ gps.day = day();
+ break;
+ case AltosLib.AO_LOG_GPS_SAT:
+ gps = state.make_temp_gps(true);
+
+ int n = nsat();
+ for (int i = 0; i < n; i++)
+ gps.add_sat(svid(i), c_n(i));
+ break;
+ }
+ }
+
+ public AltosEepromMetrum2 (String line) {
+ parse_string(line);
+ }
+
+ static public LinkedList<AltosEeprom> read(FileInputStream input) {
+ LinkedList<AltosEeprom> metrums = new LinkedList<AltosEeprom>();
+
+ for (;;) {
+ try {
+ String line = AltosLib.gets(input);
+ if (line == null)
+ break;
+ try {
+ AltosEepromMetrum2 metrum = new AltosEepromMetrum2(line);
+
+ if (metrum.cmd != AltosLib.AO_LOG_INVALID)
+ metrums.add(metrum);
+ } catch (Exception e) {
+ System.out.printf ("exception\n");
+ }
+ } catch (IOException ie) {
+ break;
+ }
+ }
+
+ return metrums;
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+import java.io.*;
+import java.util.*;
+import java.text.*;
+
+public class AltosEepromMini extends AltosEeprom {
+ public static final int record_length = 16;
+
+ public int record_length() { return record_length; }
+
+ /* AO_LOG_FLIGHT elements */
+ public int flight() { return data16(0); }
+ public int ground_pres() { return data32(4); }
+
+ /* AO_LOG_STATE elements */
+ public int state() { return data16(0); }
+ public int reason() { return data16(2); }
+
+ /* AO_LOG_SENSOR elements */
+ public int pres() { return data24(0); }
+ public int temp() { return data24(3); }
+ public int sense_a() { return data16(6); }
+ public int sense_m() { return data16(8); }
+ public int v_batt() { return data16(10); }
+
+ double voltage(AltosState state, int sensor) {
+ if (state.log_format == AltosLib.AO_LOG_FORMAT_EASYMINI)
+ return AltosConvert.easy_mini_voltage(sensor);
+ else
+ return AltosConvert.tele_mini_voltage(sensor);
+ }
+
+ public void update_state(AltosState state) {
+ super.update_state(state);
+
+ switch (cmd) {
+ case AltosLib.AO_LOG_FLIGHT:
+ state.set_flight(flight());
+ state.set_ground_pressure(ground_pres());
+ break;
+ case AltosLib.AO_LOG_STATE:
+ state.set_state(state());
+ break;
+ case AltosLib.AO_LOG_SENSOR:
+ state.set_ms5607(pres(), temp());
+ state.set_apogee_voltage(voltage(state, sense_a()));
+ state.set_main_voltage(voltage(state, sense_m()));
+ state.set_battery_voltage(voltage(state, v_batt()));
+ break;
+ }
+ }
+
+ public AltosEepromMini (AltosEepromChunk chunk, int start) throws ParseException {
+ parse_chunk(chunk, start);
+ }
+
+ public AltosEepromMini (String line) {
+ parse_string(line);
+ }
+
+ public AltosEepromMini(int in_cmd, int in_tick) {
+ cmd = in_cmd;
+ tick = in_tick;
+ valid = true;
+ }
+
+ static public LinkedList<AltosEeprom> read(FileInputStream input) {
+ LinkedList<AltosEeprom> minis = new LinkedList<AltosEeprom>();
+
+ for (;;) {
+ try {
+ String line = AltosLib.gets(input);
+ if (line == null)
+ break;
+ AltosEepromMini mini = new AltosEepromMini(line);
+ minis.add(mini);
+ } catch (IOException ie) {
+ break;
+ }
+ }
+
+ return minis;
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+public interface AltosEepromMonitor {
+
+ public void set_states(int min_state, int max_state);
+
+ public void set_value(String in_state_name, int in_state, int in_state_block, int in_block);
+
+ public void set_serial(int in_serial);
+
+ public void set_flight(int in_flight);
+
+ public void set_filename(String in_file);
+
+ public void set_thread(Thread eeprom_thread);
+
+ final static int INFO_MESSAGE = 0;
+ final static int WARNING_MESSAGE = 1;
+ final static int ERROR_MESSAGE = 2;
+
+ public void show_message(String message, String title, int message_type);
+
+ public void start();
+
+ public void done(boolean success);
+
+ public void reset();
+}
+++ /dev/null
-/*
- * Copyright © 2010 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-package org.altusmetrum.altoslib_1;
-
-import java.text.*;
-
-public class AltosEepromRecord {
- public int cmd;
- public int tick;
- public int a;
- public int b;
- public String data;
- public boolean tick_valid;
-
- public static final int record_length = 8;
-
- public AltosEepromRecord (AltosEepromChunk chunk, int start) throws ParseException {
-
- cmd = chunk.data(start);
- tick_valid = true;
-
- tick_valid = !chunk.erased(start, record_length);
- if (tick_valid) {
- if (AltosConvert.checksum(chunk.data, start, record_length) != 0)
- throw new ParseException(String.format("invalid checksum at 0x%x",
- chunk.address + start), 0);
- } else {
- cmd = AltosLib.AO_LOG_INVALID;
- }
-
- tick = chunk.data16(start + 2);
- a = chunk.data16(start + 4);
- b = chunk.data16(start + 6);
-
- data = null;
- }
-
- public AltosEepromRecord (String line) {
- tick_valid = false;
- tick = 0;
- a = 0;
- b = 0;
- data = null;
- if (line == null) {
- cmd = AltosLib.AO_LOG_INVALID;
- data = "";
- } else {
- try {
- String[] tokens = line.split("\\s+");
-
- if (tokens[0].length() == 1) {
- if (tokens.length != 4) {
- cmd = AltosLib.AO_LOG_INVALID;
- data = line;
- } else {
- cmd = tokens[0].codePointAt(0);
- tick = Integer.parseInt(tokens[1],16);
- tick_valid = true;
- a = Integer.parseInt(tokens[2],16);
- b = Integer.parseInt(tokens[3],16);
- }
- } else if (tokens[0].equals("Config") && tokens[1].equals("version:")) {
- cmd = AltosLib.AO_LOG_CONFIG_VERSION;
- data = tokens[2];
- } else if (tokens[0].equals("Main") && tokens[1].equals("deploy:")) {
- cmd = AltosLib.AO_LOG_MAIN_DEPLOY;
- a = Integer.parseInt(tokens[2]);
- } else if (tokens[0].equals("Apogee") && tokens[1].equals("delay:")) {
- cmd = AltosLib.AO_LOG_APOGEE_DELAY;
- a = Integer.parseInt(tokens[2]);
- } else if (tokens[0].equals("Radio") && tokens[1].equals("channel:")) {
- cmd = AltosLib.AO_LOG_RADIO_CHANNEL;
- a = Integer.parseInt(tokens[2]);
- } else if (tokens[0].equals("Callsign:")) {
- cmd = AltosLib.AO_LOG_CALLSIGN;
- data = tokens[1].replaceAll("\"","");
- } else if (tokens[0].equals("Accel") && tokens[1].equals("cal")) {
- cmd = AltosLib.AO_LOG_ACCEL_CAL;
- a = Integer.parseInt(tokens[3]);
- b = Integer.parseInt(tokens[5]);
- } else if (tokens[0].equals("Radio") && tokens[1].equals("cal:")) {
- cmd = AltosLib.AO_LOG_RADIO_CAL;
- a = Integer.parseInt(tokens[2]);
- } else if (tokens[0].equals("Max") && tokens[1].equals("flight") && tokens[2].equals("log:")) {
- cmd = AltosLib.AO_LOG_MAX_FLIGHT_LOG;
- a = Integer.parseInt(tokens[3]);
- } else if (tokens[0].equals("manufacturer")) {
- cmd = AltosLib.AO_LOG_MANUFACTURER;
- data = tokens[1];
- } else if (tokens[0].equals("product")) {
- cmd = AltosLib.AO_LOG_PRODUCT;
- data = tokens[1];
- } else if (tokens[0].equals("serial-number")) {
- cmd = AltosLib.AO_LOG_SERIAL_NUMBER;
- a = Integer.parseInt(tokens[1]);
- } else if (tokens[0].equals("log-format")) {
- cmd = AltosLib.AO_LOG_LOG_FORMAT;
- a = Integer.parseInt(tokens[1]);
- } else if (tokens[0].equals("software-version")) {
- cmd = AltosLib.AO_LOG_SOFTWARE_VERSION;
- data = tokens[1];
- } else {
- cmd = AltosLib.AO_LOG_INVALID;
- data = line;
- }
- } catch (NumberFormatException ne) {
- cmd = AltosLib.AO_LOG_INVALID;
- data = line;
- }
- }
- }
-
- public AltosEepromRecord(int in_cmd, int in_tick, int in_a, int in_b) {
- tick_valid = true;
- cmd = in_cmd;
- tick = in_tick;
- a = in_a;
- b = in_b;
- }
-}
--- /dev/null
+/*
+ * Copyright © 2010 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+import java.io.*;
+import java.util.*;
+import java.text.*;
+
+public class AltosEepromTM extends AltosEeprom {
+ public int a;
+ public int b;
+
+ public static final int record_length = 8;
+
+ public void write(PrintStream out) {
+ out.printf("%c %4x %4x %4x\n", cmd, tick, a, b);
+ }
+
+ public int record_length() { return record_length; }
+
+ public String string() {
+ return String.format("%c %4x %4x %4x\n", cmd, tick, a, b);
+ }
+
+ public void update_state(AltosState state) {
+ super.update_state(state);
+
+ AltosGPS gps;
+
+ /* Flush any pending GPS changes */
+ if (state.gps_pending) {
+ switch (cmd) {
+ case AltosLib.AO_LOG_GPS_LAT:
+ case AltosLib.AO_LOG_GPS_LON:
+ case AltosLib.AO_LOG_GPS_ALT:
+ case AltosLib.AO_LOG_GPS_SAT:
+ case AltosLib.AO_LOG_GPS_DATE:
+ break;
+ default:
+ state.set_temp_gps();
+ break;
+ }
+ }
+
+ switch (cmd) {
+ case AltosLib.AO_LOG_FLIGHT:
+ state.set_state(AltosLib.ao_flight_pad);
+ state.set_ground_accel(a);
+ state.set_flight(b);
+ state.set_boost_tick(tick);
+ break;
+ case AltosLib.AO_LOG_SENSOR:
+ state.set_accel(a);
+ state.set_pressure(AltosConvert.barometer_to_pressure(b));
+ break;
+ case AltosLib.AO_LOG_PRESSURE:
+ state.set_pressure(AltosConvert.barometer_to_pressure(b));
+ break;
+ case AltosLib.AO_LOG_TEMP_VOLT:
+ state.set_temperature(AltosConvert.thermometer_to_temperature(a));
+ state.set_battery_voltage(AltosConvert.cc_battery_to_voltage(b));
+ break;
+ case AltosLib.AO_LOG_DEPLOY:
+ state.set_apogee_voltage(AltosConvert.cc_ignitor_to_voltage(a));
+ state.set_main_voltage(AltosConvert.cc_ignitor_to_voltage(b));
+ break;
+ case AltosLib.AO_LOG_STATE:
+ state.set_state(a);
+ break;
+ case AltosLib.AO_LOG_GPS_TIME:
+ gps = state.make_temp_gps(false);
+
+ gps.hour = (a & 0xff);
+ gps.minute = (a >> 8);
+ gps.second = (b & 0xff);
+
+ int flags = (b >> 8);
+
+ gps.connected = (flags & AltosLib.AO_GPS_RUNNING) != 0;
+ gps.locked = (flags & AltosLib.AO_GPS_VALID) != 0;
+ gps.nsat = (flags & AltosLib.AO_GPS_NUM_SAT_MASK) >>
+ AltosLib.AO_GPS_NUM_SAT_SHIFT;
+ break;
+ case AltosLib.AO_LOG_GPS_LAT:
+ gps = state.make_temp_gps(false);
+
+ int lat32 = a | (b << 16);
+ gps.lat = (double) lat32 / 1e7;
+ break;
+ case AltosLib.AO_LOG_GPS_LON:
+ gps = state.make_temp_gps(false);
+
+ int lon32 = a | (b << 16);
+ gps.lon = (double) lon32 / 1e7;
+ break;
+ case AltosLib.AO_LOG_GPS_ALT:
+ gps = state.make_temp_gps(false);
+ gps.alt = a;
+ break;
+ case AltosLib.AO_LOG_GPS_SAT:
+ gps = state.make_temp_gps(true);
+ int svid = a;
+ int c_n0 = b >> 8;
+ gps.add_sat(svid, c_n0);
+ break;
+ case AltosLib.AO_LOG_GPS_DATE:
+ gps = state.make_temp_gps(false);
+ gps.year = (a & 0xff) + 2000;
+ gps.month = a >> 8;
+ gps.day = b & 0xff;
+ break;
+ }
+ }
+
+ public AltosEepromTM (AltosEepromChunk chunk, int start) throws ParseException {
+
+ cmd = chunk.data(start);
+ valid = true;
+
+ valid = !chunk.erased(start, record_length);
+ if (valid) {
+ if (AltosConvert.checksum(chunk.data, start, record_length) != 0)
+ throw new ParseException(String.format("invalid checksum at 0x%x",
+ chunk.address + start), 0);
+ } else {
+ cmd = AltosLib.AO_LOG_INVALID;
+ }
+
+ tick = chunk.data16(start + 2);
+ a = chunk.data16(start + 4);
+ b = chunk.data16(start + 6);
+ }
+
+ public AltosEepromTM (String line) {
+ valid = false;
+ tick = 0;
+ a = 0;
+ b = 0;
+ if (line == null) {
+ cmd = AltosLib.AO_LOG_INVALID;
+ } else {
+ try {
+ String[] tokens = line.split("\\s+");
+
+ if (tokens[0].length() == 1) {
+ if (tokens.length != 4) {
+ cmd = AltosLib.AO_LOG_INVALID;
+ } else {
+ cmd = tokens[0].codePointAt(0);
+ tick = Integer.parseInt(tokens[1],16);
+ valid = true;
+ a = Integer.parseInt(tokens[2],16);
+ b = Integer.parseInt(tokens[3],16);
+ }
+ } else {
+ cmd = AltosLib.AO_LOG_INVALID;
+ }
+ } catch (NumberFormatException ne) {
+ cmd = AltosLib.AO_LOG_INVALID;
+ }
+ }
+ }
+
+ public AltosEepromTM(int in_cmd, int in_tick, int in_a, int in_b) {
+ valid = true;
+ cmd = in_cmd;
+ tick = in_tick;
+ a = in_a;
+ b = in_b;
+ }
+
+ static public LinkedList<AltosEeprom> read(FileInputStream input) {
+ LinkedList<AltosEeprom> tms = new LinkedList<AltosEeprom>();
+
+ for (;;) {
+ try {
+ String line = AltosLib.gets(input);
+ if (line == null)
+ break;
+ AltosEepromTM tm = new AltosEepromTM(line);
+ tms.add(tm);
+ } catch (IOException ie) {
+ break;
+ }
+ }
+
+ return tms;
+ }
+
+}
+++ /dev/null
-/*
- * Copyright © 2011 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-package org.altusmetrum.altoslib_1;
-
-import java.text.*;
-
-public class AltosEepromTeleScience {
- public int type;
- public int tick;
- public int tm_state;
- public int tm_tick;
- public int[] data;
- public boolean valid;
-
- public static final int AO_LOG_TELESCIENCE_START = 's';
- public static final int AO_LOG_TELESCIENCE_DATA = 'd';
-
- static final int max_data = 12;
- public static final int record_length = 32;
-
- public AltosEepromTeleScience (AltosEepromChunk chunk, int start) throws ParseException {
- type = chunk.data(start);
-
- valid = !chunk.erased(start, record_length);
- if (valid) {
- if (AltosConvert.checksum(chunk.data, start, record_length) != 0)
- throw new ParseException(String.format("invalid checksum at 0x%x",
- chunk.address + start), 0);
- } else {
- type = AltosLib.AO_LOG_INVALID;
- }
-
- tick = chunk.data16(start+2);
- tm_tick = chunk.data16(start+4);
- tm_state = chunk.data(start+6);
- data = new int[max_data];
- for (int i = 0; i < max_data; i++)
- data[i] = chunk.data16(start + 8 + i * 2);
- }
-}
--- /dev/null
+/*
+ * Copyright © 2010 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+import java.io.*;
+import java.util.*;
+import java.text.*;
+
+public class AltosEepromTm extends AltosEeprom {
+ public int i;
+ public int a;
+ public int b;
+
+ public static final int record_length = 2;
+
+ public void write(PrintStream out) {
+ out.printf("%c %4x %4x %4x\n", cmd, tick, a, b);
+ }
+
+ public int record_length() { return record_length; }
+
+ public String string() {
+ return String.format("%c %4x %4x %4x\n", cmd, tick, a, b);
+ }
+
+ public void update_state(AltosState state) {
+ super.update_state(state);
+
+ switch (cmd) {
+ case AltosLib.AO_LOG_FLIGHT:
+ state.set_state(AltosLib.ao_flight_boost);
+ state.set_flight(b);
+ break;
+ case AltosLib.AO_LOG_PRESSURE:
+ if (tick == 0)
+ state.set_ground_pressure(AltosConvert.barometer_to_pressure(b));
+ else
+ state.set_pressure(AltosConvert.barometer_to_pressure(b));
+ break;
+ case AltosLib.AO_LOG_STATE:
+ state.set_state(a);
+ break;
+ }
+ }
+
+ public AltosEepromTm (AltosEepromChunk chunk, int start, AltosState state) throws ParseException {
+ int value = chunk.data16(start);
+
+ int i = (chunk.address + start) / record_length;
+
+ cmd = chunk.data(start);
+ valid = true;
+
+ valid = !chunk.erased(start, record_length);
+
+ switch (i) {
+ case 0:
+ cmd = AltosLib.AO_LOG_FLIGHT;
+ tick = 0;
+ a = 0;
+ b = value;
+ break;
+ case 1:
+ cmd = AltosLib.AO_LOG_PRESSURE;
+ tick = 0;
+ a = 0;
+ b = value;
+ break;
+ default:
+ if ((value & 0x8000) != 0) {
+ cmd = AltosLib.AO_LOG_STATE;
+ tick = state.tick;
+ a = value & 0x7fff;
+ b = 0;
+ } else {
+ if (state.ascent)
+ tick = state.tick + 10;
+ else
+ tick = state.tick + 100;
+ cmd = AltosLib.AO_LOG_PRESSURE;
+ a = 0;
+ b = value;
+ }
+ break;
+ }
+ }
+
+ public AltosEepromTm (String line) {
+ valid = false;
+ tick = 0;
+ a = 0;
+ b = 0;
+ if (line == null) {
+ cmd = AltosLib.AO_LOG_INVALID;
+ } else {
+ try {
+ String[] tokens = line.split("\\s+");
+
+ if (tokens[0].length() == 1) {
+ if (tokens.length != 4) {
+ cmd = AltosLib.AO_LOG_INVALID;
+ } else {
+ cmd = tokens[0].codePointAt(0);
+ tick = Integer.parseInt(tokens[1],16);
+ valid = true;
+ a = Integer.parseInt(tokens[2],16);
+ b = Integer.parseInt(tokens[3],16);
+ }
+ } else {
+ cmd = AltosLib.AO_LOG_INVALID;
+ }
+ } catch (NumberFormatException ne) {
+ cmd = AltosLib.AO_LOG_INVALID;
+ }
+ }
+ }
+
+ public AltosEepromTm(int in_cmd, int in_tick, int in_a, int in_b) {
+ valid = true;
+ cmd = in_cmd;
+ tick = in_tick;
+ a = in_a;
+ b = in_b;
+ }
+
+ static public LinkedList<AltosEeprom> read(FileInputStream input) {
+ LinkedList<AltosEeprom> tms = new LinkedList<AltosEeprom>();
+
+ for (;;) {
+ try {
+ String line = AltosLib.gets(input);
+ if (line == null)
+ break;
+ AltosEepromTm tm = new AltosEepromTm(line);
+ tms.add(tm);
+ } catch (IOException ie) {
+ break;
+ }
+ }
+
+ return tms;
+ }
+
+}
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
import java.io.File;
import java.util.*;
public class AltosFile extends File {
- public AltosFile(int year, int month, int day, int serial, int flight, String extension) {
+ static String number(int n) {
+ if (n == AltosLib.MISSING)
+ return "unkn";
+ else
+ return String.format("%04d", n);
+ }
+
+ static String receiver(int receiver) {
+ if (receiver == AltosLib.MISSING)
+ return "";
+ return String.format("-via-%04d", receiver);
+ }
+
+ public AltosFile(int year, int month, int day, int serial, int flight, int receiver, String extension) {
super (AltosPreferences.logdir(),
- String.format("%04d-%02d-%02d-serial-%03d-flight-%03d.%s",
- year, month, day, serial, flight, extension));
+ String.format("%04d-%02d-%02d-serial-%s-flight-%s%s.%s",
+ year, month, day, number(serial), number(flight), receiver(receiver), extension));
+ }
+
+ public AltosFile(int year, int month, int day, int serial, int flight, String extension) {
+ this(year, month, day, serial, flight, AltosLib.MISSING, extension);
+ }
+
+ public AltosFile(int serial, int flight, int receiver, String extension) {
+ this(Calendar.getInstance().get(Calendar.YEAR),
+ Calendar.getInstance().get(Calendar.MONTH) + 1,
+ Calendar.getInstance().get(Calendar.DAY_OF_MONTH),
+ serial,
+ flight,
+ receiver,
+ extension);
}
public AltosFile(int serial, int flight, String extension) {
Calendar.getInstance().get(Calendar.DAY_OF_MONTH),
serial,
flight,
+ AltosLib.MISSING,
extension);
}
- public AltosFile(AltosRecord telem) {
- this(telem.serial, telem.flight, "telem");
+ public AltosFile(AltosState state) {
+ this(state.serial, state.flight, state.receiver_serial, "telem");
}
}
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
import java.io.*;
-public class AltosFlash {
+public class AltosFlash extends AltosProgrammer {
File file;
FileInputStream input;
AltosHexfile image;
close();
}
- public boolean check_rom_config() {
+ public boolean check_rom_config() throws InterruptedException {
if (debug == null)
return true;
if (rom_config == null)
rom_config = romconfig;
}
- public AltosRomconfig romconfig() {
+ public AltosRomconfig romconfig() throws InterruptedException {
if (!check_rom_config())
return null;
return rom_config;
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
public interface AltosFlashListener {
public void position(String label, int percent);
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
import java.text.*;
import java.io.*;
public void init() { }
- public AltosRecord read() throws InterruptedException, ParseException, AltosCRCException, IOException { return null; }
+ public AltosState read() throws InterruptedException, ParseException, AltosCRCException, IOException { return null; }
public void close(boolean interrupted) { }
public File backing_file() { return null; }
- public boolean has_monitor_battery() { return false; }
+ public boolean has_monitor_battery() throws InterruptedException { return false; }
- public double monitor_battery() { return AltosRecord.MISSING; }
+ public double monitor_battery() throws InterruptedException { return AltosLib.MISSING; }
}
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
public class AltosFrequency {
public double frequency;
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
import java.text.*;
+import java.util.concurrent.*;
-public class AltosGPS {
+public class AltosGPS implements Cloneable {
- public final static int MISSING = AltosRecord.MISSING;
+ public final static int MISSING = AltosLib.MISSING;
public int nsat;
public boolean locked;
public boolean connected;
public double lat; /* degrees (+N -S) */
public double lon; /* degrees (+E -W) */
- public int alt; /* m */
+ public double alt; /* m */
public int year;
public int month;
public int day;
}
public void ClearGPSTime() {
- year = month = day = 0;
- hour = minute = second = 0;
+ year = month = day = AltosLib.MISSING;
+ hour = minute = second = AltosLib.MISSING;
}
public AltosGPS(AltosTelemetryMap map) throws ParseException {
- String state = map.get_string(AltosTelemetry.AO_TELEM_GPS_STATE,
- AltosTelemetry.AO_TELEM_GPS_STATE_ERROR);
+ String state = map.get_string(AltosTelemetryLegacy.AO_TELEM_GPS_STATE,
+ AltosTelemetryLegacy.AO_TELEM_GPS_STATE_ERROR);
- nsat = map.get_int(AltosTelemetry.AO_TELEM_GPS_NUM_SAT, 0);
- if (state.equals(AltosTelemetry.AO_TELEM_GPS_STATE_LOCKED)) {
+ nsat = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_NUM_SAT, 0);
+ if (state.equals(AltosTelemetryLegacy.AO_TELEM_GPS_STATE_LOCKED)) {
connected = true;
locked = true;
- lat = map.get_double(AltosTelemetry.AO_TELEM_GPS_LATITUDE, MISSING, 1.0e-7);
- lon = map.get_double(AltosTelemetry.AO_TELEM_GPS_LONGITUDE, MISSING, 1.0e-7);
- alt = map.get_int(AltosTelemetry.AO_TELEM_GPS_ALTITUDE, MISSING);
- year = map.get_int(AltosTelemetry.AO_TELEM_GPS_YEAR, MISSING);
+ lat = map.get_double(AltosTelemetryLegacy.AO_TELEM_GPS_LATITUDE, MISSING, 1.0e-7);
+ lon = map.get_double(AltosTelemetryLegacy.AO_TELEM_GPS_LONGITUDE, MISSING, 1.0e-7);
+ alt = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_ALTITUDE, MISSING);
+ year = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_YEAR, MISSING);
if (year != MISSING)
year += 2000;
- month = map.get_int(AltosTelemetry.AO_TELEM_GPS_MONTH, MISSING);
- day = map.get_int(AltosTelemetry.AO_TELEM_GPS_DAY, MISSING);
-
- hour = map.get_int(AltosTelemetry.AO_TELEM_GPS_HOUR, 0);
- minute = map.get_int(AltosTelemetry.AO_TELEM_GPS_MINUTE, 0);
- second = map.get_int(AltosTelemetry.AO_TELEM_GPS_SECOND, 0);
-
- ground_speed = map.get_double(AltosTelemetry.AO_TELEM_GPS_HORIZONTAL_SPEED,
- AltosRecord.MISSING, 1/100.0);
- course = map.get_int(AltosTelemetry.AO_TELEM_GPS_COURSE,
- AltosRecord.MISSING);
- hdop = map.get_double(AltosTelemetry.AO_TELEM_GPS_HDOP, MISSING, 1.0);
- vdop = map.get_double(AltosTelemetry.AO_TELEM_GPS_VDOP, MISSING, 1.0);
- h_error = map.get_int(AltosTelemetry.AO_TELEM_GPS_HERROR, MISSING);
- v_error = map.get_int(AltosTelemetry.AO_TELEM_GPS_VERROR, MISSING);
- } else if (state.equals(AltosTelemetry.AO_TELEM_GPS_STATE_UNLOCKED)) {
+ month = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_MONTH, MISSING);
+ day = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_DAY, MISSING);
+
+ hour = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_HOUR, 0);
+ minute = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_MINUTE, 0);
+ second = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_SECOND, 0);
+
+ ground_speed = map.get_double(AltosTelemetryLegacy.AO_TELEM_GPS_HORIZONTAL_SPEED,
+ AltosLib.MISSING, 1/100.0);
+ course = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_COURSE,
+ AltosLib.MISSING);
+ hdop = map.get_double(AltosTelemetryLegacy.AO_TELEM_GPS_HDOP, MISSING, 1.0);
+ vdop = map.get_double(AltosTelemetryLegacy.AO_TELEM_GPS_VDOP, MISSING, 1.0);
+ h_error = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_HERROR, MISSING);
+ v_error = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_VERROR, MISSING);
+ } else if (state.equals(AltosTelemetryLegacy.AO_TELEM_GPS_STATE_UNLOCKED)) {
connected = true;
locked = false;
} else {
}
}
+ public boolean parse_string (String line, boolean says_done) {
+ String[] bits = line.split("\\s+");
+ if (bits.length == 0)
+ return false;
+ if (line.startsWith("Date:")) {
+ if (bits.length < 2)
+ return false;
+ String[] d = bits[1].split("/");
+ if (d.length < 3)
+ return false;
+ year = Integer.parseInt(d[0]) + 2000;
+ month = Integer.parseInt(d[1]);
+ day = Integer.parseInt(d[2]);
+ } else if (line.startsWith("Time:")) {
+ if (bits.length < 2)
+ return false;
+ String[] d = bits[1].split(":");
+ if (d.length < 3)
+ return false;
+ hour = Integer.parseInt(d[0]);
+ minute = Integer.parseInt(d[1]);
+ second = Integer.parseInt(d[2]);
+ } else if (line.startsWith("Lat/Lon:")) {
+ if (bits.length < 3)
+ return false;
+ lat = Integer.parseInt(bits[1]) * 1.0e-7;
+ lon = Integer.parseInt(bits[2]) * 1.0e-7;
+ } else if (line.startsWith("Alt:")) {
+ if (bits.length < 2)
+ return false;
+ alt = Integer.parseInt(bits[1]);
+ } else if (line.startsWith("Flags:")) {
+ if (bits.length < 2)
+ return false;
+ int status = Integer.decode(bits[1]);
+ connected = (status & AltosLib.AO_GPS_RUNNING) != 0;
+ locked = (status & AltosLib.AO_GPS_VALID) != 0;
+ if (!says_done)
+ return false;
+ } else if (line.startsWith("Sats:")) {
+ if (bits.length < 2)
+ return false;
+ nsat = Integer.parseInt(bits[1]);
+ cc_gps_sat = new AltosGPSSat[nsat];
+ for (int i = 0; i < nsat; i++) {
+ int svid = Integer.parseInt(bits[2+i*2]);
+ int cc_n0 = Integer.parseInt(bits[3+i*2]);
+ cc_gps_sat[i] = new AltosGPSSat(svid, cc_n0);
+ }
+ } else if (line.startsWith("done")) {
+ return false;
+ } else
+ return false;
+ return true;
+ }
+
public AltosGPS(String[] words, int i, int version) throws ParseException {
AltosParse.word(words[i++], "GPS");
nsat = AltosParse.parse_int(words[i++]);
}
public AltosGPS() {
+ lat = AltosLib.MISSING;
+ lon = AltosLib.MISSING;
+ alt = AltosLib.MISSING;
ClearGPSTime();
cc_gps_sat = null;
}
+ public AltosGPS clone() {
+ AltosGPS g = new AltosGPS();
+
+ g.nsat = nsat;
+ g.locked = locked;
+ g.connected = connected;
+ g.lat = lat; /* degrees (+N -S) */
+ g.lon = lon; /* degrees (+E -W) */
+ g.alt = alt; /* m */
+ g.year = year;
+ g.month = month;
+ g.day = day;
+ g.hour = hour;
+ g.minute = minute;
+ g.second = second;
+
+ g.ground_speed = ground_speed; /* m/s */
+ g.course = course; /* degrees */
+ g.climb_rate = climb_rate; /* m/s */
+ g.hdop = hdop; /* unitless? */
+ g.h_error = h_error; /* m */
+ g.v_error = v_error; /* m */
+
+ if (cc_gps_sat != null) {
+ g.cc_gps_sat = new AltosGPSSat[cc_gps_sat.length];
+ for (int i = 0; i < cc_gps_sat.length; i++) {
+ g.cc_gps_sat[i] = new AltosGPSSat(cc_gps_sat[i].svid,
+ cc_gps_sat[i].c_n0);
+ }
+ }
+ return g;
+ }
+
public AltosGPS(AltosGPS old) {
if (old != null) {
nsat = old.nsat;
}
}
} else {
+ lat = AltosLib.MISSING;
+ lon = AltosLib.MISSING;
+ alt = AltosLib.MISSING;
ClearGPSTime();
cc_gps_sat = null;
}
}
+
+ static public void update_state(AltosState state, AltosLink link, AltosConfigData config_data) throws InterruptedException {
+ try {
+ AltosGPS gps = new AltosGPS(link, config_data);
+
+ if (gps != null) {
+ state.set_gps(gps, state.gps_sequence++);
+ return;
+ }
+ } catch (TimeoutException te) {
+ }
+ state.set_gps(null, 0);
+ }
+
+ public AltosGPS (AltosLink link, AltosConfigData config_data) throws TimeoutException, InterruptedException {
+ boolean says_done = config_data.compare_version("1.0") >= 0;
+ link.printf("g\n");
+ for (;;) {
+ String line = link.get_reply_no_dialog(5000);
+ if (line == null)
+ throw new TimeoutException();
+ if (!parse_string(line, says_done))
+ break;
+ }
+ }
}
+++ /dev/null
-/*
- * Copyright © 2012 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-package org.altusmetrum.altoslib_1;
-
-import java.util.concurrent.*;
-
-class AltosGPSQuery extends AltosGPS {
- public AltosGPSQuery (AltosLink link, AltosConfigData config_data)
- throws TimeoutException, InterruptedException {
- boolean says_done = config_data.compare_version("1.0") >= 0;
- link.printf("g\n");
- for (;;) {
- String line = link.get_reply_no_dialog(5000);
- if (line == null)
- throw new TimeoutException();
- String[] bits = line.split("\\s+");
- if (bits.length == 0)
- continue;
- if (line.startsWith("Date:")) {
- if (bits.length < 2)
- continue;
- String[] d = bits[1].split(":");
- if (d.length < 3)
- continue;
- year = Integer.parseInt(d[0]) + 2000;
- month = Integer.parseInt(d[1]);
- day = Integer.parseInt(d[2]);
- continue;
- }
- if (line.startsWith("Time:")) {
- if (bits.length < 2)
- continue;
- String[] d = bits[1].split("/");
- if (d.length < 3)
- continue;
- hour = Integer.parseInt(d[0]);
- minute = Integer.parseInt(d[1]);
- second = Integer.parseInt(d[2]);
- continue;
- }
- if (line.startsWith("Lat/Lon:")) {
- if (bits.length < 3)
- continue;
- lat = Integer.parseInt(bits[1]) * 1.0e-7;
- lon = Integer.parseInt(bits[2]) * 1.0e-7;
- continue;
- }
- if (line.startsWith("Alt:")) {
- if (bits.length < 2)
- continue;
- alt = Integer.parseInt(bits[1]);
- continue;
- }
- if (line.startsWith("Flags:")) {
- if (bits.length < 2)
- continue;
- int status = Integer.decode(bits[1]);
- connected = (status & AltosLib.AO_GPS_RUNNING) != 0;
- locked = (status & AltosLib.AO_GPS_VALID) != 0;
- if (!says_done)
- break;
- continue;
- }
- if (line.startsWith("Sats:")) {
- if (bits.length < 2)
- continue;
- nsat = Integer.parseInt(bits[1]);
- cc_gps_sat = new AltosGPSSat[nsat];
- for (int i = 0; i < nsat; i++) {
- int svid = Integer.parseInt(bits[2+i*2]);
- int cc_n0 = Integer.parseInt(bits[3+i*2]);
- cc_gps_sat[i] = new AltosGPSSat(svid, cc_n0);
- }
- }
- if (line.startsWith("done"))
- break;
- if (line.startsWith("Syntax error"))
- break;
- }
- }
-}
-
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
public class AltosGPSSat {
public int svid;
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
import java.lang.Math;
-public class AltosGreatCircle {
+public class AltosGreatCircle implements Cloneable {
public double distance;
public double bearing;
public double range;
elevation = Math.atan2(height_diff, distance) * 180 / Math.PI;
}
+ public AltosGreatCircle clone() {
+ AltosGreatCircle n = new AltosGreatCircle();
+
+ n.distance = distance;
+ n.bearing = bearing;
+ n.range = range;
+ n.elevation = elevation;
+ return n;
+ }
+
public AltosGreatCircle (double start_lat, double start_lon,
double end_lat, double end_lon) {
this(start_lat, start_lon, 0, end_lat, end_lon, 0);
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
public class AltosHeight extends AltosUnits {
- public double value(double v) {
- if (AltosConvert.imperial_units)
+ public double value(double v, boolean imperial_units) {
+ if (imperial_units)
return AltosConvert.meters_to_feet(v);
return v;
}
- public String show_units() {
- if (AltosConvert.imperial_units)
+ public double inverse(double v, boolean imperial_units) {
+ if (imperial_units)
+ return AltosConvert.feet_to_meters(v);
+ return v;
+ }
+
+ public String show_units(boolean imperial_units) {
+ if (imperial_units)
return "ft";
return "m";
}
- public String say_units() {
- if (AltosConvert.imperial_units)
+ public String say_units(boolean imperial_units) {
+ if (imperial_units)
return "feet";
return "meters";
}
- public int show_fraction(int width) {
+ public int show_fraction(int width, boolean imperial_units) {
return width / 9;
}
}
\ No newline at end of file
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
import java.io.*;
import java.util.LinkedList;
return String.format("%04x: %02x (%d)", address, type, data.length);
}
- public HexRecord(HexFileInputStream input) throws IOException {
+ public HexRecord(HexFileInputStream input) throws IOException, EOFException {
read_state state = read_state.marker;
int nhexbytes = 0;
int hex = 0;
while (state != read_state.done) {
int c = input.read();
- if (c < 0 && state != read_state.white)
+ if (c < 0 && state != read_state.white && state != read_state.marker)
throw new IOException(String.format("%d: Unexpected EOF", input.line));
if (c == ' ')
continue;
switch (state) {
case marker:
+ if (c == EOF || c == -1)
+ throw new EOFException();
if (c != ':')
- throw new IOException("Missing ':'");
+ throw new IOException(String.format ("Missing ':' (got %x)", c));
state = read_state.length;
nhexbytes = 2;
hex = 0;
}
public class AltosHexfile {
- public int address;
- public byte[] data;
+ public int address;
+ public byte[] data;
+ LinkedList<AltosHexsym> symlist = new LinkedList<AltosHexsym>();
public byte get_byte(int a) {
return data[a - address];
}
+ /* CC1111-based products have the romconfig stuff located
+ * at a fixed address; when the file we load has no symbols,
+ * assume it is one of those and set the symbols appropriately
+ */
+ final static int ao_romconfig_version_addr = 0xa0;
+ final static int ao_romconfig_check_addr = 0xa2;
+ final static int ao_serial_number_addr = 0xa4;
+ final static int ao_radio_cal_addr = 0xa6;
+ final static int ao_usb_descriptors_addr = 0xaa;
+
+ static AltosHexsym[] cc_symbols = {
+ new AltosHexsym("ao_romconfig_version", ao_romconfig_version_addr),
+ new AltosHexsym("ao_romconfig_check", ao_romconfig_check_addr),
+ new AltosHexsym("ao_serial_number", ao_serial_number_addr),
+ new AltosHexsym("ao_radio_cal", ao_radio_cal_addr),
+ new AltosHexsym("ao_usb_descriptors", ao_usb_descriptors_addr)
+ };
+
+ private void add_cc_symbols() {
+ for (int i = 0; i < cc_symbols.length; i++)
+ symlist.add(cc_symbols[i]);
+ }
+
+ public void add_symbol(AltosHexsym symbol) {
+ symlist.add(symbol);
+ }
+
+ /* Take symbols from another hexfile and duplicate them here */
+ public void add_symbols(AltosHexfile other) {
+ for (AltosHexsym symbol : other.symlist)
+ symlist.add(symbol);
+ }
+
+ public AltosHexsym lookup_symbol(String name) {
+ if (symlist.isEmpty())
+ add_cc_symbols();
+
+ for (AltosHexsym symbol : symlist)
+ if (name.equals(symbol.name))
+ return symbol;
+ return null;
+ }
+
+ private String make_string(byte[] data, int start, int length) {
+ String s = "";
+ for (int i = 0; i < length; i++)
+ s += (char) data[start + i];
+ return s;
+ }
+
+ public AltosHexfile(byte[] bytes, int offset) {
+ data = bytes;
+ address = offset;
+ }
+
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);
+ try {
+ HexRecord record = new HexRecord(input);
- if (record.type == HexRecord.EOF)
- done = true;
- else
record_list.add(record);
+ } catch (EOFException eof) {
+ done = true;
+ }
}
long extended_addr = 0;
long bound = 0;
boolean set = false;
for (HexRecord record : record_list) {
+ long addr;
switch (record.type) {
case 0:
- long addr = extended_addr + record.address;
+ addr = extended_addr + record.address;
long r_bound = addr + record.data.length;
if (!set || addr < base)
base = addr;
throw new IOException("invalid extended segment address record");
extended_addr = ((record.data[0] << 8) + (record.data[1])) << 16;
break;
+ case 0xfe:
+ String name = make_string(record.data, 0, record.data.length);
+ addr = extended_addr + record.address;
+ AltosHexsym s = new AltosHexsym(name, addr);
+ symlist.add(s);
+ break;
default:
throw new IOException ("invalid hex record type");
}
throw new IOException("invalid extended segment address record");
extended_addr = ((record.data[0] << 8) + (record.data[1])) << 16;
break;
+ case 0xfe:
+ break;
default:
throw new IOException ("invalid hex record type");
}
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+public class AltosHexsym {
+ String name;
+ long address;
+
+ final static long invalid_addr = 0xffffffff;
+
+ public AltosHexsym(String name, long address) {
+ this.name = name;
+ this.address = address;
+ }
+}
\ No newline at end of file
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
-public class AltosIMU {
+import java.util.concurrent.*;
+
+public class AltosIMU implements Cloneable {
public int accel_x;
public int accel_y;
public int accel_z;
public int gyro_x;
public int gyro_y;
public int gyro_z;
+
+ public boolean parse_string(String line) {
+ if (!line.startsWith("Accel:"))
+ return false;
+
+ String[] items = line.split("\\s+");
+
+ if (items.length >= 8) {
+ accel_x = Integer.parseInt(items[1]);
+ accel_y = Integer.parseInt(items[2]);
+ accel_z = Integer.parseInt(items[3]);
+ gyro_x = Integer.parseInt(items[5]);
+ gyro_y = Integer.parseInt(items[6]);
+ gyro_z = Integer.parseInt(items[7]);
+ }
+ return true;
+ }
+
+ public AltosIMU clone() {
+ AltosIMU n = new AltosIMU();
+
+ n.accel_x = accel_x;
+ n.accel_y = accel_y;
+ n.accel_z = accel_z;
+
+ n.gyro_x = gyro_x;
+ n.gyro_y = gyro_y;
+ n.gyro_z = gyro_z;
+ return n;
+ }
+
+ static public void update_state(AltosState state, AltosLink link, AltosConfigData config_data) throws InterruptedException {
+ try {
+ AltosIMU imu = new AltosIMU(link);
+
+ if (imu != null)
+ state.set_imu(imu);
+ } catch (TimeoutException te) {
+ }
+ }
+
+ public AltosIMU() {
+ accel_x = AltosLib.MISSING;
+ accel_y = AltosLib.MISSING;
+ accel_z = AltosLib.MISSING;
+
+ gyro_x = AltosLib.MISSING;
+ gyro_y = AltosLib.MISSING;
+ gyro_z = AltosLib.MISSING;
+ }
+
+ public AltosIMU(AltosLink link) throws InterruptedException, TimeoutException {
+ this();
+ link.printf("I\n");
+ for (;;) {
+ String line = link.get_reply_no_dialog(5000);
+ if (line == null) {
+ throw new TimeoutException();
+ }
+ if (parse_string(line))
+ break;
+ }
+ }
}
-
\ No newline at end of file
+++ /dev/null
-/*
- * Copyright © 2012 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-package org.altusmetrum.altoslib_1;
-
-import java.util.concurrent.TimeoutException;
-
-class AltosIMUQuery extends AltosIMU {
-
- public AltosIMUQuery (AltosLink link) throws InterruptedException, TimeoutException {
- link.printf("I\n");
- for (;;) {
- String line = link.get_reply_no_dialog(5000);
- if (line == null) {
- throw new TimeoutException();
- }
- if (!line.startsWith("Accel:"))
- continue;
- String[] items = line.split("\\s+");
- if (items.length >= 8) {
- accel_x = Integer.parseInt(items[1]);
- accel_y = Integer.parseInt(items[2]);
- accel_z = Integer.parseInt(items[3]);
- gyro_x = Integer.parseInt(items[5]);
- gyro_y = Integer.parseInt(items[6]);
- gyro_z = Integer.parseInt(items[7]);
- }
- break;
- }
- }
-}
-
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+import java.io.*;
+import java.util.*;
+import java.text.*;
+import java.util.concurrent.*;
+
+public abstract class AltosIdle {
+ AltosLink link;
+ AltosConfigData config_data;
+
+ public void printf(String format, Object ... arguments) {
+ link.printf(format, arguments);
+ }
+
+ public abstract void update_state(AltosState state) throws InterruptedException, TimeoutException;
+
+ public AltosIdle(AltosLink link, AltosConfigData config_data) {
+ this.link = link;
+ this.config_data = config_data;
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+import java.io.*;
+import java.util.*;
+import java.text.*;
+import java.util.concurrent.*;
+
+class AltosIdler {
+ String prefix;
+ int[] idlers;
+
+ static final int idle_gps = 0;
+ static final int idle_imu = 1;
+ static final int idle_mag = 2;
+ static final int idle_ms5607 = 3;
+ static final int idle_mma655x = 4;
+
+
+ static final int idle_sensor_tm = 10;
+ static final int idle_sensor_metrum = 11;
+ static final int idle_sensor_mega = 12;
+ static final int idle_sensor_emini = 13;
+ static final int idle_sensor_tmini = 14;
+
+ public void update_state(AltosState state, AltosLink link, AltosConfigData config_data) throws InterruptedException, TimeoutException {
+ for (int idler : idlers) {
+ AltosIdle idle = null;
+ switch (idler) {
+ case idle_gps:
+ AltosGPS.update_state(state, link, config_data);
+ break;
+ case idle_imu:
+ AltosIMU.update_state(state, link, config_data);
+ break;
+ case idle_mag:
+ AltosMag.update_state(state, link, config_data);
+ break;
+ case idle_ms5607:
+ AltosMs5607.update_state(state, link, config_data);
+ break;
+ case idle_mma655x:
+ AltosMma655x.update_state(state, link, config_data);
+ break;
+ case idle_sensor_tm:
+ AltosSensorTM.update_state(state, link, config_data);
+ break;
+ case idle_sensor_metrum:
+ AltosSensorMetrum.update_state(state, link, config_data);
+ break;
+ case idle_sensor_mega:
+ AltosSensorMega.update_state(state, link, config_data);
+ break;
+ case idle_sensor_emini:
+ AltosSensorEMini.update_state(state, link, config_data);
+ break;
+ case idle_sensor_tmini:
+ AltosSensorTMini.update_state(state, link, config_data);
+ }
+ if (idle != null)
+ idle.update_state(state);
+ }
+ }
+
+ public boolean matches(AltosConfigData config_data) {
+ return config_data.product.startsWith(prefix);
+ }
+
+ public AltosIdler(String prefix, int ... idlers) {
+ this.prefix = prefix;
+ this.idlers = idlers;
+ }
+}
+
+
+public class AltosIdleFetch implements AltosStateUpdate {
+
+ static final AltosIdler[] idlers = {
+
+ new AltosIdler("EasyMini",
+ AltosIdler.idle_ms5607,
+ AltosIdler.idle_sensor_emini),
+
+ new AltosIdler("TeleMini-v1",
+ AltosIdler.idle_sensor_tm),
+
+ new AltosIdler("TeleMini-v2",
+ AltosIdler.idle_ms5607,
+ AltosIdler.idle_sensor_tmini),
+
+ new AltosIdler("TeleMetrum-v1",
+ AltosIdler.idle_gps,
+ AltosIdler.idle_sensor_tm),
+
+ new AltosIdler("TeleMetrum-v2",
+ AltosIdler.idle_gps,
+ AltosIdler.idle_ms5607, AltosIdler.idle_mma655x,
+ AltosIdler.idle_sensor_metrum),
+
+ new AltosIdler("TeleMega",
+ AltosIdler.idle_gps,
+ AltosIdler.idle_ms5607, AltosIdler.idle_mma655x,
+ AltosIdler.idle_imu, AltosIdler.idle_mag,
+ AltosIdler.idle_sensor_mega),
+ };
+
+ AltosLink link;
+
+ double frequency;
+ String callsign;
+
+ public void update_state(AltosState state) throws InterruptedException {
+ try {
+ AltosConfigData config_data = new AltosConfigData(link);
+ state.set_state(AltosLib.ao_flight_startup);
+ state.set_serial(config_data.serial);
+ state.set_callsign(config_data.callsign);
+ state.set_ground_accel(config_data.accel_cal_plus);
+ state.set_accel_g(config_data.accel_cal_plus, config_data.accel_cal_minus);
+ for (AltosIdler idler : idlers) {
+ if (idler.matches(config_data)) {
+ idler.update_state(state, link, config_data);
+ break;
+ }
+ }
+ state.set_received_time(System.currentTimeMillis());
+ } catch (TimeoutException te) {
+ }
+
+ }
+
+ public AltosIdleFetch(AltosLink link) {
+ this.link = link;
+ }
+}
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
import java.io.*;
import java.util.concurrent.*;
public class AltosIdleMonitor extends Thread {
AltosLink link;
AltosIdleMonitorListener listener;
- AltosState state;
+
+ AltosIdleFetch fetch;
+
boolean remote;
double frequency;
String callsign;
- AltosState previous_state;
+
AltosListenerState listener_state;
AltosConfigData config_data;
AltosGPS gps;
return rssi;
}
- boolean has_sensor_tm(AltosConfigData config_data) {
- return config_data.product.startsWith("TeleMetrum") || config_data.product.startsWith("TeleMini");
- }
-
- boolean has_sensor_mm(AltosConfigData config_data) {
- return config_data.product.startsWith("TeleMega");
+ void start_link() throws InterruptedException, TimeoutException {
+ if (remote) {
+ link.set_radio_frequency(frequency);
+ link.set_callsign(callsign);
+ link.start_remote();
+ } else
+ link.flush_input();
}
- boolean has_gps(AltosConfigData config_data) {
- return config_data.product.startsWith("TeleMetrum") || config_data.product.startsWith("TeleMega");
- }
-
- AltosRecord sensor_mm(AltosConfigData config_data) throws InterruptedException, TimeoutException {
- AltosRecordMM record_mm = new AltosRecordMM();
- AltosSensorMM sensor = new AltosSensorMM(link);
- AltosMs5607 ms5607 = new AltosMs5607Query(link);
- AltosIMU imu = new AltosIMUQuery(link);
-
- record_mm.accel_plus_g = config_data.accel_cal_plus;
- record_mm.accel_minus_g = config_data.accel_cal_minus;
-
- record_mm.ground_accel = sensor.accel;
- record_mm.accel = sensor.accel;
- record_mm.ground_pres = ms5607.pa;
- record_mm.pres = ms5607.pa;
- record_mm.temp = ms5607.cc;
-
- record_mm.v_batt = sensor.v_batt;
- record_mm.v_pyro = sensor.v_pyro;
- record_mm.sense = sensor.sense;
-
- record_mm.imu = imu;
-
- return record_mm;
+ void stop_link() throws InterruptedException, TimeoutException {
+ if (remote)
+ link.stop_remote();
}
- void update_state() throws InterruptedException, TimeoutException {
- AltosRecord record = null;
+ void update_state(AltosState state) throws InterruptedException, TimeoutException {
+ boolean worked = false;
try {
- if (remote) {
- link.set_radio_frequency(frequency);
- link.set_callsign(callsign);
- link.start_remote();
- } else
- link.flush_input();
- config_data = new AltosConfigData(link);
-
- if (has_sensor_tm(config_data))
- record = new AltosSensorTM(link, config_data);
- else if (has_sensor_mm(config_data))
- record = sensor_mm(config_data);
- else
- record = new AltosRecordNone();
-
- if (has_gps(config_data))
- gps = new AltosGPSQuery(link, config_data);
-
- record.version = 0;
- record.callsign = config_data.callsign;
- record.serial = config_data.serial;
- record.flight = config_data.log_available() > 0 ? 255 : 0;
- record.status = 0;
- record.state = AltosLib.ao_flight_idle;
- record.gps = gps;
- record.gps_sequence++;
- state = new AltosState (record, state);
+ start_link();
+ fetch.update_state(state);
+ worked = true;
} finally {
- if (remote) {
- link.stop_remote();
- if (record != null) {
- record.rssi = link.rssi();
- listener_state.battery = link.monitor_battery();
- }
- } else {
- if (record != null)
- record.rssi = 0;
+ stop_link();
+ if (worked) {
+ if (remote)
+ state.set_rssi(link.rssi(), 0);
+ listener_state.battery = link.monitor_battery();
}
}
-
}
public void set_frequency(double in_frequency) {
link.abort_reply();
}
- public void post_state() {
- listener.update(state, listener_state);
- }
-
- public void abort() {
- if (isAlive()) {
+ public void abort() throws InterruptedException {
+ while (isAlive()) {
interrupt();
link.abort_reply();
- try {
- join();
- } catch (InterruptedException ie) {
- }
+ Thread.sleep(100);
}
+ join();
}
public void run() {
+ AltosState state = new AltosState();
try {
- for (;;) {
+ while (!link.has_error) {
try {
- update_state();
- post_state();
+ link.config_data();
+ update_state(state);
+ listener.update(state, listener_state);
} catch (TimeoutException te) {
}
Thread.sleep(1000);
}
} catch (InterruptedException ie) {
+ }
+ try {
link.close();
+ } catch (InterruptedException ie) {
}
}
listener = in_listener;
link = in_link;
remote = in_remote;
- state = null;
listener_state = new AltosListenerState();
+ fetch = new AltosIdleFetch(link);
}
}
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
public interface AltosIdleMonitorListener {
public void update(AltosState state, AltosListenerState listener_state);
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
import java.io.*;
import java.util.concurrent.*;
}
}
- public void fire(int igniter) {
+ public void fire(int igniter) throws InterruptedException {
if (link == null)
return;
try {
link.printf("i DoIt drogue\n");
break;
}
- } catch (InterruptedException ie) {
} catch (TimeoutException te) {
} finally {
- try {
- stop_link();
- } catch (InterruptedException ie) {
- }
+ stop_link();
}
}
- public void close() {
- try {
- stop_link();
- } catch (InterruptedException ie) {
- }
+ public void close() throws InterruptedException {
+ stop_link();
link.close();
link = null;
}
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
import java.util.*;
import java.io.*;
public static final int AO_LOG_TEMP_VOLT = 'T';
public static final int AO_LOG_DEPLOY = 'D';
public static final int AO_LOG_STATE = 'S';
+ public static final int AO_LOG_GPS_POS = 'P';
public static final int AO_LOG_GPS_TIME = 'G';
public static final int AO_LOG_GPS_LAT = 'N';
public static final int AO_LOG_GPS_LON = 'W';
public static final int AO_LOG_SOFTWARE_VERSION = 9999;
+ public final static int MISSING = 0x7fffffff;
+
/* Added to flag invalid records */
public static final int AO_LOG_INVALID = -1;
public final static int product_telemega = 0x0023;
public final static int product_megadongle = 0x0024;
public final static int product_telegps = 0x0025;
+ public final static int product_easymini = 0x0026;
+ public final static int product_telemini = 0x0027;
public final static int product_altusmetrum_min = 0x000a;
- public final static int product_altusmetrum_max = 0x0025;
+ public final static int product_altusmetrum_max = 0x002c;
public final static int product_any = 0x10000;
public final static int product_basestation = 0x10000 + 1;
public final static int product_altimeter = 0x10000 + 2;
+ private static class Product {
+ final String name;
+ final int product;
+
+ Product (String name, int product) {
+ this.name = name;
+ this.product = product;
+ }
+ }
+
+ private static Product[] products = {
+ new Product("telemetrum", product_telemetrum),
+ new Product("teleballoon", product_telemetrum),
+ new Product("teledongle", product_teledongle),
+ new Product("teleterra", product_teledongle),
+ new Product("telebt", product_telebt),
+ new Product("telelaunch", product_telelaunch),
+ new Product("telelco", product_telelco),
+ new Product("telescience", product_telescience),
+ new Product("telepyro", product_telepyro),
+ new Product("telemega", product_telemega),
+ new Product("megadongle", product_megadongle),
+ new Product("telegps", product_telegps),
+ new Product("easymini", product_easymini),
+ new Product("telemini", product_telemini)
+ };
+
+ public static int name_to_product(String name) {
+ String low = name.toLowerCase();
+
+ for (int i = 0; i < products.length; i++)
+ if (low.startsWith(products[i].name))
+ return products[i].product;
+ return product_any;
+ }
+
/* Bluetooth "identifier" (bluetooth sucks) */
public final static String bt_product_telebt = "TeleBT";
+ /* "good" voltages */
+
+ public final static double ao_battery_good = 3.8;
+ public final static double ao_igniter_good = 3.5;
+
/* Telemetry modes */
public static final int ao_telemetry_off = 0;
public static final int ao_telemetry_min = 1;
public static final int AO_LOG_FORMAT_TELEMETRY = 3;
public static final int AO_LOG_FORMAT_TELESCIENCE = 4;
public static final int AO_LOG_FORMAT_TELEMEGA = 5;
+ public static final int AO_LOG_FORMAT_EASYMINI = 6;
+ public static final int AO_LOG_FORMAT_TELEMETRUM = 7;
+ public static final int AO_LOG_FORMAT_TELEMINI = 8;
public static final int AO_LOG_FORMAT_NONE = 127;
public static boolean isspace(int c) {
public static File replace_extension(File input, String extension) {
return new File(replace_extension(input.getPath(), extension));
}
+
+ public static String product_name(int product_id) {
+ switch (product_id) {
+ case product_altusmetrum: return "AltusMetrum";
+ case product_telemetrum: return "TeleMetrum";
+ case product_teledongle: return "TeleDongle";
+ case product_teleterra: return "TeleTerra";
+ case product_telebt: return "TeleBT";
+ case product_telelaunch: return "TeleLaunch";
+ case product_telelco: return "TeleLco";
+ case product_telescience: return "Telescience";
+ case product_telepyro: return "TelePyro";
+ case product_telemega: return "TeleMega";
+ case product_megadongle: return "MegaDongle";
+ case product_telegps: return "TeleGPS";
+ case product_easymini: return "EasyMini";
+ case product_telemini: return "TeleMini";
+ default: return "unknown";
+ }
+ }
}
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
public class AltosLine {
public String line;
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
import java.io.*;
import java.util.concurrent.*;
public final static int ERROR = -1;
public final static int TIMEOUT = -2;
- public abstract int getchar();
- public abstract void print(String data);
- public abstract void close();
+ public abstract int getchar() throws InterruptedException;
+ public abstract void print(String data) throws InterruptedException;
+ public abstract void putchar(byte c);
+ public abstract void close() throws InterruptedException;
public static boolean debug = false;
public static void set_debug(boolean in_debug) { debug = in_debug; }
+
+ public boolean has_error;
+
LinkedList<String> pending_output = new LinkedList<String>();
public LinkedList<LinkedBlockingQueue<AltosLine>> monitors = new LinkedList<LinkedBlockingQueue<AltosLine>> ();;
public LinkedBlockingQueue<AltosLine> reply_queue = new LinkedBlockingQueue<AltosLine>();
+ public LinkedBlockingQueue<byte[]> binary_queue = new LinkedBlockingQueue<byte[]>();
- public void add_monitor(LinkedBlockingQueue<AltosLine> q) {
+ public synchronized void add_monitor(LinkedBlockingQueue<AltosLine> q) {
set_monitor(true);
monitors.add(q);
}
- public void remove_monitor(LinkedBlockingQueue<AltosLine> q) {
+ public synchronized void remove_monitor(LinkedBlockingQueue<AltosLine> q) {
monitors.remove(q);
if (monitors.isEmpty())
set_monitor(false);
String line = String.format(format, arguments);
if (debug)
pending_output.add(line);
- print(line);
+ try {
+ print(line);
+ } catch (InterruptedException ie) {
+
+ }
}
public String get_reply_no_dialog(int timeout) throws InterruptedException, TimeoutException {
}
}
+ private int len_read = 0;
public void run () {
int c;
for (;;) {
c = getchar();
if (Thread.interrupted()) {
- if (debug)
- System.out.printf("INTERRUPTED\n");
break;
}
if (c == ERROR) {
if (debug)
System.out.printf("ERROR\n");
+ has_error = true;
add_telem (new AltosLine());
add_reply (new AltosLine());
break;
System.out.printf("TIMEOUT\n");
continue;
}
- if (c == '\r')
+ if (c == '\r' && len_read == 0)
continue;
synchronized(this) {
- if (c == '\n') {
+ if (c == '\n' && len_read == 0) {
if (line_count != 0) {
add_bytes(line_bytes, line_count);
line_count = 0;
}
line_bytes[line_count] = (byte) c;
line_count++;
+ if (len_read !=0 && line_count == len_read) {
+ add_binary(line_bytes, line_count);
+ line_count = 0;
+ len_read = 0;
+ }
}
}
}
}
}
+
public String get_reply(int timeout) throws InterruptedException {
boolean can_cancel = can_cancel_reply();
String reply = null;
return reply;
}
+ public byte[] get_binary_reply(int timeout, int len) throws InterruptedException {
+ boolean can_cancel = can_cancel_reply();
+ byte[] bytes = null;
+
+ synchronized(this) {
+ len_read = len;
+ }
+ try {
+ ++in_reply;
+
+ flush_output();
+
+ reply_abort = false;
+ reply_timeout_shown = false;
+ for (;;) {
+ bytes = binary_queue.poll(timeout, TimeUnit.MILLISECONDS);
+ if (bytes != null) {
+ cleanup_reply_timeout();
+ break;
+ }
+ if (!remote || !can_cancel || check_reply_timeout()) {
+ bytes = null;
+ break;
+ }
+ }
+
+ } finally {
+ --in_reply;
+ }
+ return bytes;
+ }
+
public void add_telem(AltosLine line) throws InterruptedException {
for (int e = 0; e < monitors.size(); e++) {
LinkedBlockingQueue<AltosLine> q = monitors.get(e);
try {
add_telem (new AltosLine());
add_reply (new AltosLine());
- } catch (InterruptedException e) {
+ } catch (InterruptedException ie) {
}
}
add_string(line);
}
+ public void add_binary(byte[] bytes, int len) throws InterruptedException {
+ byte[] dup = new byte[len];
+
+ if (debug)
+ System.out.printf ("\t\t\t\t\t%d:", len);
+ for(int i = 0; i < len; i++) {
+ dup[i] = bytes[i];
+ if (debug)
+ System.out.printf(" %02x", dup[i]);
+ }
+ if (debug)
+ System.out.printf("\n");
+
+ binary_queue.put(dup);
+ }
+
public void flush_output() {
for (String s : pending_output)
System.out.print(s);
public String callsign;
AltosConfigData config_data;
+ private Object config_data_lock = new Object();
+
private int telemetry_len() {
return AltosLib.telemetry_len(telemetry);
}
}
public AltosConfigData config_data() throws InterruptedException, TimeoutException {
- if (config_data == null)
- config_data = new AltosConfigData(this);
- return config_data;
+ synchronized(config_data_lock) {
+ if (config_data == null)
+ config_data = new AltosConfigData(this);
+ return config_data;
+ }
}
public void set_callsign(String callsign) {
flush_output();
}
+ public boolean is_loader() throws InterruptedException {
+ boolean ret = false;
+ printf("v\n");
+ for (;;) {
+ String line = get_reply();
+
+ if (line == null)
+ return false;
+ if (line.startsWith("software-version"))
+ break;
+ if (line.startsWith("altos-loader"))
+ ret = true;
+ }
+ return ret;
+ }
+
+ public void to_loader() throws InterruptedException {
+ printf("X\n");
+ flush_output();
+ close();
+ Thread.sleep(1000);
+ }
+
public boolean remote;
public int serial;
public String name;
return config_data.has_monitor_battery();
}
- public double monitor_battery() {
- int monitor_batt = AltosRecord.MISSING;
+ public double monitor_battery() throws InterruptedException {
+ int monitor_batt = AltosLib.MISSING;
if (config_data.has_monitor_battery()) {
try {
}
i++;
}
- } catch (InterruptedException ie) {
} catch (TimeoutException te) {
}
}
- if (monitor_batt == AltosRecord.MISSING)
- return AltosRecord.MISSING;
+ if (monitor_batt == AltosLib.MISSING)
+ return AltosLib.MISSING;
return AltosConvert.cc_battery_to_voltage(monitor_batt);
}
public AltosLink() {
callsign = "";
+ has_error = false;
}
}
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
public class AltosListenerState {
public int crc_errors;
public AltosListenerState() {
crc_errors = 0;
- battery = AltosRecord.MISSING;
+ battery = AltosLib.MISSING;
}
}
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
import java.io.*;
-import java.text.ParseException;
-import java.util.concurrent.LinkedBlockingQueue;
+import java.text.*;
+import java.util.concurrent.*;
/*
* This creates a thread to capture telemetry data and write it to
LinkedBlockingQueue<String> pending_queue;
int serial;
int flight;
+ int receiver_serial;
FileWriter log_file;
Thread log_thread;
AltosFile file;
+ AltosLink link;
private void close_log_file() {
if (log_file != null) {
return file;
}
- boolean open (AltosRecord telem) throws IOException {
- AltosFile a = new AltosFile(telem);
+ boolean open (AltosState state) throws IOException, InterruptedException {
+ AltosFile a = new AltosFile(state);
log_file = new FileWriter(a, true);
if (log_file != null) {
while (!pending_queue.isEmpty()) {
- try {
- String s = pending_queue.take();
- log_file.write(s);
- log_file.write('\n');
- } catch (InterruptedException ie) {
- }
+ String s = pending_queue.take();
+ log_file.write(s);
+ log_file.write('\n');
}
log_file.flush();
file = a;
public void run () {
try {
- AltosRecord previous = null;
+ AltosState state = new AltosState();
+ AltosConfigData receiver_config = link.config_data();
+ state.set_receiver_serial(receiver_config.serial);
for (;;) {
AltosLine line = input_queue.take();
if (line.line == null)
continue;
try {
- AltosRecord telem = AltosTelemetry.parse(line.line, previous);
- if ((telem.seen & AltosRecord.seen_flight) != 0 &&
- (telem.serial != serial || telem.flight != flight || log_file == null))
+ AltosTelemetry telem = AltosTelemetry.parse(line.line);
+ state = state.clone();
+ telem.update_state(state);
+ if (state.serial != serial || state.flight != flight || log_file == null)
{
close_log_file();
- serial = telem.serial;
- flight = telem.flight;
- open(telem);
+ serial = state.serial;
+ flight = state.flight;
+ if (state.serial != AltosLib.MISSING && state.flight != AltosLib.MISSING)
+ open(state);
}
- previous = telem;
} catch (ParseException pe) {
} catch (AltosCRCException ce) {
}
pending_queue.put(line.line);
}
} catch (InterruptedException ie) {
+ } catch (TimeoutException te) {
} catch (IOException ie) {
}
close();
link.add_monitor(input_queue);
serial = -1;
flight = -1;
+ this.link = link;
log_file = null;
log_thread = new Thread(this);
log_thread.start();
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
-public class AltosMag {
+import java.util.concurrent.*;
+
+public class AltosMag implements Cloneable {
public int x;
public int y;
public int z;
+
+ public boolean parse_string(String line) {
+// if (line.startsWith("Syntax error")) {
+// x = y = z = 0;
+// return true;
+// }
+
+ if (!line.startsWith("X:"))
+ return false;
+
+ String[] items = line.split("\\s+");
+
+ if (items.length >= 6) {
+ x = Integer.parseInt(items[1]);
+ y = Integer.parseInt(items[3]);
+ z = Integer.parseInt(items[5]);
+ }
+ return true;
+ }
+
+ public AltosMag clone() {
+ AltosMag n = new AltosMag();
+
+ n.x = x;
+ n.y = y;
+ n.z = z;
+ return n;
+ }
+
+ public AltosMag() {
+ x = AltosLib.MISSING;
+ y = AltosLib.MISSING;
+ z = AltosLib.MISSING;
+ }
+
+ static public void update_state(AltosState state, AltosLink link, AltosConfigData config_data) throws InterruptedException {
+ try {
+ AltosMag mag = new AltosMag(link);
+
+ if (mag != null)
+ state.set_mag(mag);
+ } catch (TimeoutException te) {
+ }
+ }
+
+ public AltosMag(AltosLink link) throws InterruptedException, TimeoutException {
+ this();
+ link.printf("M\n");
+ for (;;) {
+ String line = link.get_reply_no_dialog(5000);
+ if (line == null) {
+ throw new TimeoutException();
+ }
+ if (parse_string(line))
+ break;
+ }
+ }
}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+import java.util.concurrent.*;
+
+public class AltosMma655x implements Cloneable {
+
+ int accel;
+
+ public boolean parse_line(String line) {
+ String[] items = line.split("\\s+");
+ if (line.startsWith("MMA655X value:")) {
+ if (items.length >= 3)
+ accel = Integer.parseInt(items[1]);
+ } else
+ return false;
+ return true;
+ }
+
+ public AltosMma655x() {
+ accel = AltosLib.MISSING;
+ }
+
+ public AltosMma655x clone() {
+ AltosMma655x n = new AltosMma655x();
+
+ n.accel = accel;
+ return n;
+ }
+
+ static public void update_state(AltosState state, AltosLink link, AltosConfigData config_data) throws InterruptedException {
+ try {
+ AltosMma655x mma655x = new AltosMma655x(link);
+
+ if (mma655x != null)
+ state.set_accel(mma655x.accel);
+ } catch (TimeoutException te) {
+ }
+ }
+
+ public AltosMma655x(AltosLink link) throws InterruptedException, TimeoutException {
+ this();
+ link.printf("A\n");
+ for (;;) {
+ String line = link.get_reply_no_dialog(5000);
+ if (line == null)
+ throw new TimeoutException();
+ if (!parse_line(line))
+ break;
+ }
+ }
+}
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
+
+import java.util.concurrent.*;
public class AltosMs5607 {
public int reserved;
public boolean parse_line(String line) {
String[] items = line.split("\\s+");
if (line.startsWith("Pressure:")) {
- if (items.length >= 2)
+ if (items.length >= 2) {
raw_pres = Integer.parseInt(items[1]);
+ }
} else if (line.startsWith("Temperature:")) {
if (items.length >= 2)
raw_temp = Integer.parseInt(items[1]);
if (items.length >= 3)
reserved = Integer.parseInt(items[2]);
} else if (line.startsWith("ms5607 sens:")) {
- if (items.length >= 3)
+ if (items.length >= 3) {
sens = Integer.parseInt(items[2]);
+ }
} else if (line.startsWith("ms5607 off:")) {
if (items.length >= 3)
off = Integer.parseInt(items[2]);
} else if (line.startsWith("ms5607 crc:")) {
if (items.length >= 3)
crc = Integer.parseInt(items[2]);
- } else if (line.startsWith("Altitude"))
+ } else if (line.startsWith("Altitude:")) {
return false;
+ }
return true;
}
+ static public void update_state(AltosState state, AltosLink link, AltosConfigData config_data) throws InterruptedException {
+ try {
+ AltosMs5607 ms5607 = new AltosMs5607(link);
+
+ if (ms5607 != null) {
+ state.set_ms5607(ms5607);
+ return;
+ }
+ } catch (TimeoutException te) {
+ }
+ }
+
public AltosMs5607() {
- raw_pres = AltosRecord.MISSING;
- raw_temp = AltosRecord.MISSING;
- pa = AltosRecord.MISSING;
- cc = AltosRecord.MISSING;
+ raw_pres = AltosLib.MISSING;
+ raw_temp = AltosLib.MISSING;
+ pa = AltosLib.MISSING;
+ cc = AltosLib.MISSING;
+ }
+
+ public AltosMs5607 (AltosLink link) throws InterruptedException, TimeoutException {
+ this();
+ link.printf("c s\nB\n");
+ for (;;) {
+ String line = link.get_reply_no_dialog(5000);
+ if (line == null) {
+ throw new TimeoutException();
+ }
+ if (!parse_line(line)) {
+ break;
+ }
+ }
+ convert();
}
}
+++ /dev/null
-/*
- * Copyright © 2012 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-package org.altusmetrum.altoslib_1;
-
-import java.util.concurrent.TimeoutException;
-
-class AltosMs5607Query extends AltosMs5607 {
- public AltosMs5607Query (AltosLink link) throws InterruptedException, TimeoutException {
- link.printf("v\nB\n");
- for (;;) {
- String line = link.get_reply_no_dialog(5000);
- if (line == null) {
- throw new TimeoutException();
- }
- if (!parse_line(line))
- break;
- }
- convert();
- }
-}
-
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+public class AltosNoSymbol extends Exception {
+ public AltosNoSymbol(String name) {
+ super(String.format("No such symbol \"%s\"", name));
+ }
+}
+++ /dev/null
-/*
- * Copyright © 2010 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-package org.altusmetrum.altoslib_1;
-
-import java.text.ParseException;
-
-/*
- * AltosRecords with an index field so they can be sorted by tick while preserving
- * the original ordering for elements with matching ticks
- */
-class AltosOrderedMegaRecord extends AltosEepromMega implements Comparable<AltosOrderedMegaRecord> {
-
- public int index;
-
- public AltosOrderedMegaRecord(String line, int in_index, int prev_tick, boolean prev_tick_valid)
- throws ParseException {
- super(line);
- if (prev_tick_valid) {
- tick |= (prev_tick & ~0xffff);
- if (tick < prev_tick) {
- if (prev_tick - tick > 0x8000)
- tick += 0x10000;
- } else {
- if (tick - prev_tick > 0x8000)
- tick -= 0x10000;
- }
- }
- index = in_index;
- }
-
- public int compareTo(AltosOrderedMegaRecord o) {
- int tick_diff = tick - o.tick;
- if (tick_diff != 0)
- return tick_diff;
- return index - o.index;
- }
-}
+++ /dev/null
-/*
- * Copyright © 2010 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-package org.altusmetrum.altoslib_1;
-
-import java.text.ParseException;
-
-/*
- * AltosRecords with an index field so they can be sorted by tick while preserving
- * the original ordering for elements with matching ticks
- */
-class AltosOrderedRecord extends AltosEepromRecord implements Comparable<AltosOrderedRecord> {
-
- public int index;
-
- public AltosOrderedRecord(String line, int in_index, int prev_tick, boolean prev_tick_valid)
- throws ParseException {
- super(line);
- if (prev_tick_valid) {
- tick |= (prev_tick & ~0xffff);
- if (tick < prev_tick) {
- if (prev_tick - tick > 0x8000)
- tick += 0x10000;
- } else {
- if (tick - prev_tick > 0x8000)
- tick -= 0x10000;
- }
- }
- index = in_index;
- }
-
- public AltosOrderedRecord(int in_cmd, int in_tick, int in_a, int in_b, int in_index) {
- super(in_cmd, in_tick, in_a, in_b);
- index = in_index;
- }
-
- public String toString() {
- return String.format("%d.%d %04x %04x %04x",
- cmd, index, tick, a, b);
- }
-
- public int compareTo(AltosOrderedRecord o) {
- int tick_diff = tick - o.tick;
- if (tick_diff != 0)
- return tick_diff;
- return index - o.index;
- }
-}
-
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
import java.text.*;
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
import java.io.*;
import java.util.*;
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
import java.io.File;
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+import java.io.*;
+
+public abstract class AltosProgrammer {
+
+ abstract public void flash();
+
+ abstract public void close();
+
+ abstract public void abort();
+
+ abstract public AltosRomconfig romconfig() throws InterruptedException;
+
+ abstract public void set_romconfig(AltosRomconfig config);
+}
\ No newline at end of file
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
import java.util.*;
import java.text.*;
public static final int pyro_accel_greater = 0x00000002;
public static final String pyro_accel_less_string = "a<";
public static final String pyro_accel_greater_string = "a>";
- public static final String pyro_accel_less_name = "Acceleration less than (m/s²)";
- public static final String pyro_accel_greater_name = "Acceleration greater than (m/s²)";
+ public static final String pyro_accel_less_name = "Acceleration less than";
+ public static final String pyro_accel_greater_name = "Acceleration greater than";
public static final double pyro_accel_scale = 16.0;
public static final int pyro_speed_less = 0x00000004;
public static final int pyro_speed_greater = 0x00000008;
public static final String pyro_speed_less_string = "s<";
public static final String pyro_speed_greater_string = "s>";
- public static final String pyro_speed_less_name = "Speed less than (m/s)";
- public static final String pyro_speed_greater_name = "Speed greater than (m/s)";
+ public static final String pyro_speed_less_name = "Speed less than";
+ public static final String pyro_speed_greater_name = "Speed greater than";
public static final double pyro_speed_scale = 16.0;
public static final int pyro_height_less = 0x00000010;
public static final int pyro_height_greater = 0x00000020;
public static final String pyro_height_less_string = "h<";
public static final String pyro_height_greater_string = "h>";
- public static final String pyro_height_less_name = "Height less than (m)";
- public static final String pyro_height_greater_name = "Height greater than (m)";
+ public static final String pyro_height_less_name = "Height less than";
+ public static final String pyro_height_greater_name = "Height greater than";
public static final double pyro_height_scale = 1.0;
public static final int pyro_orient_less = 0x00000040;
private static HashMap<Integer,String> pyro_to_name = new HashMap<Integer,String>();
+ private static HashMap<Integer,AltosUnits> pyro_to_units = new HashMap<Integer,AltosUnits>();
+
private static HashMap<Integer,Double> pyro_to_scale = new HashMap<Integer,Double>();
- private static void insert_map(int flag, String string, String name, double scale) {
+ private static void insert_map(int flag, String string, String name, AltosUnits units, double scale) {
string_to_pyro.put(string, flag);
pyro_to_string.put(flag, string);
pyro_to_name.put(flag, name);
+ if (units != null)
+ pyro_to_units.put(flag, units);
pyro_to_scale.put(flag, scale);
}
}
public static String pyro_to_name(int flag) {
- if (pyro_to_name.containsKey(flag))
- return pyro_to_name.get(flag);
+ String name;
+ AltosUnits units = null;
+ if (!pyro_to_name.containsKey(flag))
+ return null;
+
+ name = pyro_to_name.get(flag);
+ if (pyro_to_units.containsKey(flag))
+ units = pyro_to_units.get(flag);
+ if (units == null)
+ return name;
+ return String.format ("%s (%s)", name, units.show_units());
+ }
+
+ public static AltosUnits pyro_to_units(int flag) {
+ if (pyro_to_units.containsKey(flag))
+ return pyro_to_units.get(flag);
return null;
}
}
private static void initialize_maps() {
- insert_map(pyro_accel_less, pyro_accel_less_string, pyro_accel_less_name, pyro_accel_scale);
- insert_map(pyro_accel_greater, pyro_accel_greater_string, pyro_accel_greater_name, pyro_accel_scale);
+ insert_map(pyro_accel_less, pyro_accel_less_string, pyro_accel_less_name, AltosConvert.accel, pyro_accel_scale);
+ insert_map(pyro_accel_greater, pyro_accel_greater_string, pyro_accel_greater_name, AltosConvert.accel, pyro_accel_scale);
- insert_map(pyro_speed_less, pyro_speed_less_string, pyro_speed_less_name, pyro_speed_scale);
- insert_map(pyro_speed_greater, pyro_speed_greater_string, pyro_speed_greater_name, pyro_speed_scale);
+ insert_map(pyro_speed_less, pyro_speed_less_string, pyro_speed_less_name, AltosConvert.speed, pyro_speed_scale);
+ insert_map(pyro_speed_greater, pyro_speed_greater_string, pyro_speed_greater_name, AltosConvert.speed, pyro_speed_scale);
- insert_map(pyro_height_less, pyro_height_less_string, pyro_height_less_name, pyro_height_scale);
- insert_map(pyro_height_greater, pyro_height_greater_string, pyro_height_greater_name, pyro_height_scale);
+ insert_map(pyro_height_less, pyro_height_less_string, pyro_height_less_name, AltosConvert.height, pyro_height_scale);
+ insert_map(pyro_height_greater, pyro_height_greater_string, pyro_height_greater_name, AltosConvert.height, pyro_height_scale);
- insert_map(pyro_orient_less, pyro_orient_less_string, pyro_orient_less_name, pyro_orient_scale);
- insert_map(pyro_orient_greater, pyro_orient_greater_string, pyro_orient_greater_name, pyro_orient_scale);
+ insert_map(pyro_orient_less, pyro_orient_less_string, pyro_orient_less_name, null, pyro_orient_scale);
+ insert_map(pyro_orient_greater, pyro_orient_greater_string, pyro_orient_greater_name, null, pyro_orient_scale);
- insert_map(pyro_time_less, pyro_time_less_string, pyro_time_less_name, pyro_time_scale);
- insert_map(pyro_time_greater, pyro_time_greater_string, pyro_time_greater_name, pyro_time_scale);
+ insert_map(pyro_time_less, pyro_time_less_string, pyro_time_less_name, null, pyro_time_scale);
+ insert_map(pyro_time_greater, pyro_time_greater_string, pyro_time_greater_name, null, pyro_time_scale);
- insert_map(pyro_ascending, pyro_ascending_string, pyro_ascending_name, 1.0);
- insert_map(pyro_descending, pyro_descending_string, pyro_descending_name, 1.0);
+ insert_map(pyro_ascending, pyro_ascending_string, pyro_ascending_name, null, 1.0);
+ insert_map(pyro_descending, pyro_descending_string, pyro_descending_name, null, 1.0);
- insert_map(pyro_after_motor, pyro_after_motor_string, pyro_after_motor_name, 1.0);
- insert_map(pyro_delay, pyro_delay_string, pyro_delay_name, pyro_delay_scale);
+ insert_map(pyro_after_motor, pyro_after_motor_string, pyro_after_motor_name, null, 1.0);
+ insert_map(pyro_delay, pyro_delay_string, pyro_delay_name, null, pyro_delay_scale);
- insert_map(pyro_state_less, pyro_state_less_string, pyro_state_less_name, 1.0);
- insert_map(pyro_state_greater_or_equal, pyro_state_greater_or_equal_string, pyro_state_greater_or_equal_name, 1.0);
+ insert_map(pyro_state_less, pyro_state_less_string, pyro_state_less_name, null, 1.0);
+ insert_map(pyro_state_greater_or_equal, pyro_state_greater_or_equal_string, pyro_state_greater_or_equal_name, null, 1.0);
}
{
+++ /dev/null
-/*
- * Copyright © 2010 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-package org.altusmetrum.altoslib_1;
-
-public class AltosRecord implements Comparable <AltosRecord>, Cloneable {
-
- public static final int seen_flight = 1;
- public static final int seen_sensor = 2;
- public static final int seen_temp_volt = 4;
- public static final int seen_deploy = 8;
- public static final int seen_gps_time = 16;
- public static final int seen_gps_lat = 32;
- public static final int seen_gps_lon = 64;
- public static final int seen_companion = 128;
-
- public int seen;
-
- public final static int MISSING = 0x7fffffff;
-
- /* Every AltosRecord implementation provides these fields */
-
- public int version;
- public String callsign;
- public int serial;
- public int flight;
- public int rssi;
- public int status;
- public int state;
- public int tick;
-
- public AltosGPS gps;
- public int gps_sequence;
-
- public double time; /* seconds since boost */
-
- public int device_type;
- public int config_major;
- public int config_minor;
- public int apogee_delay;
- public int main_deploy;
- public int flight_log_max;
- public String firmware_version;
-
- public AltosRecordCompanion companion;
-
- /* Telemetry sources have these values recorded from the flight computer */
- public double kalman_height;
- public double kalman_speed;
- public double kalman_acceleration;
-
- /*
- * Abstract methods that convert record data
- * to standard units:
- *
- * pressure: Pa
- * voltage: V
- * acceleration: m/s²
- * speed: m/s
- * height: m
- * temperature: °C
- */
-
- public double pressure() { return MISSING; }
- public double ground_pressure() { return MISSING; }
- public double acceleration() { return MISSING; }
-
- public double altitude() {
- double p = pressure();
-
- if (p == MISSING)
- return MISSING;
- return AltosConvert.pressure_to_altitude(p);
- }
-
- public double ground_altitude() {
- double p = ground_pressure();
-
- if (p == MISSING)
- return MISSING;
- return AltosConvert.pressure_to_altitude(p);
- }
-
- public double height() {
- double g = ground_altitude();
- double a = altitude();
-
- if (g == MISSING)
- return MISSING;
- if (a == MISSING)
- return MISSING;
- return a - g;
- }
-
- public double battery_voltage() { return MISSING; }
-
- public double main_voltage() { return MISSING; }
-
- public double drogue_voltage() { return MISSING; }
-
- public double temperature() { return MISSING; }
-
- public AltosIMU imu() { return null; }
-
- public AltosMag mag() { return null; }
-
- public String state() {
- return AltosLib.state_name(state);
- }
-
- public int compareTo(AltosRecord o) {
- return tick - o.tick;
- }
-
- public AltosRecord clone() {
- AltosRecord n = new AltosRecord();
- n.copy(this);
- return n;
- }
-
- public void copy(AltosRecord old) {
- seen = old.seen;
- version = old.version;
- callsign = old.callsign;
- serial = old.serial;
- flight = old.flight;
- rssi = old.rssi;
- status = old.status;
- state = old.state;
- tick = old.tick;
- gps = new AltosGPS(old.gps);
- gps_sequence = old.gps_sequence;
- companion = old.companion;
- kalman_acceleration = old.kalman_acceleration;
- kalman_speed = old.kalman_speed;
- kalman_height = old.kalman_height;
- }
-
- public AltosRecord() {
- seen = 0;
- version = 0;
- callsign = "N0CALL";
- serial = MISSING;
- flight = MISSING;
- rssi = 0;
- status = 0;
- state = AltosLib.ao_flight_startup;
- tick = 0;
- gps = null;
- gps_sequence = 0;
- companion = null;
-
- kalman_acceleration = MISSING;
- kalman_speed = MISSING;
- kalman_height = MISSING;
- }
-}
+++ /dev/null
-/*
- * Copyright © 2011 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-package org.altusmetrum.altoslib_1;
-
-public class AltosRecordCompanion {
- public final static int board_id_telescience = 0x0a;
- public final static int MAX_CHANNELS = 12;
-
- public int tick;
- public int board_id;
- public int update_period;
- public int channels;
- public int[] companion_data;
-
- public AltosRecordCompanion(int in_channels) {
- channels = in_channels;
- if (channels < 0)
- channels = 0;
- if (channels > MAX_CHANNELS)
- channels = MAX_CHANNELS;
- companion_data = new int[channels];
- }
-}
+++ /dev/null
-/*
- * Copyright © 2010 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-package org.altusmetrum.altoslib_1;
-
-import java.io.*;
-import java.util.*;
-
-public abstract class AltosRecordIterable implements Iterable<AltosRecord> {
- public abstract Iterator<AltosRecord> iterator();
- public void write_comments(PrintStream out) { }
- public boolean has_accel() { return false; }
- public boolean has_gps() { return false; }
- public boolean has_ignite() { return false; };
-}
+++ /dev/null
-/*
- * Copyright © 2012 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-package org.altusmetrum.altoslib_1;
-
-public class AltosRecordMM extends AltosRecord {
-
- /* Sensor values */
- public int accel;
- public int pres;
- public int temp;
-
- public int v_batt;
- public int v_pyro;
- public int sense[];
-
- public int ground_accel;
- public int ground_pres;
- public int accel_plus_g;
- public int accel_minus_g;
-
- public int flight_accel;
- public int flight_vel;
- public int flight_pres;
-
- public final static int num_sense = 6;
-
- public AltosIMU imu;
- public AltosMag mag;
-
- static double adc(int raw) {
- return raw / 4095.0;
- }
-
- public double pressure() {
- if (pres != MISSING)
- return pres;
- return MISSING;
- }
-
- public double ground_pressure() {
- if (ground_pres != MISSING)
- return ground_pres;
- return MISSING;
- }
-
- public double battery_voltage() {
- if (v_batt != MISSING)
- return 3.3 * adc(v_batt) * (15.0 + 27.0) / 27.0;
- return MISSING;
- }
-
- static double pyro(int raw) {
- if (raw != MISSING)
- return 3.3 * adc(raw) * (100.0 + 27.0) / 27.0;
- return MISSING;
- }
-
- public double main_voltage() {
- return pyro(sense[5]);
- }
-
- public double drogue_voltage() {
- return pyro(sense[4]);
- }
-
- public double temperature() {
- if (temp != MISSING)
- return temp / 100.0;
- return MISSING;
- }
-
- public AltosIMU imu() { return imu; }
-
- public AltosMag mag() { return mag; }
-
- double accel_counts_per_mss() {
- double counts_per_g = Math.abs(accel_minus_g - accel_plus_g) / 2;
-
- return counts_per_g / 9.80665;
- }
-
- public double acceleration() {
- if (ground_accel == MISSING || accel == MISSING)
- return MISSING;
-
- if (accel_minus_g == MISSING || accel_plus_g == MISSING)
- return MISSING;
-
- return (ground_accel - accel) / accel_counts_per_mss();
- }
-
- public void copy (AltosRecordMM old) {
- super.copy(old);
-
- accel = old.accel;
- pres = old.pres;
- temp = old.temp;
-
- v_batt = old.v_batt;
- v_pyro = old.v_pyro;
- sense = new int[num_sense];
-
- for (int i = 0; i < num_sense; i++)
- sense[i] = old.sense[i];
-
- ground_accel = old.ground_accel;
- ground_pres = old.ground_pres;
- accel_plus_g = old.accel_plus_g;
- accel_minus_g = old.accel_minus_g;
-
- flight_accel = old.flight_accel;
- flight_vel = old.flight_vel;
- flight_pres = old.flight_pres;
-
- imu = old.imu;
- mag = old.mag;
- }
-
-
-
- public AltosRecordMM clone() {
- return new AltosRecordMM(this);
- }
-
- void make_missing() {
-
- accel = MISSING;
- pres = MISSING;
- temp = MISSING;
-
- v_batt = MISSING;
- v_pyro = MISSING;
- sense = new int[num_sense];
- for (int i = 0; i < num_sense; i++)
- sense[i] = MISSING;
-
- ground_accel = MISSING;
- ground_pres = MISSING;
- accel_plus_g = MISSING;
- accel_minus_g = MISSING;
-
- flight_accel = 0;
- flight_vel = 0;
- flight_pres = 0;
-
- imu = new AltosIMU();
- mag = new AltosMag();
- }
-
- public AltosRecordMM(AltosRecord old) {
- super.copy(old);
- make_missing();
- }
-
- public AltosRecordMM(AltosRecordMM old) {
- copy(old);
- }
-
- public AltosRecordMM() {
- super();
- make_missing();
- }
-}
+++ /dev/null
-/*
- * Copyright © 2012 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-package org.altusmetrum.altoslib_1;
-
-public class AltosRecordNone extends AltosRecord {
-
- public double pressure() { return MISSING; }
- public double ground_pressure() { return MISSING; }
- public double temperature() { return MISSING; }
- public double acceleration() { return MISSING; }
-
- public AltosRecordNone(AltosRecord old) {
- super.copy(old);
- }
-
- public AltosRecordNone clone() {
- return new AltosRecordNone(this);
- }
-
- public AltosRecordNone() {
- super();
- }
-}
+++ /dev/null
-/*
- * Copyright © 2012 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-package org.altusmetrum.altoslib_1;
-
-public class AltosRecordTM extends AltosRecord {
-
- /* Sensor values */
- public int accel;
- public int pres;
- public int temp;
- public int batt;
- public int drogue;
- public int main;
-
- public int ground_accel;
- public int ground_pres;
- public int accel_plus_g;
- public int accel_minus_g;
-
- public int flight_accel;
- public int flight_vel;
- public int flight_pres;
-
- /*
- * Values for our MP3H6115A pressure sensor
- *
- * From the data sheet:
- *
- * Pressure range: 15-115 kPa
- * Voltage at 115kPa: 2.82
- * Output scale: 27mV/kPa
- *
- *
- * 27 mV/kPa * 2047 / 3300 counts/mV = 16.75 counts/kPa
- * 2.82V * 2047 / 3.3 counts/V = 1749 counts/115 kPa
- */
-
- static final double counts_per_kPa = 27 * 2047 / 3300;
- static final double counts_at_101_3kPa = 1674.0;
-
- static double
- barometer_to_pressure(double count)
- {
- return ((count / 16.0) / 2047.0 + 0.095) / 0.009 * 1000.0;
- }
-
- public double pressure() {
- if (pres == MISSING)
- return MISSING;
- return barometer_to_pressure(pres);
- }
-
- public double ground_pressure() {
- if (ground_pres == MISSING)
- return MISSING;
- return barometer_to_pressure(ground_pres);
- }
-
- public double battery_voltage() {
- if (batt == MISSING)
- return MISSING;
- return AltosConvert.cc_battery_to_voltage(batt);
- }
-
- public double main_voltage() {
- if (main == MISSING)
- return MISSING;
- return AltosConvert.cc_ignitor_to_voltage(main);
- }
-
- public double drogue_voltage() {
- if (drogue == MISSING)
- return MISSING;
- return AltosConvert.cc_ignitor_to_voltage(drogue);
- }
-
- /* Value for the CC1111 built-in temperature sensor
- * Output voltage at 0°C = 0.755V
- * Coefficient = 0.00247V/°C
- * Reference voltage = 1.25V
- *
- * temp = ((value / 32767) * 1.25 - 0.755) / 0.00247
- * = (value - 19791.268) / 32768 * 1.25 / 0.00247
- */
-
- static double
- thermometer_to_temperature(double thermo)
- {
- return (thermo - 19791.268) / 32728.0 * 1.25 / 0.00247;
- }
-
- public double temperature() {
- if (temp == MISSING)
- return MISSING;
- return thermometer_to_temperature(temp);
- }
-
- double accel_counts_per_mss() {
- double counts_per_g = Math.abs(accel_minus_g - accel_plus_g) / 2;
-
- return counts_per_g / 9.80665;
- }
-
- public double acceleration() {
- if (ground_accel == MISSING || accel == MISSING)
- return MISSING;
- return (ground_accel - accel) / accel_counts_per_mss();
- }
-
- public void copy(AltosRecordTM old) {
- super.copy(old);
-
- version = old.version;
- callsign = old.callsign;
- serial = old.serial;
- flight = old.flight;
- rssi = old.rssi;
- status = old.status;
- state = old.state;
- tick = old.tick;
- accel = old.accel;
- pres = old.pres;
- temp = old.temp;
- batt = old.batt;
- drogue = old.drogue;
- main = old.main;
- flight_accel = old.flight_accel;
- ground_accel = old.ground_accel;
- flight_vel = old.flight_vel;
- flight_pres = old.flight_pres;
- ground_pres = old.ground_pres;
- accel_plus_g = old.accel_plus_g;
- accel_minus_g = old.accel_minus_g;
- }
-
- public AltosRecordTM clone() {
- return new AltosRecordTM(this);
- }
-
- void make_missing() {
- accel = MISSING;
- pres = MISSING;
- temp = MISSING;
- batt = MISSING;
- drogue = MISSING;
- main = MISSING;
-
- flight_accel = MISSING;
- flight_vel = MISSING;
- flight_pres = MISSING;
-
- ground_accel = MISSING;
- ground_pres = MISSING;
- accel_plus_g = MISSING;
- accel_minus_g = MISSING;
- }
-
- public AltosRecordTM(AltosRecord old) {
- super.copy(old);
- make_missing();
- }
-
- public AltosRecordTM(AltosRecordTM old) {
- copy(old);
- }
-
- public AltosRecordTM() {
- super();
- make_missing();
- }
-}
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
import java.io.*;
import java.util.*;
*/
public class AltosReplayReader extends AltosFlightReader {
- Iterator<AltosRecord> iterator;
+ Iterator<AltosState> iterator;
File file;
- public AltosRecord read() {
+ public AltosState read() {
if (iterator.hasNext())
return iterator.next();
return null;
/* Make it run in realtime after the rocket leaves the pad */
if (state.state > AltosLib.ao_flight_pad)
Thread.sleep((int) (Math.min(state.time_change,10) * 1000));
+ state.set_received_time(System.currentTimeMillis());
}
public File backing_file() { return file; }
- public AltosReplayReader(Iterator<AltosRecord> in_iterator, File in_file) {
+ public AltosReplayReader(Iterator<AltosState> in_iterator, File in_file) {
iterator = in_iterator;
file = in_file;
name = file.getName();
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
import java.io.*;
public int serial_number;
public int radio_calibration;
- static int get_int(byte[] bytes, int start, int len) {
+ static private int find_offset(AltosHexfile hexfile, String name, int len) throws AltosNoSymbol {
+ AltosHexsym symbol = hexfile.lookup_symbol(name);
+ if (symbol == null)
+ throw new AltosNoSymbol(name);
+ int offset = (int) symbol.address - hexfile.address;
+ if (offset < 0 || hexfile.data.length < offset + len)
+ throw new AltosNoSymbol(name);
+ return offset;
+ }
+
+ static int get_int(AltosHexfile hexfile, String name, int len) throws AltosNoSymbol {
+ byte[] bytes = hexfile.data;
+ int start = find_offset(hexfile, name, len);
+
int v = 0;
int o = 0;
while (len > 0) {
return v;
}
- static void put_int(int value, byte[] bytes, int start, int len) {
+ static void put_int(int value, AltosHexfile hexfile, String name, int len) throws AltosNoSymbol, IOException {
+ byte[] bytes = hexfile.data;
+ int start = find_offset(hexfile, name, len);
+
while (len > 0) {
bytes[start] = (byte) (value & 0xff);
start++;
}
}
- static void put_string(String value, byte[] bytes, int start) {
+ static void put_string(String value, AltosHexfile hexfile, String name) throws AltosNoSymbol {
+ byte[] bytes = hexfile.data;
+ int start = find_offset(hexfile, name, value.length());
+
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;
+ static void put_usb_serial(int value, AltosHexfile hexfile, String name) throws AltosNoSymbol {
+ byte[] bytes = hexfile.data;
+ int start = find_offset(hexfile, name, 2);
+
int string_num = 0;
- while (offset < bytes.length && bytes[offset] != 0) {
- if (bytes[offset + 1] == AO_USB_DESC_STRING) {
+ while (start < bytes.length && bytes[start] != 0) {
+ if (bytes[start + 1] == AO_USB_DESC_STRING) {
++string_num;
if (string_num == 4)
break;
}
- offset += ((int) bytes[offset]) & 0xff;
+ start += ((int) bytes[start]) & 0xff;
}
- if (offset >= bytes.length || bytes[offset] == 0)
- return;
- int len = ((((int) bytes[offset]) & 0xff) - 2) / 2;
+ if (start >= bytes.length || bytes[start] == 0)
+ throw new AltosNoSymbol(name);
+
+ int len = ((((int) bytes[start]) & 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;
- }
+ if (s.length() != len)
+ throw new AltosNoSymbol(String.format("weird usb length issue %s isn't %d\n", s, len));
+
for (int i = 0; i < len; i++) {
- bytes[offset + 2 + i*2] = (byte) s.charAt(i);
- bytes[offset + 2 + i*2+1] = 0;
+ bytes[start + 2 + i*2] = (byte) s.charAt(i);
+ bytes[start + 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;
+ final static String ao_romconfig_version = "ao_romconfig_version";
+ final static String ao_romconfig_check = "ao_romconfig_check";
+ final static String ao_serial_number = "ao_serial_number";
+ final static String ao_radio_cal = "ao_radio_cal";
+ final static String ao_usb_descriptors = "ao_usb_descriptors";
+
+ public AltosRomconfig(AltosHexfile hexfile) {
+ try {
+ version = get_int(hexfile, ao_romconfig_version, 2);
+ check = get_int(hexfile, ao_romconfig_check, 2);
+ if (check == (~version & 0xffff)) {
+ switch (version) {
+ case 2:
+ case 1:
+ serial_number = get_int(hexfile, ao_serial_number, 2);
+ try {
+ radio_calibration = get_int(hexfile, ao_radio_cal, 4);
+ } catch (AltosNoSymbol missing) {
+ radio_calibration = 0;
+ }
+ valid = true;
+ break;
+ }
}
+ } catch (AltosNoSymbol missing) {
+ valid = false;
}
}
- public AltosRomconfig(AltosHexfile hexfile) {
- this(hexfile.data, 0xa0 - hexfile.address);
+ private final static String[] fetch_names = {
+ ao_romconfig_version,
+ ao_romconfig_check,
+ ao_serial_number,
+ ao_radio_cal
+ };
+
+ private final static String[] required_names = {
+ ao_romconfig_version,
+ ao_romconfig_check,
+ ao_serial_number
+ };
+
+ private static boolean name_required(String name) {
+ for (String required : required_names)
+ if (name.equals(required))
+ return true;
+ return false;
}
- public void write(byte[] bytes, int offset) throws IOException {
+ public static int fetch_base(AltosHexfile hexfile) throws AltosNoSymbol {
+ int base = 0x7fffffff;
+ for (String name : fetch_names) {
+ try {
+ int addr = find_offset(hexfile, name, 2) + hexfile.address;
+ if (addr < base)
+ base = addr;
+ } catch (AltosNoSymbol ns) {
+ if (name_required(name))
+ throw (ns);
+ }
+ }
+ return base;
+ }
+
+ public static int fetch_bounds(AltosHexfile hexfile) throws AltosNoSymbol {
+ int bounds = 0;
+ for (String name : fetch_names) {
+ try {
+ int addr = find_offset(hexfile, name, 2) + hexfile.address;
+ if (addr > bounds)
+ bounds = addr;
+ } catch (AltosNoSymbol ns) {
+ if (name_required(name))
+ throw (ns);
+ }
+ }
+ return bounds + 2;
+ }
+
+ public void write (AltosHexfile hexfile) 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);
+ AltosRomconfig existing = new AltosRomconfig(hexfile);
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;
+ try {
+ switch (existing.version) {
+ case 2:
+ try {
+ put_usb_serial(serial_number, hexfile, ao_usb_descriptors);
+ } catch (AltosNoSymbol missing) {
+ }
+ /* fall through ... */
+ case 1:
+ put_int(serial_number, hexfile, ao_serial_number, 2);
+ try {
+ put_int(radio_calibration, hexfile, ao_radio_cal, 4);
+ } catch (AltosNoSymbol missing) {
+ }
+ break;
+ }
+ } catch (AltosNoSymbol missing) {
+ throw new IOException(missing.getMessage());
}
- }
- public void write (AltosHexfile hexfile) throws IOException {
- write(hexfile.data, 0xa0 - hexfile.address);
AltosRomconfig check = new AltosRomconfig(hexfile);
- if (!check.valid())
+ if (!check.valid)
throw new IOException("writing new rom config failed\n");
}
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+import java.io.*;
+
+public class AltosSelfFlash extends AltosProgrammer {
+ File file;
+ FileInputStream input;
+ AltosHexfile image;
+ AltosLink link;
+ boolean aborted;
+ AltosFlashListener listener;
+ AltosRomconfig rom_config;
+
+ void action(String s, int percent) {
+ if (listener != null && !aborted)
+ listener.position(s, percent);
+ }
+
+ void action(int part, int total) {
+ int percent = 100 * part / total;
+ action(String.format("%d/%d (%d%%)",
+ part, total, percent),
+ percent);
+ }
+
+ byte[] read_memory(long addr, int len) throws InterruptedException, IOException {
+ int b;
+ byte[] data = new byte[len];
+
+ for (int offset = 0; offset < len; offset += 0x100) {
+ link.printf("R %x\n", addr + offset);
+ byte[] reply = link.get_binary_reply(5000, 0x100);
+
+ if (reply == null)
+ throw new IOException("Read device memory timeout");
+ for (b = 0; b < len; b++)
+ data[b+offset] = reply[b];
+ }
+ return data;
+ }
+
+ void write_memory(long addr, byte[] data, int start, int len) {
+ int b;
+ link.printf("W %x\n", addr);
+ link.flush_output();
+ for (b = 0; b < len; b++)
+ link.putchar(data[start + b]);
+ for (; b < 0x100; b++)
+ link.putchar((byte) 0xff);
+ }
+
+ void reboot() {
+ link.printf("a\n");
+ link.flush_output();
+ }
+
+ public void flash() {
+ try {
+ if (!check_rom_config())
+ throw new IOException("Invalid rom config settings");
+
+ /*
+ * Store desired config values into image
+ */
+ rom_config.write(image);
+
+ int remain = image.data.length;
+ long 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 > 0x100)
+ this_time = 0x100;
+
+ if (link != null) {
+ /* write the data */
+ write_memory(flash_addr, image.data, image_start, this_time);
+
+ byte[] check = read_memory(flash_addr, this_time);
+ for (int i = 0; i < this_time; i++)
+ if (check[i] != image.data[image_start + i])
+ throw new IOException(String.format("Flash write failed at 0x%x (%02x != %02x)",
+ image.address + image_start + i,
+ check[i], image.data[image_start + i]));
+ } else {
+ Thread.sleep(100);
+ }
+
+ remain -= this_time;
+ flash_addr += this_time;
+ image_start += this_time;
+
+ action(image.data.length - remain, image.data.length);
+ }
+ if (!aborted) {
+ action("done", 100);
+ }
+ close();
+ } catch (IOException ie) {
+ action(ie.getMessage(), -1);
+ abort();
+ } catch (InterruptedException ie) {
+ abort();
+ }
+ }
+
+ public void close() {
+ if (link != null) {
+ reboot();
+ try {
+ link.close();
+ } catch (InterruptedException ie) {
+ }
+ link = null;
+ }
+ }
+
+ synchronized public void abort() {
+ aborted = true;
+ close();
+ }
+
+ private AltosHexfile get_rom() throws InterruptedException {
+ try {
+ int base = AltosRomconfig.fetch_base(image);
+ int bounds = AltosRomconfig.fetch_bounds(image);
+ byte[] data = read_memory(base, bounds - base);
+ AltosHexfile hexfile = new AltosHexfile(data, base);
+ hexfile.add_symbols(image);
+ return hexfile;
+ } catch (AltosNoSymbol none) {
+ return null;
+ } catch (IOException ie) {
+ return null;
+ }
+
+ }
+
+ public boolean check_rom_config() throws InterruptedException {
+ if (link == null) {
+ return true;
+ }
+ if (rom_config == null) {
+ AltosHexfile hexfile = get_rom();
+ if (hexfile != null)
+ rom_config = new AltosRomconfig(hexfile);
+ }
+ return rom_config != null && rom_config.valid();
+ }
+
+ public void set_romconfig (AltosRomconfig romconfig) {
+ rom_config = romconfig;
+ }
+
+ public AltosRomconfig romconfig() throws InterruptedException {
+ if (!check_rom_config())
+ return null;
+ return rom_config;
+ }
+
+ public AltosSelfFlash(File file, AltosLink link, AltosFlashListener listener)
+ throws IOException, FileNotFoundException, InterruptedException {
+ this.file = file;
+ this.link = link;
+ this.listener = listener;
+ input = new FileInputStream(file);
+ image = new AltosHexfile(input);
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+import java.util.concurrent.TimeoutException;
+
+public class AltosSensorEMini {
+ public int tick;
+ public int apogee;
+ public int main;
+ public int batt;
+
+ static public void update_state(AltosState state, AltosLink link, AltosConfigData config_data) throws InterruptedException {
+ try {
+ AltosSensorEMini sensor_emini = new AltosSensorEMini(link);
+
+ if (sensor_emini == null)
+ return;
+ state.set_battery_voltage(AltosConvert.easy_mini_voltage(sensor_emini.batt));
+ state.set_apogee_voltage(AltosConvert.easy_mini_voltage(sensor_emini.apogee));
+ state.set_main_voltage(AltosConvert.easy_mini_voltage(sensor_emini.main));
+
+ } catch (TimeoutException te) {
+ }
+ }
+
+ public AltosSensorEMini(AltosLink link) throws InterruptedException, TimeoutException {
+ String[] items = link.adc();
+ for (int i = 0; i < items.length;) {
+ if (items[i].equals("tick:")) {
+ tick = Integer.parseInt(items[i+1]);
+ i += 2;
+ continue;
+ }
+ if (items[i].equals("apogee:")) {
+ apogee = Integer.parseInt(items[i+1]);
+ i += 2;
+ continue;
+ }
+ if (items[i].equals("main:")) {
+ main = Integer.parseInt(items[i+1]);
+ i += 2;
+ continue;
+ }
+ if (items[i].equals("batt:")) {
+ batt = Integer.parseInt(items[i+1]);
+ i += 2;
+ continue;
+ }
+ i++;
+ }
+ }
+}
+
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
import java.util.concurrent.TimeoutException;
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+import java.util.concurrent.TimeoutException;
+
+class AltosSensorMega {
+ int tick;
+ int[] sense;
+ int v_batt;
+ int v_pbatt;
+ int temp;
+
+ public AltosSensorMega() {
+ sense = new int[6];
+ }
+
+ public AltosSensorMega(AltosLink link) throws InterruptedException, TimeoutException {
+ this();
+ String[] items = link.adc();
+ for (int i = 0; i < items.length;) {
+ if (items[i].equals("tick:")) {
+ tick = Integer.parseInt(items[i+1]);
+ i += 2;
+ continue;
+ }
+ if (items[i].equals("A:")) {
+ sense[0] = Integer.parseInt(items[i+1]);
+ i += 2;
+ continue;
+ }
+ if (items[i].equals("B:")) {
+ sense[1] = Integer.parseInt(items[i+1]);
+ i += 2;
+ continue;
+ }
+ if (items[i].equals("C:")) {
+ sense[2] = Integer.parseInt(items[i+1]);
+ i += 2;
+ continue;
+ }
+ if (items[i].equals("D:")) {
+ sense[3] = Integer.parseInt(items[i+1]);
+ i += 2;
+ continue;
+ }
+ if (items[i].equals("drogue:")) {
+ sense[4] = Integer.parseInt(items[i+1]);
+ i += 2;
+ continue;
+ }
+ if (items[i].equals("main:")) {
+ sense[5] = Integer.parseInt(items[i+1]);
+ i += 2;
+ continue;
+ }
+ if (items[i].equals("batt:")) {
+ v_batt = Integer.parseInt(items[i+1]);
+ i += 2;
+ continue;
+ }
+ if (items[i].equals("pbatt:")) {
+ v_pbatt = Integer.parseInt(items[i+1]);
+ i += 2;
+ continue;
+ }
+ if (items[i].equals("temp:")) {
+ temp = Integer.parseInt(items[i+1]);
+ i += 2;
+ continue;
+ }
+ i++;
+ }
+ }
+
+ static public void update_state(AltosState state, AltosLink link, AltosConfigData config_data) throws InterruptedException {
+ try {
+ AltosSensorMega sensor_mega = new AltosSensorMega(link);
+
+ state.set_battery_voltage(AltosConvert.mega_battery_voltage(sensor_mega.v_batt));
+ state.set_apogee_voltage(AltosConvert.mega_pyro_voltage(sensor_mega.sense[4]));
+ state.set_main_voltage(AltosConvert.mega_pyro_voltage(sensor_mega.sense[5]));
+
+ double[] ignitor_voltage = new double[4];
+ for (int i = 0; i < 4; i++)
+ ignitor_voltage[i] = AltosConvert.mega_pyro_voltage(sensor_mega.sense[i]);
+ state.set_ignitor_voltage(ignitor_voltage);
+
+ } catch (TimeoutException te) {
+ }
+ }
+}
+
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+import java.util.concurrent.TimeoutException;
+
+class AltosSensorMetrum {
+ int tick;
+ int sense_a;
+ int sense_m;
+ int v_batt;
+
+ public AltosSensorMetrum(AltosLink link) throws InterruptedException, TimeoutException {
+ String[] items = link.adc();
+ for (int i = 0; i < items.length;) {
+ if (items[i].equals("tick:")) {
+ tick = Integer.parseInt(items[i+1]);
+ i += 2;
+ continue;
+ }
+ if (items[i].equals("drogue:")) {
+ sense_a = Integer.parseInt(items[i+1]);
+ i += 2;
+ continue;
+ }
+ if (items[i].equals("main:")) {
+ sense_m = Integer.parseInt(items[i+1]);
+ i += 2;
+ continue;
+ }
+ if (items[i].equals("batt:")) {
+ v_batt = Integer.parseInt(items[i+1]);
+ i += 2;
+ continue;
+ }
+ i++;
+ }
+ }
+
+ static public void update_state(AltosState state, AltosLink link, AltosConfigData config_data) throws InterruptedException {
+ try {
+ AltosSensorMetrum sensor_metrum = new AltosSensorMetrum(link);
+ state.set_battery_voltage(AltosConvert.mega_battery_voltage(sensor_metrum.v_batt));
+ state.set_apogee_voltage(AltosConvert.mega_pyro_voltage(sensor_metrum.sense_a));
+ state.set_main_voltage(AltosConvert.mega_pyro_voltage(sensor_metrum.sense_m));
+ } catch (TimeoutException te) {
+ }
+ }
+}
+
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
import java.util.concurrent.TimeoutException;
-class AltosSensorTM extends AltosRecordTM {
+public class AltosSensorTM {
+ public int tick;
+ public int accel;
+ public int pres;
+ public int temp;
+ public int batt;
+ public int drogue;
+ public int main;
- public AltosSensorTM(AltosLink link, AltosConfigData config_data) throws InterruptedException, TimeoutException {
- super();
+ static public void update_state(AltosState state, AltosLink link, AltosConfigData config_data) throws InterruptedException {
+ try {
+ AltosSensorTM sensor_tm = new AltosSensorTM(link);
+
+ if (sensor_tm == null)
+ return;
+ state.set_accel(sensor_tm.accel);
+ state.set_pressure(AltosConvert.barometer_to_pressure(sensor_tm.pres));
+ state.set_temperature(AltosConvert.thermometer_to_temperature(sensor_tm.temp));
+ state.set_battery_voltage(AltosConvert.cc_battery_to_voltage(sensor_tm.batt));
+ state.set_apogee_voltage(AltosConvert.cc_ignitor_to_voltage(sensor_tm.drogue));
+ state.set_main_voltage(AltosConvert.cc_ignitor_to_voltage(sensor_tm.main));
+
+ } catch (TimeoutException te) {
+ }
+ }
+
+ public AltosSensorTM(AltosLink link) throws InterruptedException, TimeoutException {
String[] items = link.adc();
for (int i = 0; i < items.length;) {
if (items[i].equals("tick:")) {
}
i++;
}
- ground_accel = config_data.accel_cal_plus;
- ground_pres = pres;
- accel_plus_g = config_data.accel_cal_plus;
- accel_minus_g = config_data.accel_cal_minus;
}
}
--- /dev/null
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+import java.util.concurrent.TimeoutException;
+
+public class AltosSensorTMini {
+ public int tick;
+ public int apogee;
+ public int main;
+ public int batt;
+
+ static public void update_state(AltosState state, AltosLink link, AltosConfigData config_data) throws InterruptedException {
+ try {
+ AltosSensorTMini sensor_tmini = new AltosSensorTMini(link);
+
+ if (sensor_tmini == null)
+ return;
+ state.set_battery_voltage(AltosConvert.easy_mini_voltage(sensor_tmini.batt));
+ state.set_apogee_voltage(AltosConvert.easy_mini_voltage(sensor_tmini.apogee));
+ state.set_main_voltage(AltosConvert.easy_mini_voltage(sensor_tmini.main));
+
+ } catch (TimeoutException te) {
+ }
+ }
+
+ public AltosSensorTMini(AltosLink link) throws InterruptedException, TimeoutException {
+ String[] items = link.adc();
+ for (int i = 0; i < items.length;) {
+ if (items[i].equals("tick:")) {
+ tick = Integer.parseInt(items[i+1]);
+ i += 2;
+ continue;
+ }
+ if (items[i].equals("apogee:")) {
+ apogee = Integer.parseInt(items[i+1]);
+ i += 2;
+ continue;
+ }
+ if (items[i].equals("main:")) {
+ main = Integer.parseInt(items[i+1]);
+ i += 2;
+ continue;
+ }
+ if (items[i].equals("batt:")) {
+ batt = Integer.parseInt(items[i+1]);
+ i += 2;
+ continue;
+ }
+ i++;
+ }
+ }
+}
+
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
public class AltosSpeed extends AltosUnits {
- public double value(double v) {
- if (AltosConvert.imperial_units)
+ public double value(double v, boolean imperial_units) {
+ if (imperial_units)
return AltosConvert.meters_to_mph(v);
return v;
}
- public String show_units() {
- if (AltosConvert.imperial_units)
+ public double inverse(double v, boolean imperial_units) {
+ if (imperial_units)
+ return AltosConvert.mph_to_meters(v);
+ return v;
+ }
+
+ public String show_units(boolean imperial_units) {
+ if (imperial_units)
return "mph";
return "m/s";
}
- public String say_units() {
- if (AltosConvert.imperial_units)
+ public String say_units(boolean imperial_units) {
+ if (imperial_units)
return "miles per hour";
return "meters per second";
}
- public int show_fraction(int width) {
+ public int show_fraction(int width, boolean imperial_units) {
return width / 9;
}
}
\ No newline at end of file
* Track flight state from telemetry or eeprom data stream
*/
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
-public class AltosState {
- public AltosRecord data;
+public class AltosState implements Cloneable {
+
+ public static final int set_position = 1;
+ public static final int set_gps = 2;
+ public static final int set_data = 4;
+
+ public int set;
+
+ static final double ascent_filter_len = 0.5;
+ static final double descent_filter_len = 0.5;
/* derived data */
- public long report_time;
+ public long received_time;
public double time;
+ public double prev_time;
public double time_change;
public int tick;
+ private int prev_tick;
+ public int boost_tick;
+
+ class AltosValue {
+ private double value;
+ private double prev_value;
+ private double max_value;
+ private double set_time;
+ private double prev_set_time;
+
+ void set(double new_value, double time) {
+ if (new_value != AltosLib.MISSING) {
+ value = new_value;
+ if (max_value == AltosLib.MISSING || value > max_value) {
+ max_value = value;
+ }
+ set_time = time;
+ }
+ }
+
+ void set_filtered(double new_value, double time) {
+ if (prev_value != AltosLib.MISSING)
+ new_value = (prev_value * 15.0 + new_value) / 16.0;
+ set(new_value, time);
+ }
+
+ double value() {
+ return value;
+ }
+
+ double max() {
+ return max_value;
+ }
+
+ double prev() {
+ return prev_value;
+ }
+
+ double change() {
+ if (value != AltosLib.MISSING && prev_value != AltosLib.MISSING)
+ return value - prev_value;
+ return AltosLib.MISSING;
+ }
+
+ double rate() {
+ double c = change();
+ double t = set_time - prev_set_time;
+
+ if (c != AltosLib.MISSING && t != 0)
+ return c / t;
+ return AltosLib.MISSING;
+ }
+
+ double integrate() {
+ if (value == AltosLib.MISSING)
+ return AltosLib.MISSING;
+ if (prev_value == AltosLib.MISSING)
+ return AltosLib.MISSING;
+
+ return (value + prev_value) / 2 * (set_time - prev_set_time);
+ }
+
+ double time() {
+ return set_time;
+ }
+
+ void set_derivative(AltosValue in) {
+ double n = in.rate();
+
+ if (n == AltosLib.MISSING)
+ return;
+
+ double p = prev_value;
+ double pt = prev_set_time;
+
+ if (p == AltosLib.MISSING) {
+ p = 0;
+ pt = in.time() - 0.01;
+ }
+
+ /* Clip changes to reduce noise */
+ double ddt = in.time() - pt;
+ double ddv = (n - p) / ddt;
+
+ final double max = 100000;
+
+ /* 100gs */
+ if (Math.abs(ddv) > max) {
+ if (n > p)
+ n = p + ddt * max;
+ else
+ n = p - ddt * max;
+ }
+
+ double filter_len;
+
+ if (ascent)
+ filter_len = ascent_filter_len;
+ else
+ filter_len = descent_filter_len;
+
+ double f = 1/Math.exp(ddt/ filter_len);
+ n = p * f + n * (1-f);
+
+ set(n, in.time());
+ }
+
+ void set_integral(AltosValue in) {
+ double change = in.integrate();
+
+ if (change != AltosLib.MISSING) {
+ double prev = prev_value;
+ if (prev == AltosLib.MISSING)
+ prev = 0;
+ set(prev + change, in.time());
+ }
+ }
+
+ void copy(AltosValue old) {
+ value = old.value;
+ set_time = old.set_time;
+ prev_value = old.value;
+ prev_set_time = old.set_time;
+ max_value = old.max_value;
+ }
+
+ void finish_update() {
+ prev_value = value;
+ prev_set_time = set_time;
+ }
+
+ AltosValue() {
+ value = AltosLib.MISSING;
+ prev_value = AltosLib.MISSING;
+ max_value = AltosLib.MISSING;
+ }
+ }
+
+ class AltosCValue {
+ AltosValue measured;
+ AltosValue computed;
+
+ double value() {
+ double v = measured.value();
+ if (v != AltosLib.MISSING)
+ return v;
+ return computed.value();
+ }
+
+ boolean is_measured() {
+ return measured.value() != AltosLib.MISSING;
+ }
+
+ double max() {
+ double m = measured.max();
+
+ if (m != AltosLib.MISSING)
+ return m;
+ return computed.max();
+ }
+
+ double prev_value() {
+ if (measured.value != AltosLib.MISSING && measured.prev_value != AltosLib.MISSING)
+ return measured.prev_value;
+ return computed.prev_value;
+ }
+
+ AltosValue altos_value() {
+ if (measured.value() != AltosLib.MISSING)
+ return measured;
+ return computed;
+ }
+
+ double change() {
+ double c = measured.change();
+ if (c == AltosLib.MISSING)
+ c = computed.change();
+ return c;
+ }
+
+ double rate() {
+ double r = measured.rate();
+ if (r == AltosLib.MISSING)
+ r = computed.rate();
+ return r;
+ }
+
+ void set_measured(double new_value, double time) {
+ measured.set(new_value, time);
+ }
+
+ void set_computed(double new_value, double time) {
+ computed.set(new_value, time);
+ }
+
+ void set_derivative(AltosValue in) {
+ computed.set_derivative(in);
+ }
+
+ void set_derivative(AltosCValue in) {
+ set_derivative(in.altos_value());
+ }
+
+ void set_integral(AltosValue in) {
+ computed.set_integral(in);
+ }
+
+ void set_integral(AltosCValue in) {
+ set_integral(in.altos_value());
+ }
+
+ void copy(AltosCValue old) {
+ measured.copy(old.measured);
+ computed.copy(old.computed);
+ }
+
+ void finish_update() {
+ measured.finish_update();
+ computed.finish_update();
+ }
+
+ AltosCValue() {
+ measured = new AltosValue();
+ computed = new AltosValue();
+ }
+ }
public int state;
+ public int flight;
+ public int serial;
+ public int receiver_serial;
public boolean landed;
public boolean ascent; /* going up? */
- public boolean boost; /* under power */
+ public boolean boost; /* under power */
+ public int rssi;
+ public int status;
+ public int device_type;
+ public int config_major;
+ public int config_minor;
+ public int apogee_delay;
+ public int main_deploy;
+ public int flight_log_max;
+
+ private double pressure_to_altitude(double p) {
+ if (p == AltosLib.MISSING)
+ return AltosLib.MISSING;
+ return AltosConvert.pressure_to_altitude(p);
+ }
+
+ private AltosCValue ground_altitude;
- public double ground_altitude;
- public double altitude;
- public double height;
- public double acceleration;
- public double battery;
+ public double ground_altitude() {
+ return ground_altitude.value();
+ }
+
+ public void set_ground_altitude(double a) {
+ ground_altitude.set_measured(a, time);
+ }
+
+ class AltosGroundPressure extends AltosCValue {
+ void set_filtered(double p, double time) {
+ computed.set_filtered(p, time);
+ if (!is_measured())
+ ground_altitude.set_computed(pressure_to_altitude(computed.value()), time);
+ }
+
+ void set_measured(double p, double time) {
+ super.set_measured(p, time);
+ ground_altitude.set_computed(pressure_to_altitude(p), time);
+ }
+ }
+
+ private AltosGroundPressure ground_pressure;
+
+ public double ground_pressure() {
+ return ground_pressure.value();
+ }
+
+ public void set_ground_pressure (double pressure) {
+ ground_pressure.set_measured(pressure, time);
+ }
+
+ class AltosAltitude extends AltosCValue {
+
+ private void set_speed(AltosValue v) {
+ if (!acceleration.is_measured() || !ascent)
+ speed.set_derivative(this);
+ }
+
+ void set_computed(double a, double time) {
+ super.set_computed(a,time);
+ set_speed(computed);
+ set |= set_position;
+ }
+
+ void set_measured(double a, double time) {
+ super.set_measured(a,time);
+ set_speed(measured);
+ set |= set_position;
+ }
+ }
+
+ private AltosAltitude altitude;
+
+ public double altitude() {
+ double a = altitude.value();
+ if (a != AltosLib.MISSING)
+ return a;
+ if (gps != null)
+ return gps.alt;
+ return AltosLib.MISSING;
+ }
+
+ public double max_altitude() {
+ double a = altitude.max();
+ if (a != AltosLib.MISSING)
+ return a;
+ return AltosLib.MISSING;
+ }
+
+ public void set_altitude(double new_altitude) {
+ altitude.set_measured(new_altitude, time);
+ }
+
+ class AltosPressure extends AltosValue {
+ void set(double p, double time) {
+ super.set(p, time);
+ if (state == AltosLib.ao_flight_pad)
+ ground_pressure.set_filtered(p, time);
+ double a = pressure_to_altitude(p);
+ altitude.set_computed(a, time);
+ }
+ }
+
+ private AltosPressure pressure;
+
+ public double pressure() {
+ return pressure.value();
+ }
+
+ public void set_pressure(double p) {
+ pressure.set(p, time);
+ }
+
+ public double height() {
+ double k = kalman_height.value();
+ if (k != AltosLib.MISSING)
+ return k;
+
+ double a = altitude();
+ double g = ground_altitude();
+ if (a != AltosLib.MISSING && g != AltosLib.MISSING)
+ return a - g;
+ return AltosLib.MISSING;
+ }
+
+ public double max_height() {
+ double k = kalman_height.max();
+ if (k != AltosLib.MISSING)
+ return k;
+
+ double a = altitude.max();
+ double g = ground_altitude();
+ if (a != AltosLib.MISSING && g != AltosLib.MISSING)
+ return a - g;
+ return AltosLib.MISSING;
+ }
+
+ class AltosSpeed extends AltosCValue {
+
+ void set_accel() {
+ acceleration.set_derivative(this);
+ }
+
+ void set_derivative(AltosCValue in) {
+ super.set_derivative(in);
+ set_accel();
+ }
+
+ void set_computed(double new_value, double time) {
+ super.set_computed(new_value, time);
+ set_accel();
+ }
+
+ void set_measured(double new_value, double time) {
+ super.set_measured(new_value, time);
+ set_accel();
+ }
+ }
+
+ private AltosSpeed speed;
+
+ public double speed() {
+ double v = kalman_speed.value();
+ if (v != AltosLib.MISSING)
+ return v;
+ return speed.value();
+ }
+
+ public double max_speed() {
+ double v = kalman_speed.max();
+ if (v != AltosLib.MISSING)
+ return v;
+ return speed.max();
+ }
+
+ class AltosAccel extends AltosCValue {
+ void set_measured(double a, double time) {
+ super.set_measured(a, time);
+ if (ascent)
+ speed.set_integral(this.measured);
+ }
+ }
+
+ AltosAccel acceleration;
+
+ public double acceleration() {
+ return acceleration.value();
+ }
+
+ public double max_acceleration() {
+ return acceleration.max();
+ }
+
+ public AltosValue kalman_height, kalman_speed, kalman_acceleration;
+
+ public void set_kalman(double height, double speed, double acceleration) {
+ kalman_height.set(height, time);
+ kalman_speed.set(speed, time);
+ kalman_acceleration.set(acceleration, time);
+ }
+
+ public double battery_voltage;
+ public double pyro_voltage;
public double temperature;
- public double main_sense;
- public double drogue_sense;
- public double accel_speed;
- public double baro_speed;
+ public double apogee_voltage;
+ public double main_voltage;
- public double max_height;
- public double max_acceleration;
- public double max_accel_speed;
- public double max_baro_speed;
+ public double ignitor_voltage[];
public AltosGPS gps;
+ public AltosGPS temp_gps;
+ public int temp_gps_sat_tick;
+ public boolean gps_pending;
public int gps_sequence;
public AltosIMU imu;
public static final int MIN_PAD_SAMPLES = 10;
public int npad;
- public int ngps;
public int gps_waiting;
public boolean gps_ready;
+ public int ngps;
+
public AltosGreatCircle from_pad;
public double elevation; /* from pad */
public double range; /* total distance */
public int speak_tick;
public double speak_altitude;
- public double speed() {
- if (ascent)
- return accel_speed;
- else
- return baro_speed;
+ public String callsign;
+ public String firmware_version;
+
+ public double accel_plus_g;
+ public double accel_minus_g;
+ public double accel;
+ public double ground_accel;
+ public double ground_accel_avg;
+
+ public int log_format;
+
+ public AltosMs5607 baro;
+
+ public AltosCompanion companion;
+
+ public void set_npad(int npad) {
+ this.npad = npad;
+ gps_waiting = MIN_PAD_SAMPLES - npad;
+ if (this.gps_waiting < 0)
+ gps_waiting = 0;
+ gps_ready = gps_waiting == 0;
}
- public double max_speed() {
- if (max_accel_speed != 0)
- return max_accel_speed;
- return max_baro_speed;
- }
-
- public void init (AltosRecord cur, AltosState prev_state) {
- data = cur;
-
- /* Discard previous state if it was for a different board */
- if (prev_state != null && prev_state.data.serial != data.serial)
- prev_state = null;
- ground_altitude = data.ground_altitude();
-
- altitude = data.altitude();
- if (altitude == AltosRecord.MISSING && data.gps != null)
- altitude = data.gps.alt;
-
- height = AltosRecord.MISSING;
- if (data.kalman_height != AltosRecord.MISSING)
- height = data.kalman_height;
- else {
- if (altitude != AltosRecord.MISSING && ground_altitude != AltosRecord.MISSING) {
- double cur_height = altitude - ground_altitude;
- if (prev_state == null || prev_state.height == AltosRecord.MISSING)
- height = cur_height;
- else
- height = (prev_state.height * 15 + cur_height) / 16.0;
- }
+ public void init() {
+ set = 0;
+
+ received_time = System.currentTimeMillis();
+ time = AltosLib.MISSING;
+ time_change = AltosLib.MISSING;
+ prev_time = AltosLib.MISSING;
+ tick = AltosLib.MISSING;
+ prev_tick = AltosLib.MISSING;
+ boost_tick = AltosLib.MISSING;
+ state = AltosLib.ao_flight_invalid;
+ flight = AltosLib.MISSING;
+ landed = false;
+ boost = false;
+ rssi = AltosLib.MISSING;
+ status = 0;
+ device_type = AltosLib.MISSING;
+ config_major = AltosLib.MISSING;
+ config_minor = AltosLib.MISSING;
+ apogee_delay = AltosLib.MISSING;
+ main_deploy = AltosLib.MISSING;
+ flight_log_max = AltosLib.MISSING;
+
+ ground_altitude = new AltosCValue();
+ ground_pressure = new AltosGroundPressure();
+ altitude = new AltosAltitude();
+ pressure = new AltosPressure();
+ speed = new AltosSpeed();
+ acceleration = new AltosAccel();
+
+ temperature = AltosLib.MISSING;
+ battery_voltage = AltosLib.MISSING;
+ pyro_voltage = AltosLib.MISSING;
+ apogee_voltage = AltosLib.MISSING;
+ main_voltage = AltosLib.MISSING;
+ ignitor_voltage = null;
+
+ kalman_height = new AltosValue();
+ kalman_speed = new AltosValue();
+ kalman_acceleration = new AltosValue();
+
+ gps = null;
+ temp_gps = null;
+ temp_gps_sat_tick = 0;
+ gps_sequence = 0;
+ gps_pending = false;
+
+ imu = null;
+ mag = null;
+
+ set_npad(0);
+ ngps = 0;
+
+ from_pad = null;
+ elevation = AltosLib.MISSING;
+ range = AltosLib.MISSING;
+ gps_height = AltosLib.MISSING;
+
+ pad_lat = AltosLib.MISSING;
+ pad_lon = AltosLib.MISSING;
+ pad_alt = AltosLib.MISSING;
+
+ speak_tick = AltosLib.MISSING;
+ speak_altitude = AltosLib.MISSING;
+
+ callsign = null;
+
+ accel_plus_g = AltosLib.MISSING;
+ accel_minus_g = AltosLib.MISSING;
+ accel = AltosLib.MISSING;
+
+ ground_accel = AltosLib.MISSING;
+ ground_accel_avg = AltosLib.MISSING;
+
+ log_format = AltosLib.MISSING;
+ serial = AltosLib.MISSING;
+ receiver_serial = AltosLib.MISSING;
+
+ baro = null;
+ companion = null;
+ }
+
+ void finish_update() {
+ prev_tick = tick;
+
+ ground_altitude.finish_update();
+ altitude.finish_update();
+ pressure.finish_update();
+ speed.finish_update();
+ acceleration.finish_update();
+
+ kalman_height.finish_update();
+ kalman_speed.finish_update();
+ kalman_acceleration.finish_update();
+ }
+
+ void copy(AltosState old) {
+
+ if (old == null) {
+ init();
+ return;
}
- report_time = System.currentTimeMillis();
+ received_time = old.received_time;
+ time = old.time;
+ time_change = old.time_change;
+ prev_time = old.time;
+
+ tick = old.tick;
+ prev_tick = old.tick;
+ boost_tick = old.boost_tick;
+
+ state = old.state;
+ flight = old.flight;
+ landed = old.landed;
+ ascent = old.ascent;
+ boost = old.boost;
+ rssi = old.rssi;
+ status = old.status;
+ device_type = old.device_type;
+ config_major = old.config_major;
+ config_minor = old.config_minor;
+ apogee_delay = old.apogee_delay;
+ main_deploy = old.main_deploy;
+ flight_log_max = old.flight_log_max;
+
+ set = 0;
+
+ ground_pressure.copy(old.ground_pressure);
+ ground_altitude.copy(old.ground_altitude);
+ altitude.copy(old.altitude);
+ pressure.copy(old.pressure);
+ speed.copy(old.speed);
+ acceleration.copy(old.acceleration);
+
+ battery_voltage = old.battery_voltage;
+ pyro_voltage = old.pyro_voltage;
+ temperature = old.temperature;
+ apogee_voltage = old.apogee_voltage;
+ main_voltage = old.main_voltage;
+ ignitor_voltage = old.ignitor_voltage;
+
+ kalman_height.copy(old.kalman_height);
+ kalman_speed.copy(old.kalman_speed);
+ kalman_acceleration.copy(old.kalman_acceleration);
- if (data.kalman_acceleration != AltosRecord.MISSING)
- acceleration = data.kalman_acceleration;
+ if (old.gps != null)
+ gps = old.gps.clone();
else
- acceleration = data.acceleration();
- temperature = data.temperature();
- drogue_sense = data.drogue_voltage();
- main_sense = data.main_voltage();
- battery = data.battery_voltage();
- tick = data.tick;
- state = data.state;
-
- if (prev_state != null) {
-
- /* Preserve any existing gps data */
- npad = prev_state.npad;
- ngps = prev_state.ngps;
- gps = prev_state.gps;
- gps_sequence = prev_state.gps_sequence;
- pad_lat = prev_state.pad_lat;
- pad_lon = prev_state.pad_lon;
- pad_alt = prev_state.pad_alt;
- max_height = prev_state.max_height;
- max_acceleration = prev_state.max_acceleration;
- max_accel_speed = prev_state.max_accel_speed;
- max_baro_speed = prev_state.max_baro_speed;
- imu = prev_state.imu;
- mag = prev_state.mag;
-
- /* make sure the clock is monotonic */
- while (tick < prev_state.tick)
- tick += 65536;
-
- time_change = (tick - prev_state.tick) / 100.0;
-
- if (data.kalman_speed != AltosRecord.MISSING) {
- baro_speed = accel_speed = data.kalman_speed;
- } else {
- /* compute barometric speed */
-
- double height_change = height - prev_state.height;
-
- double prev_baro_speed = prev_state.baro_speed;
- if (prev_baro_speed == AltosRecord.MISSING)
- prev_baro_speed = 0;
-
- if (time_change > 0)
- baro_speed = (prev_baro_speed * 3 + (height_change / time_change)) / 4.0;
- else
- baro_speed = prev_state.baro_speed;
+ gps = null;
+ if (old.temp_gps != null)
+ temp_gps = old.temp_gps.clone();
+ else
+ temp_gps = null;
+ temp_gps_sat_tick = old.temp_gps_sat_tick;
+ gps_sequence = old.gps_sequence;
+ gps_pending = old.gps_pending;
- double prev_accel_speed = prev_state.accel_speed;
+ if (old.imu != null)
+ imu = old.imu.clone();
+ else
+ imu = null;
- if (prev_accel_speed == AltosRecord.MISSING)
- prev_accel_speed = 0;
+ if (old.mag != null)
+ mag = old.mag.clone();
+ else
+ mag = null;
- if (acceleration == AltosRecord.MISSING) {
- /* Fill in mising acceleration value */
- accel_speed = baro_speed;
+ npad = old.npad;
+ gps_waiting = old.gps_waiting;
+ gps_ready = old.gps_ready;
+ ngps = old.ngps;
- if (time_change > 0 && accel_speed != AltosRecord.MISSING)
- acceleration = (accel_speed - prev_accel_speed) / time_change;
- else
- acceleration = prev_state.acceleration;
- } else {
- /* compute accelerometer speed */
- accel_speed = prev_accel_speed + acceleration * time_change;
+ if (old.from_pad != null)
+ from_pad = old.from_pad.clone();
+ else
+ from_pad = null;
+
+ elevation = old.elevation;
+ range = old.range;
+
+ gps_height = old.gps_height;
+ pad_lat = old.pad_lat;
+ pad_lon = old.pad_lon;
+ pad_alt = old.pad_alt;
+
+ speak_tick = old.speak_tick;
+ speak_altitude = old.speak_altitude;
+
+ callsign = old.callsign;
+
+ accel_plus_g = old.accel_plus_g;
+ accel_minus_g = old.accel_minus_g;
+ accel = old.accel;
+ ground_accel = old.ground_accel;
+ ground_accel_avg = old.ground_accel_avg;
+
+ log_format = old.log_format;
+ serial = old.serial;
+ receiver_serial = old.receiver_serial;
+
+ baro = old.baro;
+ companion = old.companion;
+ }
+
+ void update_time() {
+ }
+
+ void update_gps() {
+ elevation = 0;
+ range = -1;
+ gps_height = 0;
+
+ if (gps == null)
+ return;
+
+ if (gps.locked && gps.nsat >= 4) {
+ /* Track consecutive 'good' gps reports, waiting for 10 of them */
+ if (state == AltosLib.ao_flight_pad) {
+ set_npad(npad+1);
+ if (pad_lat != AltosLib.MISSING) {
+ pad_lat = (pad_lat * 31 + gps.lat) / 32;
+ pad_lon = (pad_lon * 31 + gps.lon) / 32;
+ pad_alt = (pad_alt * 31 + gps.alt) / 32;
}
}
- } else {
- npad = 0;
- ngps = 0;
- gps = null;
- gps_sequence = 0;
- baro_speed = AltosRecord.MISSING;
- accel_speed = AltosRecord.MISSING;
- pad_alt = AltosRecord.MISSING;
- max_baro_speed = 0;
- max_accel_speed = 0;
- max_height = 0;
- max_acceleration = 0;
- time_change = 0;
+ if (pad_lat == AltosLib.MISSING) {
+ pad_lat = gps.lat;
+ pad_lon = gps.lon;
+ pad_alt = gps.alt;
+ }
}
+ if (gps.lat != 0 && gps.lon != 0 &&
+ pad_lat != AltosLib.MISSING &&
+ pad_lon != AltosLib.MISSING)
+ {
+ double h = height();
- time = tick / 100.0;
-
- if (data.gps != null && data.gps_sequence != gps_sequence && (state < AltosLib.ao_flight_boost)) {
+ if (h == AltosLib.MISSING)
+ h = 0;
+ from_pad = new AltosGreatCircle(pad_lat, pad_lon, 0, gps.lat, gps.lon, h);
+ elevation = from_pad.elevation;
+ range = from_pad.range;
+ gps_height = gps.alt - pad_alt;
+ }
+ }
- /* Track consecutive 'good' gps reports, waiting for 10 of them */
- if (data.gps != null && data.gps.locked && data.gps.nsat >= 4)
- npad++;
- else
- npad = 0;
-
- /* Average GPS data while on the pad */
- if (data.gps != null && data.gps.locked && data.gps.nsat >= 4) {
- if (ngps > 1 && state == AltosLib.ao_flight_pad) {
- /* filter pad position */
- pad_lat = (pad_lat * 31.0 + data.gps.lat) / 32.0;
- pad_lon = (pad_lon * 31.0 + data.gps.lon) / 32.0;
- pad_alt = (pad_alt * 31.0 + data.gps.alt) / 32.0;
- } else {
- pad_lat = data.gps.lat;
- pad_lon = data.gps.lon;
- pad_alt = data.gps.alt;
+ public void set_tick(int new_tick) {
+ if (new_tick != AltosLib.MISSING) {
+ if (prev_tick != AltosLib.MISSING) {
+ while (new_tick < prev_tick - 1000) {
+ new_tick += 65536;
}
- ngps++;
}
- } else {
- if (ngps == 0 && ground_altitude != AltosRecord.MISSING)
- pad_alt = ground_altitude;
+ tick = new_tick;
+ time = tick / 100.0;
+ time_change = time - prev_time;
}
+ }
- gps_sequence = data.gps_sequence;
+ public void set_boost_tick(int boost_tick) {
+ if (boost_tick != AltosLib.MISSING)
+ this.boost_tick = boost_tick;
+ }
- gps_waiting = MIN_PAD_SAMPLES - npad;
- if (gps_waiting < 0)
- gps_waiting = 0;
+ public String state_name() {
+ return AltosLib.state_name(state);
+ }
- gps_ready = gps_waiting == 0;
+ public void set_state(int state) {
+ if (state != AltosLib.ao_flight_invalid) {
+ this.state = state;
+ ascent = (AltosLib.ao_flight_boost <= state &&
+ state <= AltosLib.ao_flight_coast);
+ boost = (AltosLib.ao_flight_boost == state);
+ }
- ascent = (AltosLib.ao_flight_boost <= state &&
- state <= AltosLib.ao_flight_coast);
- boost = (AltosLib.ao_flight_boost == state);
+ }
- /* Only look at accelerometer data under boost */
- if (boost && acceleration != AltosRecord.MISSING && (max_acceleration == AltosRecord.MISSING || acceleration > max_acceleration))
- max_acceleration = acceleration;
- if (boost && accel_speed != AltosRecord.MISSING && accel_speed > max_accel_speed)
- max_accel_speed = accel_speed;
- if (boost && baro_speed != AltosRecord.MISSING && baro_speed > max_baro_speed)
- max_baro_speed = baro_speed;
+ public void set_device_type(int device_type) {
+ this.device_type = device_type;
+ }
- if (height != AltosRecord.MISSING && height > max_height)
- max_height = height;
- elevation = 0;
- range = -1;
- gps_height = 0;
- if (data.gps != null) {
- gps = data.gps;
- if (ngps > 0 && gps.locked) {
- double h = height;
-
- if (h == AltosRecord.MISSING) h = 0;
- from_pad = new AltosGreatCircle(pad_lat, pad_lon, 0, gps.lat, gps.lon, h);
- elevation = from_pad.elevation;
- range = from_pad.range;
- gps_height = gps.alt - pad_alt;
+ public void set_config(int major, int minor, int apogee_delay, int main_deploy, int flight_log_max) {
+ config_major = major;
+ config_minor = minor;
+ this.apogee_delay = apogee_delay;
+ this.main_deploy = main_deploy;
+ this.flight_log_max = flight_log_max;
+ }
+
+ public void set_callsign(String callsign) {
+ this.callsign = callsign;
+ }
+
+ public void set_firmware_version(String version) {
+ firmware_version = version;
+ }
+
+ public void set_flight(int flight) {
+
+ /* When the flight changes, reset the state */
+ if (flight != AltosLib.MISSING && flight != 0) {
+ if (this.flight != AltosLib.MISSING &&
+ this.flight != flight) {
+ int bt = boost_tick;
+ init();
+ boost_tick = bt;
+ }
+ this.flight = flight;
+ }
+ }
+
+ public void set_serial(int serial) {
+ /* When the serial changes, reset the state */
+ if (serial != AltosLib.MISSING) {
+ if (this.serial != AltosLib.MISSING &&
+ this.serial != serial) {
+ int bt = boost_tick;
+ init();
+ boost_tick = bt;
+ }
+ this.serial = serial;
+ }
+ }
+
+ public void set_receiver_serial(int serial) {
+ if (serial != AltosLib.MISSING)
+ receiver_serial = serial;
+ }
+
+ public int rssi() {
+ if (rssi == AltosLib.MISSING)
+ return 0;
+ return rssi;
+ }
+
+ public void set_rssi(int rssi, int status) {
+ if (rssi != AltosLib.MISSING) {
+ this.rssi = rssi;
+ this.status = status;
+ }
+ }
+
+ public void set_received_time(long ms) {
+ received_time = ms;
+ }
+
+ public void set_gps(AltosGPS gps, int sequence) {
+ if (gps != null) {
+ this.gps = gps.clone();
+ gps_sequence = sequence;
+ update_gps();
+ set |= set_gps;
+ }
+ }
+
+ public void set_imu(AltosIMU imu) {
+ if (imu != null)
+ imu = imu.clone();
+ this.imu = imu;
+ }
+
+ public void set_mag(AltosMag mag) {
+ this.mag = mag.clone();
+ }
+
+ public AltosMs5607 make_baro() {
+ if (baro == null)
+ baro = new AltosMs5607();
+ return baro;
+ }
+
+ public void set_ms5607(AltosMs5607 ms5607) {
+ baro = ms5607;
+
+ if (baro != null) {
+ set_pressure(baro.pa);
+ set_temperature(baro.cc / 100.0);
+ }
+ }
+
+ public void set_ms5607(int pres, int temp) {
+ if (baro != null) {
+ baro.set(pres, temp);
+
+ set_pressure(baro.pa);
+ set_temperature(baro.cc / 100.0);
+ }
+ }
+
+ public void make_companion (int nchannels) {
+ if (companion == null)
+ companion = new AltosCompanion(nchannels);
+ }
+
+ public void set_companion(AltosCompanion companion) {
+ this.companion = companion;
+ }
+
+ void update_accel() {
+ double ground = ground_accel;
+
+ if (ground == AltosLib.MISSING)
+ ground = ground_accel_avg;
+ if (accel == AltosLib.MISSING)
+ return;
+ if (ground == AltosLib.MISSING)
+ return;
+ if (accel_plus_g == AltosLib.MISSING)
+ return;
+ if (accel_minus_g == AltosLib.MISSING)
+ return;
+
+ double counts_per_g = (accel_minus_g - accel_plus_g) / 2.0;
+ double counts_per_mss = counts_per_g / 9.80665;
+ acceleration.set_measured((ground - accel) / counts_per_mss, time);
+ }
+
+ public void set_accel_g(double accel_plus_g, double accel_minus_g) {
+ if (accel_plus_g != AltosLib.MISSING) {
+ this.accel_plus_g = accel_plus_g;
+ this.accel_minus_g = accel_minus_g;
+ update_accel();
+ }
+ }
+
+ public void set_ground_accel(double ground_accel) {
+ if (ground_accel != AltosLib.MISSING) {
+ this.ground_accel = ground_accel;
+ update_accel();
+ }
+ }
+
+ public void set_accel(double accel) {
+ if (accel != AltosLib.MISSING) {
+ this.accel = accel;
+ if (state == AltosLib.ao_flight_pad) {
+ if (ground_accel_avg == AltosLib.MISSING)
+ ground_accel_avg = accel;
+ else
+ ground_accel_avg = (ground_accel_avg * 7 + accel) / 8;
}
}
+ update_accel();
+ }
+
+ public void set_temperature(double temperature) {
+ if (temperature != AltosLib.MISSING) {
+ this.temperature = temperature;
+ set |= set_data;
+ }
+ }
+
+ public void set_battery_voltage(double battery_voltage) {
+ if (battery_voltage != AltosLib.MISSING) {
+ this.battery_voltage = battery_voltage;
+ set |= set_data;
+ }
+ }
+
+ public void set_pyro_voltage(double pyro_voltage) {
+ if (pyro_voltage != AltosLib.MISSING) {
+ this.pyro_voltage = pyro_voltage;
+ set |= set_data;
+ }
+ }
+
+ public void set_apogee_voltage(double apogee_voltage) {
+ if (apogee_voltage != AltosLib.MISSING) {
+ this.apogee_voltage = apogee_voltage;
+ set |= set_data;
+ }
+ }
+
+ public void set_main_voltage(double main_voltage) {
+ if (main_voltage != AltosLib.MISSING) {
+ this.main_voltage = main_voltage;
+ set |= set_data;
+ }
+ }
+
+ public void set_ignitor_voltage(double[] voltage) {
+ this.ignitor_voltage = voltage;
+ }
+
+ public double time_since_boost() {
+ if (tick == AltosLib.MISSING)
+ return 0.0;
+
+ if (boost_tick == AltosLib.MISSING)
+ return tick / 100.0;
+ return (tick - boost_tick) / 100.0;
+ }
+
+ public boolean valid() {
+ return tick != AltosLib.MISSING && serial != AltosLib.MISSING;
+ }
+
+ public AltosGPS make_temp_gps(boolean sats) {
+ if (temp_gps == null) {
+ temp_gps = new AltosGPS(gps);
+ }
+ gps_pending = true;
+ if (sats) {
+ if (tick != temp_gps_sat_tick)
+ temp_gps.cc_gps_sat = null;
+ temp_gps_sat_tick = tick;
+ }
+ return temp_gps;
+ }
+
+ public void set_temp_gps() {
+ set_gps(temp_gps, gps_sequence + 1);
+ gps_pending = false;
+ temp_gps = null;
}
- public AltosState(AltosRecord cur) {
- init(cur, null);
+ public AltosState clone() {
+ AltosState s = new AltosState();
+ s.copy(this);
+ return s;
}
- public AltosState (AltosRecord cur, AltosState prev) {
- init(cur, prev);
+ public AltosState () {
+ init();
}
}
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+import java.io.*;
+import java.util.*;
+
+public abstract class AltosStateIterable implements Iterable<AltosState> {
+
+ public void write_comments (PrintStream out) {
+ }
+
+ public abstract void write(PrintStream out);
+}
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+public interface AltosStateUpdate {
+ public void update_state(AltosState state) throws InterruptedException;
+}
\ No newline at end of file
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
import java.text.*;
* Telemetry data contents
*/
+public abstract class AltosTelemetry implements AltosStateUpdate {
-/*
- * The packet format is a simple hex dump of the raw telemetry frame.
- * It starts with 'TELEM', then contains hex digits with a checksum as the last
- * byte on the line.
- *
- * Version 4 is a replacement with consistent syntax. Each telemetry line
- * contains a sequence of space-separated names and values, the values are
- * either integers or strings. The names are all unique. All values are
- * optional
- *
- * VERSION 4 c KD7SQG n 236 f 18 r -25 s pad t 513 r_a 15756 r_b 26444 r_t 20944
- * r_v 26640 r_d 512 r_m 208 c_a 15775 c_b 26439 c_p 15749 c_m 16281 a_a 15764
- * a_s 0 a_b 26439 g_s u g_n 0 s_n 0
- *
- * VERSION 4 c KD7SQG n 19 f 0 r -23 s pad t 513 r_b 26372 r_t 21292 r_v 26788
- * r_d 136 r_m 140 c_b 26370 k_h 0 k_s 0 k_a 0
- *
- * General header fields
- *
- * Name Value
- *
- * VERSION Telemetry version number (4 or more). Must be first.
- * c Callsign (string, no spaces allowed)
- * n Flight unit serial number (integer)
- * f Flight number (integer)
- * r Packet RSSI value (integer)
- * s Flight computer state (string, no spaces allowed)
- * t Flight computer clock (integer in centiseconds)
- *
- * Version 3 is Version 2 with fixed RSSI numbers -- the radio reports
- * in 1/2dB increments while this protocol provides only integers. So,
- * the syntax didn't change just the interpretation of the RSSI
- * values.
- *
- * Version 2 of the telemetry data stream is a bit of a mess, with no
- * consistent formatting. In particular, the GPS data is formatted for
- * viewing instead of parsing. However, the key feature is that every
- * telemetry line contains all of the information necessary to
- * describe the current rocket state, including the calibration values
- * for accelerometer and barometer.
- *
- * GPS unlocked:
- *
- * VERSION 2 CALL KB0G SERIAL 51 FLIGHT 2 RSSI -68 STATUS ff STATE pad 1001 \
- * a: 16032 p: 21232 t: 20284 v: 25160 d: 204 m: 204 fa: 16038 ga: 16032 fv: 0 \
- * fp: 21232 gp: 21230 a+: 16049 a-: 16304 GPS 0 sat unlocked SAT 1 15 30
- *
- * GPS locked:
- *
- * VERSION 2 CALL KB0G SERIAL 51 FLIGHT 2 RSSI -71 STATUS ff STATE pad 2504 \
- * a: 16028 p: 21220 t: 20360 v: 25004 d: 208 m: 200 fa: 16031 ga: 16032 fv: 330 \
- * fp: 21231 gp: 21230 a+: 16049 a-: 16304 \
- * GPS 9 sat 2010-02-13 17:16:51 35°20.0803'N 106°45.2235'W 1790m \
- * 0.00m/s(H) 0° 0.00m/s(V) 1.0(hdop) 0(herr) 0(verr) \
- * SAT 10 29 30 24 28 5 25 21 20 15 33 1 23 30 24 18 26 10 29 2 26
- *
- */
+ /* All telemetry packets have these fields */
+ public int tick;
+ public int serial;
+ public int rssi;
+ public int status;
+
+ /* Mark when we received the packet */
+ long received_time;
+
+ static boolean cksum(int[] bytes) {
+ int sum = 0x5a;
+ for (int i = 1; i < bytes.length - 1; i++)
+ sum += bytes[i];
+ sum &= 0xff;
+ return sum == bytes[bytes.length - 1];
+ }
+
+ public void update_state(AltosState state) {
+ if (state.state == AltosLib.ao_flight_invalid)
+ state.set_state(AltosLib.ao_flight_startup);
+ state.set_serial(serial);
+ state.set_tick(tick);
+ state.set_rssi(rssi, status);
+ state.set_received_time(received_time);
+ }
+
+ final static int PKT_APPEND_STATUS_1_CRC_OK = (1 << 7);
+ final static int PKT_APPEND_STATUS_1_LQI_MASK = (0x7f);
+ final static int PKT_APPEND_STATUS_1_LQI_SHIFT = 0;
+
+ final static int packet_type_TM_sensor = 0x01;
+ final static int packet_type_Tm_sensor = 0x02;
+ final static int packet_type_Tn_sensor = 0x03;
+ final static int packet_type_configuration = 0x04;
+ final static int packet_type_location = 0x05;
+ final static int packet_type_satellite = 0x06;
+ final static int packet_type_companion = 0x07;
+ final static int packet_type_mega_sensor = 0x08;
+ final static int packet_type_mega_data = 0x09;
+ final static int packet_type_metrum_sensor = 0x0a;
+ final static int packet_type_metrum_data = 0x0b;
+ final static int packet_type_mini = 0x10;
+
+ static AltosTelemetry parse_hex(String hex) throws ParseException, AltosCRCException {
+ AltosTelemetry telem = null;
+
+ int[] bytes;
+ try {
+ bytes = AltosLib.hexbytes(hex);
+ } catch (NumberFormatException ne) {
+ throw new ParseException(ne.getMessage(), 0);
+ }
+
+ /* one for length, one for checksum */
+ if (bytes[0] != bytes.length - 2)
+ throw new ParseException(String.format("invalid length %d != %d\n",
+ bytes[0],
+ bytes.length - 2), 0);
+ if (!cksum(bytes))
+ throw new ParseException(String.format("invalid line \"%s\"", hex), 0);
+
+ int rssi = AltosLib.int8(bytes, bytes.length - 3) / 2 - 74;
+ int status = AltosLib.uint8(bytes, bytes.length - 2);
+
+ if ((status & PKT_APPEND_STATUS_1_CRC_OK) == 0)
+ throw new AltosCRCException(rssi);
+
+ /* length, data ..., rssi, status, checksum -- 4 bytes extra */
+ switch (bytes.length) {
+ case AltosLib.ao_telemetry_standard_len + 4:
+ telem = AltosTelemetryStandard.parse_hex(bytes);
+ break;
+ case AltosLib.ao_telemetry_0_9_len + 4:
+ telem = new AltosTelemetryLegacy(bytes);
+ break;
+ case AltosLib.ao_telemetry_0_8_len + 4:
+ telem = new AltosTelemetryLegacy(bytes);
+ break;
+ default:
+ throw new ParseException(String.format("Invalid packet length %d", bytes.length), 0);
+ }
+ if (telem != null) {
+ telem.received_time = System.currentTimeMillis();
+ telem.rssi = rssi;
+ telem.status = status;
+ }
+ return telem;
+ }
+
+ public static AltosTelemetry parse(String line) throws ParseException, AltosCRCException {
+ String[] word = line.split("\\s+");
+ int i =0;
+
+ if (word[i].equals("CRC") && word[i+1].equals("INVALID")) {
+ i += 2;
+ AltosParse.word(word[i++], "RSSI");
+ throw new AltosCRCException(AltosParse.parse_int(word[i++]));
+ }
+
+ AltosTelemetry telem;
-public abstract class AltosTelemetry extends AltosRecord {
-
- /*
- * General header fields
- *
- * Name Value
- *
- * VERSION Telemetry version number (4 or more). Must be first.
- * c Callsign (string, no spaces allowed)
- * n Flight unit serial number (integer)
- * f Flight number (integer)
- * r Packet RSSI value (integer)
- * s Flight computer state (string, no spaces allowed)
- * t Flight computer clock (integer in centiseconds)
- */
-
- final static String AO_TELEM_VERSION = "VERSION";
- final static String AO_TELEM_CALL = "c";
- final static String AO_TELEM_SERIAL = "n";
- final static String AO_TELEM_FLIGHT = "f";
- final static String AO_TELEM_RSSI = "r";
- final static String AO_TELEM_STATE = "s";
- final static String AO_TELEM_TICK = "t";
-
- /*
- * Raw sensor values
- *
- * Name Value
- * r_a Accelerometer reading (integer)
- * r_b Barometer reading (integer)
- * r_t Thermometer reading (integer)
- * r_v Battery reading (integer)
- * r_d Drogue continuity (integer)
- * r_m Main continuity (integer)
- */
-
- final static String AO_TELEM_RAW_ACCEL = "r_a";
- final static String AO_TELEM_RAW_BARO = "r_b";
- final static String AO_TELEM_RAW_THERMO = "r_t";
- final static String AO_TELEM_RAW_BATT = "r_v";
- final static String AO_TELEM_RAW_DROGUE = "r_d";
- final static String AO_TELEM_RAW_MAIN = "r_m";
-
- /*
- * Sensor calibration values
- *
- * Name Value
- * c_a Ground accelerometer reading (integer)
- * c_b Ground barometer reading (integer)
- * c_p Accelerometer reading for +1g
- * c_m Accelerometer reading for -1g
- */
-
- final static String AO_TELEM_CAL_ACCEL_GROUND = "c_a";
- final static String AO_TELEM_CAL_BARO_GROUND = "c_b";
- final static String AO_TELEM_CAL_ACCEL_PLUS = "c_p";
- final static String AO_TELEM_CAL_ACCEL_MINUS = "c_m";
-
- /*
- * Kalman state values
- *
- * Name Value
- * k_h Height above pad (integer, meters)
- * k_s Vertical speeed (integer, m/s * 16)
- * k_a Vertical acceleration (integer, m/s² * 16)
- */
-
- final static String AO_TELEM_KALMAN_HEIGHT = "k_h";
- final static String AO_TELEM_KALMAN_SPEED = "k_s";
- final static String AO_TELEM_KALMAN_ACCEL = "k_a";
-
- /*
- * Ad-hoc flight values
- *
- * Name Value
- * a_a Acceleration (integer, sensor units)
- * a_s Speed (integer, integrated acceleration value)
- * a_b Barometer reading (integer, sensor units)
- */
-
- final static String AO_TELEM_ADHOC_ACCEL = "a_a";
- final static String AO_TELEM_ADHOC_SPEED = "a_s";
- final static String AO_TELEM_ADHOC_BARO = "a_b";
-
- /*
- * GPS values
- *
- * Name Value
- * g_s GPS state (string):
- * l locked
- * u unlocked
- * e error (missing or broken)
- * g_n Number of sats used in solution
- * g_ns Latitude (degrees * 10e7)
- * g_ew Longitude (degrees * 10e7)
- * g_a Altitude (integer meters)
- * g_Y GPS year (integer)
- * g_M GPS month (integer - 1-12)
- * g_D GPS day (integer - 1-31)
- * g_h GPS hour (integer - 0-23)
- * g_m GPS minute (integer - 0-59)
- * g_s GPS second (integer - 0-59)
- * g_v GPS vertical speed (integer, cm/sec)
- * g_s GPS horizontal speed (integer, cm/sec)
- * g_c GPS course (integer, 0-359)
- * g_hd GPS hdop (integer * 10)
- * g_vd GPS vdop (integer * 10)
- * g_he GPS h error (integer)
- * g_ve GPS v error (integer)
- */
-
- final static String AO_TELEM_GPS_STATE = "g";
- final static String AO_TELEM_GPS_STATE_LOCKED = "l";
- final static String AO_TELEM_GPS_STATE_UNLOCKED = "u";
- final static String AO_TELEM_GPS_STATE_ERROR = "e";
- final static String AO_TELEM_GPS_NUM_SAT = "g_n";
- final static String AO_TELEM_GPS_LATITUDE = "g_ns";
- final static String AO_TELEM_GPS_LONGITUDE = "g_ew";
- final static String AO_TELEM_GPS_ALTITUDE = "g_a";
- final static String AO_TELEM_GPS_YEAR = "g_Y";
- final static String AO_TELEM_GPS_MONTH = "g_M";
- final static String AO_TELEM_GPS_DAY = "g_D";
- final static String AO_TELEM_GPS_HOUR = "g_h";
- final static String AO_TELEM_GPS_MINUTE = "g_m";
- final static String AO_TELEM_GPS_SECOND = "g_s";
- final static String AO_TELEM_GPS_VERTICAL_SPEED = "g_v";
- final static String AO_TELEM_GPS_HORIZONTAL_SPEED = "g_g";
- final static String AO_TELEM_GPS_COURSE = "g_c";
- final static String AO_TELEM_GPS_HDOP = "g_hd";
- final static String AO_TELEM_GPS_VDOP = "g_vd";
- final static String AO_TELEM_GPS_HERROR = "g_he";
- final static String AO_TELEM_GPS_VERROR = "g_ve";
-
- /*
- * GPS satellite values
- *
- * Name Value
- * s_n Number of satellites reported (integer)
- * s_v0 Space vehicle ID (integer) for report 0
- * s_c0 C/N0 number (integer) for report 0
- * s_v1 Space vehicle ID (integer) for report 1
- * s_c1 C/N0 number (integer) for report 1
- * ...
- */
-
- final static String AO_TELEM_SAT_NUM = "s_n";
- final static String AO_TELEM_SAT_SVID = "s_v";
- final static String AO_TELEM_SAT_C_N_0 = "s_c";
-
- static public AltosRecord parse(String line, AltosRecord previous) throws ParseException, AltosCRCException {
- AltosTelemetryRecord r = AltosTelemetryRecord.parse(line);
-
- return r.update_state(previous);
+ if (word[i].equals("TELEM")) {
+ telem = parse_hex(word[i+1]);
+ } else {
+ telem = new AltosTelemetryLegacy(line);
+ }
+ return telem;
}
}
--- /dev/null
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+
+public class AltosTelemetryConfiguration extends AltosTelemetryStandard {
+ int device_type;
+ int flight;
+ int config_major;
+ int config_minor;
+ int apogee_delay;
+ int main_deploy;
+ int flight_log_max;
+ String callsign;
+ String version;
+
+ public AltosTelemetryConfiguration(int[] bytes) {
+ super(bytes);
+
+ device_type = uint8(5);
+ flight = uint16(6);
+ config_major = uint8(8);
+ config_minor = uint8(9);
+ apogee_delay = uint16(10);
+ main_deploy = uint16(12);
+ flight_log_max = uint16(14);
+ callsign = string(16, 8);
+ version = string(24, 8);
+ }
+
+ public void update_state(AltosState state) {
+ super.update_state(state);
+ state.set_device_type(device_type);
+ state.set_flight(flight);
+ state.set_config(config_major, config_minor, apogee_delay, main_deploy, flight_log_max);
+
+ state.set_callsign(callsign);
+ state.set_firmware_version(version);
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+import java.io.*;
+import java.util.*;
+import java.text.*;
+
+class AltosTelemetryIterator implements Iterator<AltosState> {
+ AltosState state;
+ Iterator<AltosTelemetry> telems;
+ AltosTelemetry next;
+ boolean seen;
+
+ public boolean hasNext() {
+ return !seen || telems.hasNext();
+ }
+
+ public AltosState next() {
+ if (seen) {
+ AltosState n = state.clone();
+ AltosTelemetry t = telems.next();
+
+ t.update_state(n);
+ state = n;
+ }
+ seen = true;
+ return state;
+ }
+
+ public void remove () {
+ }
+
+ public AltosTelemetryIterator(AltosState start, Iterator<AltosTelemetry> telems) {
+ this.state = start;
+ this.telems = telems;
+ this.seen = false;
+ }
+}
+
+public class AltosTelemetryFile extends AltosStateIterable {
+
+ AltosTelemetryIterable telems;
+ AltosState start;
+
+ public void write_comments(PrintStream out) {
+ }
+
+ public void write(PrintStream out) {
+
+ }
+
+ public AltosTelemetryFile(FileInputStream input) {
+ telems = new AltosTelemetryIterable(input);
+ start = new AltosState();
+
+ /* Find boost tick */
+ AltosState state = start.clone();
+
+ for (AltosTelemetry telem : telems) {
+ telem.update_state(state);
+ state.finish_update();
+ if (state.state != AltosLib.ao_flight_invalid && state.state >= AltosLib.ao_flight_boost) {
+ start.set_boost_tick(state.tick);
+ break;
+ }
+ }
+ }
+
+ public Iterator<AltosState> iterator() {
+ AltosState state = start.clone();
+ Iterator<AltosTelemetry> i = telems.iterator();
+
+ while (i.hasNext() && !state.valid()) {
+ AltosTelemetry t = i.next();
+ t.update_state(state);
+ state.finish_update();
+ }
+ return new AltosTelemetryIterator(state, i);
+ }
+}
\ No newline at end of file
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
import java.io.*;
import java.util.*;
import java.text.*;
-public class AltosTelemetryIterable extends AltosRecordIterable {
- TreeSet<AltosRecord> records;
+class AltosTelemetryOrdered implements Comparable<AltosTelemetryOrdered> {
+ AltosTelemetry telem;
+ int index;
+ int tick;
- public Iterator<AltosRecord> iterator () {
- return records.iterator();
+ public int compareTo(AltosTelemetryOrdered o) {
+ int tick_diff = tick - o.tick;
+
+ if (tick_diff != 0)
+ return tick_diff;
+ return index - o.index;
}
- boolean has_gps = false;
- boolean has_accel = false;
- boolean has_ignite = false;
- public boolean has_gps() { return has_gps; }
- public boolean has_accel() { return has_accel; }
- public boolean has_ignite() { return has_ignite; };
+ AltosTelemetryOrdered (AltosTelemetry telem, int index, int tick) {
+ this.telem = telem;
+ this.index = index;
+ this.tick = tick;
+ }
+}
- public AltosTelemetryIterable (FileInputStream input) {
- boolean saw_boost = false;
- int current_tick = 0;
- int boost_tick = 0;
+class AltosTelemetryOrderedIterator implements Iterator<AltosTelemetry> {
+ Iterator<AltosTelemetryOrdered> iterator;
+
+ public AltosTelemetryOrderedIterator(TreeSet<AltosTelemetryOrdered> telems) {
+ iterator = telems.iterator();
+ }
+
+ public boolean hasNext() {
+ return iterator.hasNext();
+ }
- AltosRecord previous = null;
- records = new TreeSet<AltosRecord> ();
+ public AltosTelemetry next() {
+ return iterator.next().telem;
+ }
+
+ public void remove () {
+ }
+}
+
+public class AltosTelemetryIterable implements Iterable<AltosTelemetry> {
+ TreeSet<AltosTelemetryOrdered> telems;
+ int tick;
+ int index;
+
+ public void add (AltosTelemetry telem) {
+ int t = telem.tick;
+ if (!telems.isEmpty()) {
+ while (t < tick - 1000)
+ t += 65536;
+ }
+ tick = t;
+ telems.add(new AltosTelemetryOrdered(telem, index++, tick));
+ }
+
+ public Iterator<AltosTelemetry> iterator () {
+ return new AltosTelemetryOrderedIterator(telems);
+ }
+
+ public AltosTelemetryIterable (FileInputStream input) {
+ telems = new TreeSet<AltosTelemetryOrdered> ();
+ tick = 0;
+ index = 0;
try {
for (;;) {
break;
}
try {
- AltosRecord record = AltosTelemetry.parse(line, previous);
- if (record == null)
+ AltosTelemetry telem = AltosTelemetry.parse(line);
+ if (telem == null)
break;
- if (records.isEmpty()) {
- current_tick = record.tick;
- } else {
- int tick = record.tick;
- while (tick < current_tick - 0x1000)
- tick += 0x10000;
- current_tick = tick;
- record.tick = current_tick;
- }
- if (!saw_boost && record.state >= AltosLib.ao_flight_boost)
- {
- saw_boost = true;
- boost_tick = record.tick;
- }
- if (record.acceleration() != AltosRecord.MISSING)
- has_accel = true;
- if (record.gps != null)
- has_gps = true;
- if (record.main_voltage() != AltosRecord.MISSING)
- has_ignite = true;
- if (previous != null && previous.tick != record.tick)
- records.add(previous);
- previous = record;
+ add(telem);
} catch (ParseException pe) {
System.out.printf("parse exception %s\n", pe.getMessage());
} catch (AltosCRCException ce) {
} catch (IOException io) {
System.out.printf("io exception\n");
}
-
- if (previous != null)
- records.add(previous);
-
- /* Adjust all tick counts to match expected eeprom values,
- * which starts with a 16-bit tick count 16 samples before boost
- */
-
- int tick_adjust = (boost_tick - 16) & 0xffff0000;
- for (AltosRecord r : this)
- r.tick -= tick_adjust;
- boost_tick -= tick_adjust;
-
- /* adjust all tick counts to be relative to boost time */
- for (AltosRecord r : this)
- r.time = (r.tick - boost_tick) / 100.0;
-
- try {
- input.close();
- } catch (IOException ie) {
- }
}
}
--- /dev/null
+/*
+ * Copyright © 2010 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+import java.text.*;
+
+/*
+ * Telemetry data contents
+ */
+
+
+/*
+ * The packet format is a simple hex dump of the raw telemetry frame.
+ * It starts with 'TELEM', then contains hex digits with a checksum as the last
+ * byte on the line.
+ *
+ * Version 4 is a replacement with consistent syntax. Each telemetry line
+ * contains a sequence of space-separated names and values, the values are
+ * either integers or strings. The names are all unique. All values are
+ * optional
+ *
+ * VERSION 4 c KD7SQG n 236 f 18 r -25 s pad t 513 r_a 15756 r_b 26444 r_t 20944
+ * r_v 26640 r_d 512 r_m 208 c_a 15775 c_b 26439 c_p 15749 c_m 16281 a_a 15764
+ * a_s 0 a_b 26439 g_s u g_n 0 s_n 0
+ *
+ * VERSION 4 c KD7SQG n 19 f 0 r -23 s pad t 513 r_b 26372 r_t 21292 r_v 26788
+ * r_d 136 r_m 140 c_b 26370 k_h 0 k_s 0 k_a 0
+ *
+ * General header fields
+ *
+ * Name Value
+ *
+ * VERSION Telemetry version number (4 or more). Must be first.
+ * c Callsign (string, no spaces allowed)
+ * n Flight unit serial number (integer)
+ * f Flight number (integer)
+ * r Packet RSSI value (integer)
+ * s Flight computer state (string, no spaces allowed)
+ * t Flight computer clock (integer in centiseconds)
+ *
+ * Version 3 is Version 2 with fixed RSSI numbers -- the radio reports
+ * in 1/2dB increments while this protocol provides only integers. So,
+ * the syntax didn't change just the interpretation of the RSSI
+ * values.
+ *
+ * Version 2 of the telemetry data stream is a bit of a mess, with no
+ * consistent formatting. In particular, the GPS data is formatted for
+ * viewing instead of parsing. However, the key feature is that every
+ * telemetry line contains all of the information necessary to
+ * describe the current rocket state, including the calibration values
+ * for accelerometer and barometer.
+ *
+ * GPS unlocked:
+ *
+ * VERSION 2 CALL KB0G SERIAL 51 FLIGHT 2 RSSI -68 STATUS ff STATE pad 1001 \
+ * a: 16032 p: 21232 t: 20284 v: 25160 d: 204 m: 204 fa: 16038 ga: 16032 fv: 0 \
+ * fp: 21232 gp: 21230 a+: 16049 a-: 16304 GPS 0 sat unlocked SAT 1 15 30
+ *
+ * GPS locked:
+ *
+ * VERSION 2 CALL KB0G SERIAL 51 FLIGHT 2 RSSI -71 STATUS ff STATE pad 2504 \
+ * a: 16028 p: 21220 t: 20360 v: 25004 d: 208 m: 200 fa: 16031 ga: 16032 fv: 330 \
+ * fp: 21231 gp: 21230 a+: 16049 a-: 16304 \
+ * GPS 9 sat 2010-02-13 17:16:51 35°20.0803'N 106°45.2235'W 1790m \
+ * 0.00m/s(H) 0° 0.00m/s(V) 1.0(hdop) 0(herr) 0(verr) \
+ * SAT 10 29 30 24 28 5 25 21 20 15 33 1 23 30 24 18 26 10 29 2 26
+ *
+ */
+
+public class AltosTelemetryLegacy extends AltosTelemetry {
+ /*
+ * General header fields
+ *
+ * Name Value
+ *
+ * VERSION Telemetry version number (4 or more). Must be first.
+ * c Callsign (string, no spaces allowed)
+ * n Flight unit serial number (integer)
+ * f Flight number (integer)
+ * r Packet RSSI value (integer)
+ * s Flight computer state (string, no spaces allowed)
+ * t Flight computer clock (integer in centiseconds)
+ */
+
+ final static String AO_TELEM_VERSION = "VERSION";
+ final static String AO_TELEM_CALL = "c";
+ final static String AO_TELEM_SERIAL = "n";
+ final static String AO_TELEM_FLIGHT = "f";
+ final static String AO_TELEM_RSSI = "r";
+ final static String AO_TELEM_STATE = "s";
+ final static String AO_TELEM_TICK = "t";
+
+ /*
+ * Raw sensor values
+ *
+ * Name Value
+ * r_a Accelerometer reading (integer)
+ * r_b Barometer reading (integer)
+ * r_t Thermometer reading (integer)
+ * r_v Battery reading (integer)
+ * r_d Drogue continuity (integer)
+ * r_m Main continuity (integer)
+ */
+
+ final static String AO_TELEM_RAW_ACCEL = "r_a";
+ final static String AO_TELEM_RAW_BARO = "r_b";
+ final static String AO_TELEM_RAW_THERMO = "r_t";
+ final static String AO_TELEM_RAW_BATT = "r_v";
+ final static String AO_TELEM_RAW_DROGUE = "r_d";
+ final static String AO_TELEM_RAW_MAIN = "r_m";
+
+ /*
+ * Sensor calibration values
+ *
+ * Name Value
+ * c_a Ground accelerometer reading (integer)
+ * c_b Ground barometer reading (integer)
+ * c_p Accelerometer reading for +1g
+ * c_m Accelerometer reading for -1g
+ */
+
+ final static String AO_TELEM_CAL_ACCEL_GROUND = "c_a";
+ final static String AO_TELEM_CAL_BARO_GROUND = "c_b";
+ final static String AO_TELEM_CAL_ACCEL_PLUS = "c_p";
+ final static String AO_TELEM_CAL_ACCEL_MINUS = "c_m";
+
+ /*
+ * Kalman state values
+ *
+ * Name Value
+ * k_h Height above pad (integer, meters)
+ * k_s Vertical speeed (integer, m/s * 16)
+ * k_a Vertical acceleration (integer, m/s² * 16)
+ */
+
+ final static String AO_TELEM_KALMAN_HEIGHT = "k_h";
+ final static String AO_TELEM_KALMAN_SPEED = "k_s";
+ final static String AO_TELEM_KALMAN_ACCEL = "k_a";
+
+ /*
+ * Ad-hoc flight values
+ *
+ * Name Value
+ * a_a Acceleration (integer, sensor units)
+ * a_s Speed (integer, integrated acceleration value)
+ * a_b Barometer reading (integer, sensor units)
+ */
+
+ final static String AO_TELEM_ADHOC_ACCEL = "a_a";
+ final static String AO_TELEM_ADHOC_SPEED = "a_s";
+ final static String AO_TELEM_ADHOC_BARO = "a_b";
+
+ /*
+ * GPS values
+ *
+ * Name Value
+ * g_s GPS state (string):
+ * l locked
+ * u unlocked
+ * e error (missing or broken)
+ * g_n Number of sats used in solution
+ * g_ns Latitude (degrees * 10e7)
+ * g_ew Longitude (degrees * 10e7)
+ * g_a Altitude (integer meters)
+ * g_Y GPS year (integer)
+ * g_M GPS month (integer - 1-12)
+ * g_D GPS day (integer - 1-31)
+ * g_h GPS hour (integer - 0-23)
+ * g_m GPS minute (integer - 0-59)
+ * g_s GPS second (integer - 0-59)
+ * g_v GPS vertical speed (integer, cm/sec)
+ * g_s GPS horizontal speed (integer, cm/sec)
+ * g_c GPS course (integer, 0-359)
+ * g_hd GPS hdop (integer * 10)
+ * g_vd GPS vdop (integer * 10)
+ * g_he GPS h error (integer)
+ * g_ve GPS v error (integer)
+ */
+
+ final static String AO_TELEM_GPS_STATE = "g";
+ final static String AO_TELEM_GPS_STATE_LOCKED = "l";
+ final static String AO_TELEM_GPS_STATE_UNLOCKED = "u";
+ final static String AO_TELEM_GPS_STATE_ERROR = "e";
+ final static String AO_TELEM_GPS_NUM_SAT = "g_n";
+ final static String AO_TELEM_GPS_LATITUDE = "g_ns";
+ final static String AO_TELEM_GPS_LONGITUDE = "g_ew";
+ final static String AO_TELEM_GPS_ALTITUDE = "g_a";
+ final static String AO_TELEM_GPS_YEAR = "g_Y";
+ final static String AO_TELEM_GPS_MONTH = "g_M";
+ final static String AO_TELEM_GPS_DAY = "g_D";
+ final static String AO_TELEM_GPS_HOUR = "g_h";
+ final static String AO_TELEM_GPS_MINUTE = "g_m";
+ final static String AO_TELEM_GPS_SECOND = "g_s";
+ final static String AO_TELEM_GPS_VERTICAL_SPEED = "g_v";
+ final static String AO_TELEM_GPS_HORIZONTAL_SPEED = "g_g";
+ final static String AO_TELEM_GPS_COURSE = "g_c";
+ final static String AO_TELEM_GPS_HDOP = "g_hd";
+ final static String AO_TELEM_GPS_VDOP = "g_vd";
+ final static String AO_TELEM_GPS_HERROR = "g_he";
+ final static String AO_TELEM_GPS_VERROR = "g_ve";
+
+ /*
+ * GPS satellite values
+ *
+ * Name Value
+ * s_n Number of satellites reported (integer)
+ * s_v0 Space vehicle ID (integer) for report 0
+ * s_c0 C/N0 number (integer) for report 0
+ * s_v1 Space vehicle ID (integer) for report 1
+ * s_c1 C/N0 number (integer) for report 1
+ * ...
+ */
+
+ final static String AO_TELEM_SAT_NUM = "s_n";
+ final static String AO_TELEM_SAT_SVID = "s_v";
+ final static String AO_TELEM_SAT_C_N_0 = "s_c";
+
+ public int version;
+ public String callsign;
+ public int flight;
+ public int state;
+
+ public AltosGPS gps;
+ public int gps_sequence;
+
+ /* Telemetry sources have these values recorded from the flight computer */
+ public double kalman_height;
+ public double kalman_speed;
+ public double kalman_acceleration;
+
+ /* Sensor values */
+ public int accel;
+ public int pres;
+ public int temp;
+ public int batt;
+ public int apogee;
+ public int main;
+
+ public int ground_accel;
+ public int ground_pres;
+ public int accel_plus_g;
+ public int accel_minus_g;
+
+ public int flight_accel;
+ public int flight_vel;
+ public int flight_pres;
+
+ private void parse_v4(String[] words, int i) throws ParseException {
+ AltosTelemetryMap map = new AltosTelemetryMap(words, i);
+
+ callsign = map.get_string(AO_TELEM_CALL, "N0CALL");
+ serial = map.get_int(AO_TELEM_SERIAL, AltosLib.MISSING);
+ flight = map.get_int(AO_TELEM_FLIGHT, AltosLib.MISSING);
+ rssi = map.get_int(AO_TELEM_RSSI, AltosLib.MISSING);
+ state = AltosLib.state(map.get_string(AO_TELEM_STATE, "invalid"));
+ tick = map.get_int(AO_TELEM_TICK, 0);
+
+ /* raw sensor values */
+ accel = map.get_int(AO_TELEM_RAW_ACCEL, AltosLib.MISSING);
+ pres = map.get_int(AO_TELEM_RAW_BARO, AltosLib.MISSING);
+ temp = map.get_int(AO_TELEM_RAW_THERMO, AltosLib.MISSING);
+ batt = map.get_int(AO_TELEM_RAW_BATT, AltosLib.MISSING);
+ apogee = map.get_int(AO_TELEM_RAW_DROGUE, AltosLib.MISSING);
+ main = map.get_int(AO_TELEM_RAW_MAIN, AltosLib.MISSING);
+
+ /* sensor calibration information */
+ ground_accel = map.get_int(AO_TELEM_CAL_ACCEL_GROUND, AltosLib.MISSING);
+ ground_pres = map.get_int(AO_TELEM_CAL_BARO_GROUND, AltosLib.MISSING);
+ accel_plus_g = map.get_int(AO_TELEM_CAL_ACCEL_PLUS, AltosLib.MISSING);
+ accel_minus_g = map.get_int(AO_TELEM_CAL_ACCEL_MINUS, AltosLib.MISSING);
+
+ /* flight computer values */
+ kalman_acceleration = map.get_double(AO_TELEM_KALMAN_ACCEL, AltosLib.MISSING, 1/16.0);
+ kalman_speed = map.get_double(AO_TELEM_KALMAN_SPEED, AltosLib.MISSING, 1/16.0);
+ kalman_height = map.get_int(AO_TELEM_KALMAN_HEIGHT, AltosLib.MISSING);
+
+ flight_accel = map.get_int(AO_TELEM_ADHOC_ACCEL, AltosLib.MISSING);
+ flight_vel = map.get_int(AO_TELEM_ADHOC_SPEED, AltosLib.MISSING);
+ flight_pres = map.get_int(AO_TELEM_ADHOC_BARO, AltosLib.MISSING);
+
+ if (map.has(AO_TELEM_GPS_STATE))
+ gps = new AltosGPS(map);
+ else
+ gps = null;
+ }
+
+ private void parse_legacy(String[] words, int i) throws ParseException {
+
+ AltosParse.word (words[i++], "CALL");
+ callsign = words[i++];
+
+ AltosParse.word (words[i++], "SERIAL");
+ serial = AltosParse.parse_int(words[i++]);
+
+ if (version >= 2) {
+ AltosParse.word (words[i++], "FLIGHT");
+ flight = AltosParse.parse_int(words[i++]);
+ } else
+ flight = 0;
+
+ AltosParse.word(words[i++], "RSSI");
+ rssi = AltosParse.parse_int(words[i++]);
+
+ /* Older telemetry data had mis-computed RSSI value */
+ if (version <= 2)
+ rssi = (rssi + 74) / 2 - 74;
+
+ AltosParse.word(words[i++], "STATUS");
+ status = AltosParse.parse_hex(words[i++]);
+
+ AltosParse.word(words[i++], "STATE");
+ state = AltosLib.state(words[i++]);
+
+ tick = AltosParse.parse_int(words[i++]);
+
+ AltosParse.word(words[i++], "a:");
+ accel = AltosParse.parse_int(words[i++]);
+
+ AltosParse.word(words[i++], "p:");
+ pres = AltosParse.parse_int(words[i++]);
+
+ AltosParse.word(words[i++], "t:");
+ temp = AltosParse.parse_int(words[i++]);
+
+ AltosParse.word(words[i++], "v:");
+ batt = AltosParse.parse_int(words[i++]);
+
+ AltosParse.word(words[i++], "d:");
+ apogee = AltosParse.parse_int(words[i++]);
+
+ AltosParse.word(words[i++], "m:");
+ main = AltosParse.parse_int(words[i++]);
+
+ AltosParse.word(words[i++], "fa:");
+ flight_accel = AltosParse.parse_int(words[i++]);
+
+ AltosParse.word(words[i++], "ga:");
+ ground_accel = AltosParse.parse_int(words[i++]);
+
+ AltosParse.word(words[i++], "fv:");
+ flight_vel = AltosParse.parse_int(words[i++]);
+
+ AltosParse.word(words[i++], "fp:");
+ flight_pres = AltosParse.parse_int(words[i++]);
+
+ /* Old TeleDongle code with kalman-reporting TeleMetrum code */
+ if ((flight_vel & 0xffff0000) == 0x80000000) {
+ kalman_speed = ((short) flight_vel) / 16.0;
+ kalman_acceleration = flight_accel / 16.0;
+ kalman_height = flight_pres;
+ flight_vel = AltosLib.MISSING;
+ flight_pres = AltosLib.MISSING;
+ flight_accel = AltosLib.MISSING;
+ } else {
+ kalman_speed = AltosLib.MISSING;
+ kalman_acceleration = AltosLib.MISSING;
+ kalman_height = AltosLib.MISSING;
+ }
+
+ AltosParse.word(words[i++], "gp:");
+ ground_pres = AltosParse.parse_int(words[i++]);
+
+ if (version >= 1) {
+ AltosParse.word(words[i++], "a+:");
+ accel_plus_g = AltosParse.parse_int(words[i++]);
+
+ AltosParse.word(words[i++], "a-:");
+ accel_minus_g = AltosParse.parse_int(words[i++]);
+ } else {
+ accel_plus_g = ground_accel;
+ accel_minus_g = ground_accel + 530;
+ }
+
+ gps = new AltosGPS(words, i, version);
+ gps_sequence++;
+ }
+
+ public AltosTelemetryLegacy(String line) throws ParseException, AltosCRCException {
+ String[] words = line.split("\\s+");
+ int i = 0;
+
+ if (words[i].equals("CRC") && words[i+1].equals("INVALID")) {
+ i += 2;
+ AltosParse.word(words[i++], "RSSI");
+ rssi = AltosParse.parse_int(words[i++]);
+ throw new AltosCRCException(rssi);
+ }
+ if (words[i].equals("CALL")) {
+ version = 0;
+ } else {
+ AltosParse.word (words[i++], "VERSION");
+ version = AltosParse.parse_int(words[i++]);
+ }
+
+ if (version < 4)
+ parse_legacy(words, i);
+ else
+ parse_v4(words, i);
+ }
+
+ /*
+ * Given a hex dump of a legacy telemetry line, construct an AltosRecordTM from that
+ */
+
+ int[] bytes;
+ int adjust;
+
+ /*
+ private int int8(int i) {
+ return AltosLib.int8(bytes, i + 1 + adjust);
+ }
+ */
+ private int uint8(int i) {
+ return AltosLib.uint8(bytes, i + 1 + adjust);
+ }
+ private int int16(int i) {
+ return AltosLib.int16(bytes, i + 1 + adjust);
+ }
+ private int uint16(int i) {
+ return AltosLib.uint16(bytes, i + 1 + adjust);
+ }
+ private int uint32(int i) {
+ return AltosLib.uint32(bytes, i + 1 + adjust);
+ }
+ private String string(int i, int l) {
+ return AltosLib.string(bytes, i + 1 + adjust, l);
+ }
+
+ static final int AO_GPS_NUM_SAT_MASK = (0xf << 0);
+ static final int AO_GPS_NUM_SAT_SHIFT = (0);
+
+ static final int AO_GPS_VALID = (1 << 4);
+ static final int AO_GPS_RUNNING = (1 << 5);
+ static final int AO_GPS_DATE_VALID = (1 << 6);
+ static final int AO_GPS_COURSE_VALID = (1 << 7);
+
+ public AltosTelemetryLegacy(int[] in_bytes) {
+ bytes = in_bytes;
+ version = 4;
+ adjust = 0;
+
+ if (bytes.length == AltosLib.ao_telemetry_0_8_len + 4) {
+ serial = uint8(0);
+ adjust = -1;
+ } else
+ serial = uint16(0);
+
+ callsign = string(62, 8);
+ flight = uint16(2);
+ state = uint8(4);
+ tick = uint16(21);
+ accel = int16(23);
+ pres = int16(25);
+ temp = int16(27);
+ batt = int16(29);
+ apogee = int16(31);
+ main = int16(33);
+
+ ground_accel = int16(7);
+ ground_pres = int16(15);
+ accel_plus_g = int16(17);
+ accel_minus_g = int16(19);
+
+ if (uint16(11) == 0x8000) {
+ kalman_acceleration = int16(5);
+ kalman_speed = int16(9);
+ kalman_height = int16(13);
+ flight_accel = AltosLib.MISSING;
+ flight_vel = AltosLib.MISSING;
+ flight_pres = AltosLib.MISSING;
+ } else {
+ flight_accel = int16(5);
+ flight_vel = uint32(9);
+ flight_pres = int16(13);
+ kalman_acceleration = AltosLib.MISSING;
+ kalman_speed = AltosLib.MISSING;
+ kalman_height = AltosLib.MISSING;
+ }
+
+ gps = null;
+
+ int gps_flags = uint8(41);
+
+ if ((gps_flags & (AO_GPS_VALID|AO_GPS_RUNNING)) != 0) {
+ gps = new AltosGPS();
+ gps_sequence++;
+
+ gps.nsat = (gps_flags & AO_GPS_NUM_SAT_MASK);
+ gps.locked = (gps_flags & AO_GPS_VALID) != 0;
+ gps.connected = true;
+ gps.lat = uint32(42) / 1.0e7;
+ gps.lon = uint32(46) / 1.0e7;
+ gps.alt = int16(50);
+ gps.ground_speed = uint16(52) / 100.0;
+ gps.course = uint8(54) * 2;
+ gps.hdop = uint8(55) / 5.0;
+ gps.h_error = uint16(58);
+ gps.v_error = uint16(60);
+
+ int n_tracking_reported = uint8(70);
+ if (n_tracking_reported > 12)
+ n_tracking_reported = 12;
+ int n_tracking_actual = 0;
+ for (int i = 0; i < n_tracking_reported; i++) {
+ if (uint8(71 + i*2) != 0)
+ n_tracking_actual++;
+ }
+ if (n_tracking_actual > 0) {
+ gps.cc_gps_sat = new AltosGPSSat[n_tracking_actual];
+
+ n_tracking_actual = 0;
+ for (int i = 0; i < n_tracking_reported; i++) {
+ int svid = uint8(71 + i*2);
+ int c_n0 = uint8(72 + i*2);
+ if (svid != 0)
+ gps.cc_gps_sat[n_tracking_actual++] = new AltosGPSSat(svid, c_n0);
+ }
+ }
+ }
+ }
+
+ public void update_state(AltosState state) {
+ state.set_tick(tick);
+ state.set_state(this.state);
+ state.set_flight(flight);
+ state.set_serial(serial);
+ state.set_rssi(rssi, status);
+
+ state.set_pressure(AltosConvert.barometer_to_pressure(pres));
+ state.set_accel_g(accel_plus_g, accel_minus_g);
+ state.set_accel(accel);
+ if (kalman_height != AltosLib.MISSING)
+ state.set_kalman(kalman_height, kalman_speed, kalman_acceleration);
+ state.set_temperature(AltosConvert.thermometer_to_temperature(temp));
+ state.set_battery_voltage(AltosConvert.cc_battery_to_voltage(batt));
+ state.set_apogee_voltage(AltosConvert.cc_ignitor_to_voltage(apogee));
+ state.set_main_voltage(AltosConvert.cc_ignitor_to_voltage(main));
+ if (gps != null)
+ state.set_gps(gps, gps_sequence);
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+
+public class AltosTelemetryLocation extends AltosTelemetryStandard {
+ int flags;
+ int altitude;
+ int latitude;
+ int longitude;
+ int year;
+ int month;
+ int day;
+ int hour;
+ int minute;
+ int second;
+ int pdop;
+ int hdop;
+ int vdop;
+ int mode;
+ int ground_speed;
+ int climb_rate;
+ int course;
+
+ public AltosTelemetryLocation(int[] bytes) {
+ super(bytes);
+
+ flags = uint8(5);
+ altitude = int16(6);
+ latitude = uint32(8);
+ longitude = uint32(12);
+ year = uint8(16);
+ month = uint8(17);
+ day = uint8(18);
+ hour = uint8(19);
+ minute = uint8(20);
+ second = uint8(21);
+ pdop = uint8(22);
+ hdop = uint8(23);
+ vdop = uint8(24);
+ mode = uint8(25);
+ ground_speed = uint16(26);
+ climb_rate = int16(28);
+ course = uint8(30);
+ }
+
+ public void update_state(AltosState state) {
+ super.update_state(state);
+ AltosGPS gps = state.make_temp_gps(false);
+
+ gps.nsat = flags & 0xf;
+ gps.locked = (flags & (1 << 4)) != 0;
+ gps.connected = (flags & (1 << 5)) != 0;
+
+ if (gps.locked) {
+ gps.lat = latitude * 1.0e-7;
+ gps.lon = longitude * 1.0e-7;
+ gps.alt = altitude;
+ gps.year = 2000 + year;
+ gps.month = month;
+ gps.day = day;
+ gps.hour = hour;
+ gps.minute = minute;
+ gps.second = second;
+ gps.ground_speed = ground_speed * 1.0e-2;
+ gps.course = course * 2;
+ gps.climb_rate = climb_rate * 1.0e-2;
+ gps.hdop = hdop;
+ gps.vdop = vdop;
+ }
+ state.set_temp_gps();
+ }
+}
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
import java.text.*;
import java.util.HashMap;
--- /dev/null
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+public class AltosTelemetryMegaData extends AltosTelemetryStandard {
+ int state;
+
+ int v_batt;
+ int v_pyro;
+ int sense[];
+
+ int ground_pres;
+ int ground_accel;
+ int accel_plus_g;
+ int accel_minus_g;
+
+ int acceleration;
+ int speed;
+ int height;
+
+ public AltosTelemetryMegaData(int[] bytes) {
+ super(bytes);
+
+ state = int8(5);
+
+ v_batt = int16(6);
+ v_pyro = int16(8);
+
+ sense = new int[6];
+
+ for (int i = 0; i < 6; i++) {
+ sense[i] = int8(10 + i) << 4;
+ sense[i] |= sense[i] >> 8;
+ }
+
+ ground_pres = int32(16);
+ ground_accel = int16(20);
+ accel_plus_g = int16(22);
+ accel_minus_g = int16(24);
+
+ acceleration = int16(26);
+ speed = int16(28);
+ height = int16(30);
+ }
+
+ public void update_state(AltosState state) {
+ super.update_state(state);
+
+ state.set_state(this.state);
+
+ state.set_battery_voltage(AltosConvert.mega_battery_voltage(v_batt));
+ state.set_pyro_voltage(AltosConvert.mega_pyro_voltage(v_pyro));
+
+ state.set_apogee_voltage(AltosConvert.mega_pyro_voltage(sense[4]));
+ state.set_main_voltage(AltosConvert.mega_pyro_voltage(sense[5]));
+
+ double voltages[] = new double[4];
+ for (int i = 0; i < 4; i++)
+ voltages[i] = AltosConvert.mega_pyro_voltage(sense[i]);
+
+ state.set_ignitor_voltage(voltages);
+
+ state.set_ground_accel(ground_accel);
+ state.set_ground_pressure(ground_pres);
+ state.set_accel_g(accel_plus_g, accel_minus_g);
+
+ state.set_kalman(height, speed/16.0, acceleration / 16.0);
+ }
+}
+
--- /dev/null
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+public class AltosTelemetryMegaSensor extends AltosTelemetryStandard {
+ int accel;
+ int pres;
+ int temp;
+
+ int accel_x;
+ int accel_y;
+ int accel_z;
+
+ int gyro_x;
+ int gyro_y;
+ int gyro_z;
+
+ int mag_x;
+ int mag_y;
+ int mag_z;
+
+ public AltosTelemetryMegaSensor(int[] bytes) {
+ super(bytes);
+
+ accel = int16(6);
+ pres = int32(8);
+ temp = int16(12);
+
+ accel_x = int16(14);
+ accel_y = int16(16);
+ accel_z = int16(18);
+
+ gyro_x = int16(20);
+ gyro_y = int16(22);
+ gyro_z = int16(24);
+
+ mag_x = int16(26);
+ mag_y = int16(28);
+ mag_z = int16(30);
+ }
+
+ public void update_state(AltosState state) {
+ super.update_state(state);
+
+ state.set_accel(accel);
+ state.set_pressure(pres);
+ state.set_temperature(temp / 100.0);
+
+ AltosIMU imu = new AltosIMU();
+
+ imu.accel_x = accel_x;
+ imu.accel_y = accel_y;
+ imu.accel_z = accel_z;
+
+ imu.gyro_x = gyro_x;
+ imu.gyro_y = gyro_y;
+ imu.gyro_z = gyro_z;
+
+ state.imu = imu;
+
+ AltosMag mag = new AltosMag();
+
+ mag.x = mag_x;
+ mag.y = mag_y;
+ mag.z = mag_z;
+
+ state.mag = mag;
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+
+public class AltosTelemetryMetrumData extends AltosTelemetryStandard {
+
+ int ground_pres;
+ int ground_accel;
+ int accel_plus_g;
+ int accel_minus_g;
+
+ public AltosTelemetryMetrumData(int[] bytes) {
+ super(bytes);
+
+ ground_pres = int32(8);
+ ground_accel = int16(12);
+ accel_plus_g = int16(14);
+ accel_minus_g = int16(16);
+ }
+
+ public void update_state(AltosState state) {
+ state.set_ground_accel(ground_accel);
+ state.set_accel_g(accel_plus_g, accel_minus_g);
+ state.set_ground_pressure(ground_pres);
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+
+public class AltosTelemetryMetrumSensor extends AltosTelemetryStandard {
+ int state;
+
+ int accel;
+ int pres;
+ int temp;
+
+ int acceleration;
+ int speed;
+ int height;
+
+ int v_batt;
+ int sense_a;
+ int sense_m;
+
+ public AltosTelemetryMetrumSensor(int[] bytes) {
+ super(bytes);
+
+ state = int8(5);
+ accel = int16(6);
+ pres = int32(8);
+ temp = int16(12);
+
+ acceleration = int16(14);
+ speed = int16(16);
+ height = int16(18);
+
+ v_batt = int16(20);
+ sense_a = int16(22);
+ sense_m = int16(24);
+ }
+
+ public void update_state(AltosState state) {
+ super.update_state(state);
+
+ state.set_state(this.state);
+
+ state.set_accel(accel);
+ state.set_pressure(pres);
+ state.set_temperature(temp/100.0);
+
+ state.set_kalman(height, speed/16.0, acceleration/16.0);
+
+ state.set_battery_voltage(AltosConvert.mega_battery_voltage(v_batt));
+
+ state.set_apogee_voltage(AltosConvert.mega_pyro_voltage(sense_a));
+ state.set_main_voltage(AltosConvert.mega_pyro_voltage(sense_m));
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+
+public class AltosTelemetryMini extends AltosTelemetryStandard {
+ int state;
+
+ int v_batt;
+ int sense_a;
+ int sense_m;
+
+ int pres;
+ int temp;
+
+ int acceleration;
+ int speed;
+ int height;
+
+ int ground_pres;
+
+ public AltosTelemetryMini(int[] bytes) {
+ super(bytes);
+
+ state = int8(5);
+
+ v_batt = int16(6);
+ sense_a = int16(8);
+ sense_m = int16(10);
+
+ pres = int32(12);
+ temp = int16(16);
+
+ acceleration = int16(18);
+ speed = int16(20);
+ height = int16(22);
+
+ ground_pres = int32(24);
+ }
+
+ public void update_state(AltosState state) {
+ super.update_state(state);
+
+ state.set_state(this.state);
+
+ state.set_battery_voltage(AltosConvert.tele_mini_voltage(v_batt));
+ state.set_apogee_voltage(AltosConvert.tele_mini_voltage(sense_a));
+ state.set_main_voltage(AltosConvert.tele_mini_voltage(sense_m));
+
+ state.set_ground_pressure(ground_pres);
+
+ state.set_pressure(pres);
+ state.set_temperature(temp/100.0);
+
+ state.set_kalman(height, speed/16.0, acceleration/16.0);
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+public class AltosTelemetryRaw extends AltosTelemetryStandard {
+ public AltosTelemetryRaw(int[] bytes) {
+ super(bytes);
+ }
+
+ public void update_state(AltosState state) {
+ super.update_state(state);
+ }
+}
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
import java.text.*;
import java.io.*;
public class AltosTelemetryReader extends AltosFlightReader {
AltosLink link;
AltosLog log;
- AltosRecord previous;
double frequency;
int telemetry;
+ AltosState state = null;
LinkedBlockingQueue<AltosLine> telem;
- public AltosRecord read() throws InterruptedException, ParseException, AltosCRCException, IOException {
+ public AltosState read() throws InterruptedException, ParseException, AltosCRCException, IOException {
AltosLine l = telem.take();
if (l.line == null)
throw new IOException("IO error");
- AltosRecord next = AltosTelemetry.parse(l.line, previous);
- previous = next;
- return next;
+ AltosTelemetry telem = AltosTelemetry.parse(l.line);
+ if (state == null)
+ state = new AltosState();
+ else
+ state = state.clone();
+ telem.update_state(state);
+ return state;
}
public void flush() {
}
public void reset() {
- previous = null;
flush();
}
public void close(boolean interrupted) {
link.remove_monitor(telem);
log.close();
- link.close();
+ try {
+ link.close();
+ } catch (InterruptedException ie) {
+ }
}
public void set_frequency(double in_frequency) throws InterruptedException, TimeoutException {
else
return false;
} catch (InterruptedException ie) {
- return true;
+ return false;
} catch (TimeoutException te) {
return true;
}
return link.has_monitor_battery();
}
- public double monitor_battery() {
+ public double monitor_battery() throws InterruptedException {
return link.monitor_battery();
}
public AltosTelemetryReader (AltosLink in_link)
throws IOException, InterruptedException, TimeoutException {
link = in_link;
+ boolean success = false;
try {
log = new AltosLog(link);
name = link.name;
- previous = null;
telem = new LinkedBlockingQueue<AltosLine>();
frequency = AltosPreferences.frequency(link.serial);
set_frequency(frequency);
telemetry = AltosPreferences.telemetry(link.serial);
set_telemetry(telemetry);
link.add_monitor(telem);
- } catch (TimeoutException e) {
- close(true);
- throw(e);
- } catch (InterruptedException e) {
- close(true);
- throw(e);
+ success = true;
+ } finally {
+ if (!success)
+ close(true);
}
}
}
+++ /dev/null
-/*
- * Copyright © 2011 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-package org.altusmetrum.altoslib_1;
-import java.text.*;
-
-public abstract class AltosTelemetryRecord {
-
- long received_time;
- abstract public AltosRecord update_state(AltosRecord previous);
-
- static boolean cksum(int[] bytes) {
- int sum = 0x5a;
- for (int i = 1; i < bytes.length - 1; i++)
- sum += bytes[i];
- sum &= 0xff;
- return sum == bytes[bytes.length - 1];
- }
-
- final static int PKT_APPEND_STATUS_1_CRC_OK = (1 << 7);
- final static int PKT_APPEND_STATUS_1_LQI_MASK = (0x7f);
- final static int PKT_APPEND_STATUS_1_LQI_SHIFT = 0;
-
- final static int packet_type_TM_sensor = 0x01;
- final static int packet_type_Tm_sensor = 0x02;
- final static int packet_type_Tn_sensor = 0x03;
- final static int packet_type_configuration = 0x04;
- final static int packet_type_location = 0x05;
- final static int packet_type_satellite = 0x06;
- final static int packet_type_companion = 0x07;
- final static int packet_type_MM_sensor = 0x08;
- final static int packet_type_MM_data = 0x09;
-
- static AltosTelemetryRecord parse_hex(String hex) throws ParseException, AltosCRCException {
- AltosTelemetryRecord r;
-
- int[] bytes;
- try {
- bytes = AltosLib.hexbytes(hex);
- } catch (NumberFormatException ne) {
- throw new ParseException(ne.getMessage(), 0);
- }
-
- /* one for length, one for checksum */
- if (bytes[0] != bytes.length - 2)
- throw new ParseException(String.format("invalid length %d != %d\n",
- bytes[0],
- bytes.length - 2), 0);
- if (!cksum(bytes))
- throw new ParseException(String.format("invalid line \"%s\"", hex), 0);
-
- int rssi = AltosLib.int8(bytes, bytes.length - 3) / 2 - 74;
- int status = AltosLib.uint8(bytes, bytes.length - 2);
-
- if ((status & PKT_APPEND_STATUS_1_CRC_OK) == 0)
- throw new AltosCRCException(rssi);
-
- /* length, data ..., rssi, status, checksum -- 4 bytes extra */
- switch (bytes.length) {
- case AltosLib.ao_telemetry_standard_len + 4:
- int type = AltosLib.uint8(bytes, 4 + 1);
- switch (type) {
- case packet_type_TM_sensor:
- case packet_type_Tm_sensor:
- case packet_type_Tn_sensor:
- r = new AltosTelemetryRecordSensor(bytes, rssi);
- break;
- case packet_type_configuration:
- r = new AltosTelemetryRecordConfiguration(bytes, rssi);
- break;
- case packet_type_location:
- r = new AltosTelemetryRecordLocation(bytes, rssi);
- break;
- case packet_type_satellite:
- r = new AltosTelemetryRecordSatellite(bytes, rssi);
- break;
- case packet_type_companion:
- r = new AltosTelemetryRecordCompanion(bytes, rssi);
- break;
- case packet_type_MM_sensor:
- r = new AltosTelemetryRecordMegaSensor(bytes, rssi);
- break;
- case packet_type_MM_data:
- r = new AltosTelemetryRecordMegaData(bytes, rssi);
- break;
- default:
- r = new AltosTelemetryRecordRaw(bytes, rssi);
- break;
- }
- break;
- case AltosLib.ao_telemetry_0_9_len + 4:
- r = new AltosTelemetryRecordLegacy(bytes, rssi, status);
- break;
- case AltosLib.ao_telemetry_0_8_len + 4:
- r = new AltosTelemetryRecordLegacy(bytes, rssi, status);
- break;
- default:
- throw new ParseException(String.format("Invalid packet length %d", bytes.length), 0);
- }
- r.received_time = System.currentTimeMillis();
- return r;
- }
-
- public static AltosTelemetryRecord parse(String line) throws ParseException, AltosCRCException {
- AltosTelemetryRecord r;
-
- String[] word = line.split("\\s+");
- int i =0;
- if (word[i].equals("CRC") && word[i+1].equals("INVALID")) {
- i += 2;
- AltosParse.word(word[i++], "RSSI");
- throw new AltosCRCException(AltosParse.parse_int(word[i++]));
- }
-
- if (word[i].equals("TELEM"))
- r = parse_hex(word[i+1]);
- else
- r = new AltosTelemetryRecordLegacy(line);
- return r;
- }
-}
+++ /dev/null
-/*
- * Copyright © 2011 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-package org.altusmetrum.altoslib_1;
-
-public class AltosTelemetryRecordCompanion extends AltosTelemetryRecordRaw {
-
- AltosRecordCompanion companion;
-
- public AltosTelemetryRecordCompanion(int[] in_bytes, int rssi) {
- super(in_bytes, rssi);
-
- int off = 0;
- if (uint8(6) == 0)
- off = 1;
- int channels = uint8(7+off);
-
- if (off != 0 && channels >= 12)
- channels = 11;
-
- companion = new AltosRecordCompanion(channels);
- companion.tick = tick;
- companion.board_id = uint8(5);
- companion.update_period = uint8(6+off);
- for (int i = 0; i < companion.companion_data.length; i++)
- companion.companion_data[i] = uint16(8 + off + i * 2);
- }
-
- public AltosRecord update_state(AltosRecord previous) {
- AltosRecord next = super.update_state(previous);
-
- next.companion = companion;
- next.seen |= AltosRecord.seen_sensor | AltosRecord.seen_temp_volt;
-
- companion.tick = tick;
- return next;
- }
-}
+++ /dev/null
-/*
- * Copyright © 2011 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-package org.altusmetrum.altoslib_1;
-
-
-public class AltosTelemetryRecordConfiguration extends AltosTelemetryRecordRaw {
- int device_type;
- int flight;
- int config_major;
- int config_minor;
- int apogee_delay;
- int main_deploy;
- int flight_log_max;
- String callsign;
- String version;
-
- public AltosTelemetryRecordConfiguration(int[] in_bytes, int rssi) {
- super(in_bytes, rssi);
-
- device_type = uint8(5);
- flight = uint16(6);
- config_major = uint8(8);
- config_minor = uint8(9);
- apogee_delay = uint16(10);
- main_deploy = uint16(12);
- flight_log_max = uint16(14);
- callsign = string(16, 8);
- version = string(24, 8);
- }
-
- public AltosRecord update_state(AltosRecord previous) {
- AltosRecord next = super.update_state(previous);
-
- next.device_type = device_type;
- next.flight = flight;
- next.config_major = config_major;
- next.config_minor = config_minor;
- next.apogee_delay = apogee_delay;
- next.main_deploy = main_deploy;
- next.flight_log_max = flight_log_max;
-
- next.callsign = callsign;
- next.firmware_version = version;
-
- next.seen |= AltosRecord.seen_deploy | AltosRecord.seen_flight;
-
- return next;
- }
-}
+++ /dev/null
-/*
- * Copyright © 2011 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-package org.altusmetrum.altoslib_1;
-
-import java.text.*;
-
-public class AltosTelemetryRecordGeneral {
-
- static AltosTelemetryRecord parse(String line) throws ParseException, AltosCRCException {
- AltosTelemetryRecord r;
-
- String[] word = line.split("\\s+");
- int i =0;
- if (word[i].equals("CRC") && word[i+1].equals("INVALID")) {
- i += 2;
- AltosParse.word(word[i++], "RSSI");
- throw new AltosCRCException(AltosParse.parse_int(word[i++]));
- }
-
- if (word[i].equals("TELEM"))
- r = AltosTelemetryRecordRaw.parse(word[i+1]);
- else
- r = new AltosTelemetryRecordLegacy(line);
- return r;
- }
-}
+++ /dev/null
-/*
- * Copyright © 2010 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-package org.altusmetrum.altoslib_1;
-
-import java.text.*;
-
-/*
- * Telemetry data contents
- */
-
-
-/*
- * The packet format is a simple hex dump of the raw telemetry frame.
- * It starts with 'TELEM', then contains hex digits with a checksum as the last
- * byte on the line.
- *
- * Version 4 is a replacement with consistent syntax. Each telemetry line
- * contains a sequence of space-separated names and values, the values are
- * either integers or strings. The names are all unique. All values are
- * optional
- *
- * VERSION 4 c KD7SQG n 236 f 18 r -25 s pad t 513 r_a 15756 r_b 26444 r_t 20944
- * r_v 26640 r_d 512 r_m 208 c_a 15775 c_b 26439 c_p 15749 c_m 16281 a_a 15764
- * a_s 0 a_b 26439 g_s u g_n 0 s_n 0
- *
- * VERSION 4 c KD7SQG n 19 f 0 r -23 s pad t 513 r_b 26372 r_t 21292 r_v 26788
- * r_d 136 r_m 140 c_b 26370 k_h 0 k_s 0 k_a 0
- *
- * General header fields
- *
- * Name Value
- *
- * VERSION Telemetry version number (4 or more). Must be first.
- * c Callsign (string, no spaces allowed)
- * n Flight unit serial number (integer)
- * f Flight number (integer)
- * r Packet RSSI value (integer)
- * s Flight computer state (string, no spaces allowed)
- * t Flight computer clock (integer in centiseconds)
- *
- * Version 3 is Version 2 with fixed RSSI numbers -- the radio reports
- * in 1/2dB increments while this protocol provides only integers. So,
- * the syntax didn't change just the interpretation of the RSSI
- * values.
- *
- * Version 2 of the telemetry data stream is a bit of a mess, with no
- * consistent formatting. In particular, the GPS data is formatted for
- * viewing instead of parsing. However, the key feature is that every
- * telemetry line contains all of the information necessary to
- * describe the current rocket state, including the calibration values
- * for accelerometer and barometer.
- *
- * GPS unlocked:
- *
- * VERSION 2 CALL KB0G SERIAL 51 FLIGHT 2 RSSI -68 STATUS ff STATE pad 1001 \
- * a: 16032 p: 21232 t: 20284 v: 25160 d: 204 m: 204 fa: 16038 ga: 16032 fv: 0 \
- * fp: 21232 gp: 21230 a+: 16049 a-: 16304 GPS 0 sat unlocked SAT 1 15 30
- *
- * GPS locked:
- *
- * VERSION 2 CALL KB0G SERIAL 51 FLIGHT 2 RSSI -71 STATUS ff STATE pad 2504 \
- * a: 16028 p: 21220 t: 20360 v: 25004 d: 208 m: 200 fa: 16031 ga: 16032 fv: 330 \
- * fp: 21231 gp: 21230 a+: 16049 a-: 16304 \
- * GPS 9 sat 2010-02-13 17:16:51 35°20.0803'N 106°45.2235'W 1790m \
- * 0.00m/s(H) 0° 0.00m/s(V) 1.0(hdop) 0(herr) 0(verr) \
- * SAT 10 29 30 24 28 5 25 21 20 15 33 1 23 30 24 18 26 10 29 2 26
- *
- */
-
-public class AltosTelemetryRecordLegacy extends AltosTelemetryRecord {
- /*
- * General header fields
- *
- * Name Value
- *
- * VERSION Telemetry version number (4 or more). Must be first.
- * c Callsign (string, no spaces allowed)
- * n Flight unit serial number (integer)
- * f Flight number (integer)
- * r Packet RSSI value (integer)
- * s Flight computer state (string, no spaces allowed)
- * t Flight computer clock (integer in centiseconds)
- */
-
- final static String AO_TELEM_VERSION = "VERSION";
- final static String AO_TELEM_CALL = "c";
- final static String AO_TELEM_SERIAL = "n";
- final static String AO_TELEM_FLIGHT = "f";
- final static String AO_TELEM_RSSI = "r";
- final static String AO_TELEM_STATE = "s";
- final static String AO_TELEM_TICK = "t";
-
- /*
- * Raw sensor values
- *
- * Name Value
- * r_a Accelerometer reading (integer)
- * r_b Barometer reading (integer)
- * r_t Thermometer reading (integer)
- * r_v Battery reading (integer)
- * r_d Drogue continuity (integer)
- * r_m Main continuity (integer)
- */
-
- final static String AO_TELEM_RAW_ACCEL = "r_a";
- final static String AO_TELEM_RAW_BARO = "r_b";
- final static String AO_TELEM_RAW_THERMO = "r_t";
- final static String AO_TELEM_RAW_BATT = "r_v";
- final static String AO_TELEM_RAW_DROGUE = "r_d";
- final static String AO_TELEM_RAW_MAIN = "r_m";
-
- /*
- * Sensor calibration values
- *
- * Name Value
- * c_a Ground accelerometer reading (integer)
- * c_b Ground barometer reading (integer)
- * c_p Accelerometer reading for +1g
- * c_m Accelerometer reading for -1g
- */
-
- final static String AO_TELEM_CAL_ACCEL_GROUND = "c_a";
- final static String AO_TELEM_CAL_BARO_GROUND = "c_b";
- final static String AO_TELEM_CAL_ACCEL_PLUS = "c_p";
- final static String AO_TELEM_CAL_ACCEL_MINUS = "c_m";
-
- /*
- * Kalman state values
- *
- * Name Value
- * k_h Height above pad (integer, meters)
- * k_s Vertical speeed (integer, m/s * 16)
- * k_a Vertical acceleration (integer, m/s² * 16)
- */
-
- final static String AO_TELEM_KALMAN_HEIGHT = "k_h";
- final static String AO_TELEM_KALMAN_SPEED = "k_s";
- final static String AO_TELEM_KALMAN_ACCEL = "k_a";
-
- /*
- * Ad-hoc flight values
- *
- * Name Value
- * a_a Acceleration (integer, sensor units)
- * a_s Speed (integer, integrated acceleration value)
- * a_b Barometer reading (integer, sensor units)
- */
-
- final static String AO_TELEM_ADHOC_ACCEL = "a_a";
- final static String AO_TELEM_ADHOC_SPEED = "a_s";
- final static String AO_TELEM_ADHOC_BARO = "a_b";
-
- /*
- * GPS values
- *
- * Name Value
- * g_s GPS state (string):
- * l locked
- * u unlocked
- * e error (missing or broken)
- * g_n Number of sats used in solution
- * g_ns Latitude (degrees * 10e7)
- * g_ew Longitude (degrees * 10e7)
- * g_a Altitude (integer meters)
- * g_Y GPS year (integer)
- * g_M GPS month (integer - 1-12)
- * g_D GPS day (integer - 1-31)
- * g_h GPS hour (integer - 0-23)
- * g_m GPS minute (integer - 0-59)
- * g_s GPS second (integer - 0-59)
- * g_v GPS vertical speed (integer, cm/sec)
- * g_s GPS horizontal speed (integer, cm/sec)
- * g_c GPS course (integer, 0-359)
- * g_hd GPS hdop (integer * 10)
- * g_vd GPS vdop (integer * 10)
- * g_he GPS h error (integer)
- * g_ve GPS v error (integer)
- */
-
- final static String AO_TELEM_GPS_STATE = "g";
- final static String AO_TELEM_GPS_STATE_LOCKED = "l";
- final static String AO_TELEM_GPS_STATE_UNLOCKED = "u";
- final static String AO_TELEM_GPS_STATE_ERROR = "e";
- final static String AO_TELEM_GPS_NUM_SAT = "g_n";
- final static String AO_TELEM_GPS_LATITUDE = "g_ns";
- final static String AO_TELEM_GPS_LONGITUDE = "g_ew";
- final static String AO_TELEM_GPS_ALTITUDE = "g_a";
- final static String AO_TELEM_GPS_YEAR = "g_Y";
- final static String AO_TELEM_GPS_MONTH = "g_M";
- final static String AO_TELEM_GPS_DAY = "g_D";
- final static String AO_TELEM_GPS_HOUR = "g_h";
- final static String AO_TELEM_GPS_MINUTE = "g_m";
- final static String AO_TELEM_GPS_SECOND = "g_s";
- final static String AO_TELEM_GPS_VERTICAL_SPEED = "g_v";
- final static String AO_TELEM_GPS_HORIZONTAL_SPEED = "g_g";
- final static String AO_TELEM_GPS_COURSE = "g_c";
- final static String AO_TELEM_GPS_HDOP = "g_hd";
- final static String AO_TELEM_GPS_VDOP = "g_vd";
- final static String AO_TELEM_GPS_HERROR = "g_he";
- final static String AO_TELEM_GPS_VERROR = "g_ve";
-
- /*
- * GPS satellite values
- *
- * Name Value
- * s_n Number of satellites reported (integer)
- * s_v0 Space vehicle ID (integer) for report 0
- * s_c0 C/N0 number (integer) for report 0
- * s_v1 Space vehicle ID (integer) for report 1
- * s_c1 C/N0 number (integer) for report 1
- * ...
- */
-
- final static String AO_TELEM_SAT_NUM = "s_n";
- final static String AO_TELEM_SAT_SVID = "s_v";
- final static String AO_TELEM_SAT_C_N_0 = "s_c";
-
- AltosRecordTM record;
-
- private void parse_v4(String[] words, int i) throws ParseException {
- AltosTelemetryMap map = new AltosTelemetryMap(words, i);
-
- record.callsign = map.get_string(AO_TELEM_CALL, "N0CALL");
- record.serial = map.get_int(AO_TELEM_SERIAL, AltosRecord.MISSING);
- record.flight = map.get_int(AO_TELEM_FLIGHT, AltosRecord.MISSING);
- record.rssi = map.get_int(AO_TELEM_RSSI, AltosRecord.MISSING);
- record.state = AltosLib.state(map.get_string(AO_TELEM_STATE, "invalid"));
- record.tick = map.get_int(AO_TELEM_TICK, 0);
-
- /* raw sensor values */
- record.accel = map.get_int(AO_TELEM_RAW_ACCEL, AltosRecord.MISSING);
- record.pres = map.get_int(AO_TELEM_RAW_BARO, AltosRecord.MISSING);
- record.temp = map.get_int(AO_TELEM_RAW_THERMO, AltosRecord.MISSING);
- record.batt = map.get_int(AO_TELEM_RAW_BATT, AltosRecord.MISSING);
- record.drogue = map.get_int(AO_TELEM_RAW_DROGUE, AltosRecord.MISSING);
- record.main = map.get_int(AO_TELEM_RAW_MAIN, AltosRecord.MISSING);
-
- /* sensor calibration information */
- record.ground_accel = map.get_int(AO_TELEM_CAL_ACCEL_GROUND, AltosRecord.MISSING);
- record.ground_pres = map.get_int(AO_TELEM_CAL_BARO_GROUND, AltosRecord.MISSING);
- record.accel_plus_g = map.get_int(AO_TELEM_CAL_ACCEL_PLUS, AltosRecord.MISSING);
- record.accel_minus_g = map.get_int(AO_TELEM_CAL_ACCEL_MINUS, AltosRecord.MISSING);
-
- /* flight computer values */
- record.kalman_acceleration = map.get_double(AO_TELEM_KALMAN_ACCEL, AltosRecord.MISSING, 1/16.0);
- record.kalman_speed = map.get_double(AO_TELEM_KALMAN_SPEED, AltosRecord.MISSING, 1/16.0);
- record.kalman_height = map.get_int(AO_TELEM_KALMAN_HEIGHT, AltosRecord.MISSING);
-
- record.flight_accel = map.get_int(AO_TELEM_ADHOC_ACCEL, AltosRecord.MISSING);
- record.flight_vel = map.get_int(AO_TELEM_ADHOC_SPEED, AltosRecord.MISSING);
- record.flight_pres = map.get_int(AO_TELEM_ADHOC_BARO, AltosRecord.MISSING);
-
- if (map.has(AO_TELEM_GPS_STATE)) {
- record.gps = new AltosGPS(map);
- record.gps_sequence++;
- }
- else
- record.gps = null;
- }
-
- private void parse_legacy(String[] words, int i) throws ParseException {
-
- AltosParse.word (words[i++], "CALL");
- record.callsign = words[i++];
-
- AltosParse.word (words[i++], "SERIAL");
- record.serial = AltosParse.parse_int(words[i++]);
-
- if (record.version >= 2) {
- AltosParse.word (words[i++], "FLIGHT");
- record.flight = AltosParse.parse_int(words[i++]);
- } else
- record.flight = 0;
-
- AltosParse.word(words[i++], "RSSI");
- record.rssi = AltosParse.parse_int(words[i++]);
-
- /* Older telemetry data had mis-computed RSSI value */
- if (record.version <= 2)
- record.rssi = (record.rssi + 74) / 2 - 74;
-
- AltosParse.word(words[i++], "STATUS");
- record.status = AltosParse.parse_hex(words[i++]);
-
- AltosParse.word(words[i++], "STATE");
- record.state = AltosLib.state(words[i++]);
-
- record.tick = AltosParse.parse_int(words[i++]);
-
- AltosParse.word(words[i++], "a:");
- record.accel = AltosParse.parse_int(words[i++]);
-
- AltosParse.word(words[i++], "p:");
- record.pres = AltosParse.parse_int(words[i++]);
-
- AltosParse.word(words[i++], "t:");
- record.temp = AltosParse.parse_int(words[i++]);
-
- AltosParse.word(words[i++], "v:");
- record.batt = AltosParse.parse_int(words[i++]);
-
- AltosParse.word(words[i++], "d:");
- record.drogue = AltosParse.parse_int(words[i++]);
-
- AltosParse.word(words[i++], "m:");
- record.main = AltosParse.parse_int(words[i++]);
-
- AltosParse.word(words[i++], "fa:");
- record.flight_accel = AltosParse.parse_int(words[i++]);
-
- AltosParse.word(words[i++], "ga:");
- record.ground_accel = AltosParse.parse_int(words[i++]);
-
- AltosParse.word(words[i++], "fv:");
- record.flight_vel = AltosParse.parse_int(words[i++]);
-
- AltosParse.word(words[i++], "fp:");
- record.flight_pres = AltosParse.parse_int(words[i++]);
-
- /* Old TeleDongle code with kalman-reporting TeleMetrum code */
- if ((record.flight_vel & 0xffff0000) == 0x80000000) {
- record.kalman_speed = ((short) record.flight_vel) / 16.0;
- record.kalman_acceleration = record.flight_accel / 16.0;
- record.kalman_height = record.flight_pres;
- record.flight_vel = AltosRecord.MISSING;
- record.flight_pres = AltosRecord.MISSING;
- record.flight_accel = AltosRecord.MISSING;
- }
-
- AltosParse.word(words[i++], "gp:");
- record.ground_pres = AltosParse.parse_int(words[i++]);
-
- if (record.version >= 1) {
- AltosParse.word(words[i++], "a+:");
- record.accel_plus_g = AltosParse.parse_int(words[i++]);
-
- AltosParse.word(words[i++], "a-:");
- record.accel_minus_g = AltosParse.parse_int(words[i++]);
- } else {
- record.accel_plus_g = record.ground_accel;
- record.accel_minus_g = record.ground_accel + 530;
- }
-
- record.gps = new AltosGPS(words, i, record.version);
- record.gps_sequence++;
- }
-
- public AltosTelemetryRecordLegacy(String line) throws ParseException, AltosCRCException {
- String[] words = line.split("\\s+");
- int i = 0;
-
- record = new AltosRecordTM();
-
- if (words[i].equals("CRC") && words[i+1].equals("INVALID")) {
- i += 2;
- AltosParse.word(words[i++], "RSSI");
- record.rssi = AltosParse.parse_int(words[i++]);
- throw new AltosCRCException(record.rssi);
- }
- if (words[i].equals("CALL")) {
- record.version = 0;
- } else {
- AltosParse.word (words[i++], "VERSION");
- record.version = AltosParse.parse_int(words[i++]);
- }
-
- if (record.version < 4)
- parse_legacy(words, i);
- else
- parse_v4(words, i);
- }
-
- /*
- * Given a hex dump of a legacy telemetry line, construct an AltosRecordTM from that
- */
-
- int[] bytes;
- int adjust;
-
- /*
- private int int8(int i) {
- return AltosLib.int8(bytes, i + 1 + adjust);
- }
- */
- private int uint8(int i) {
- return AltosLib.uint8(bytes, i + 1 + adjust);
- }
- private int int16(int i) {
- return AltosLib.int16(bytes, i + 1 + adjust);
- }
- private int uint16(int i) {
- return AltosLib.uint16(bytes, i + 1 + adjust);
- }
- private int uint32(int i) {
- return AltosLib.uint32(bytes, i + 1 + adjust);
- }
- private String string(int i, int l) {
- return AltosLib.string(bytes, i + 1 + adjust, l);
- }
-
- static final int AO_GPS_NUM_SAT_MASK = (0xf << 0);
- static final int AO_GPS_NUM_SAT_SHIFT = (0);
-
- static final int AO_GPS_VALID = (1 << 4);
- static final int AO_GPS_RUNNING = (1 << 5);
- static final int AO_GPS_DATE_VALID = (1 << 6);
- static final int AO_GPS_COURSE_VALID = (1 << 7);
-
- public AltosTelemetryRecordLegacy(int[] in_bytes, int in_rssi, int in_status) {
- record = new AltosRecordTM();
-
- bytes = in_bytes;
- record.version = 4;
- adjust = 0;
-
- if (bytes.length == AltosLib.ao_telemetry_0_8_len + 4) {
- record.serial = uint8(0);
- adjust = -1;
- } else
- record.serial = uint16(0);
-
- record.seen = AltosRecord.seen_flight | AltosRecord.seen_sensor | AltosRecord.seen_temp_volt | AltosRecord.seen_deploy;
-
- record.callsign = string(62, 8);
- record.flight = uint16(2);
- record.rssi = in_rssi;
- record.status = in_status;
- record.state = uint8(4);
- record.tick = uint16(21);
- record.accel = int16(23);
- record.pres = int16(25);
- record.temp = int16(27);
- record.batt = int16(29);
- record.drogue = int16(31);
- record.main = int16(33);
-
- record.ground_accel = int16(7);
- record.ground_pres = int16(15);
- record.accel_plus_g = int16(17);
- record.accel_minus_g = int16(19);
-
- if (uint16(11) == 0x8000) {
- record.kalman_acceleration = int16(5);
- record.kalman_speed = int16(9);
- record.kalman_height = int16(13);
- record.flight_accel = AltosRecord.MISSING;
- record.flight_vel = AltosRecord.MISSING;
- record.flight_pres = AltosRecord.MISSING;
- } else {
- record.flight_accel = int16(5);
- record.flight_vel = uint32(9);
- record.flight_pres = int16(13);
- record.kalman_acceleration = AltosRecord.MISSING;
- record.kalman_speed = AltosRecord.MISSING;
- record.kalman_height = AltosRecord.MISSING;
- }
-
- record.gps = null;
-
- int gps_flags = uint8(41);
-
- if ((gps_flags & (AO_GPS_VALID|AO_GPS_RUNNING)) != 0) {
- record.gps = new AltosGPS();
- record.gps_sequence++;
-
- record.seen |= AltosRecord.seen_gps_time | AltosRecord.seen_gps_lat | AltosRecord.seen_gps_lon;
- record.gps.nsat = (gps_flags & AO_GPS_NUM_SAT_MASK);
- record.gps.locked = (gps_flags & AO_GPS_VALID) != 0;
- record.gps.connected = true;
- record.gps.lat = uint32(42) / 1.0e7;
- record.gps.lon = uint32(46) / 1.0e7;
- record.gps.alt = int16(50);
- record.gps.ground_speed = uint16(52) / 100.0;
- record.gps.course = uint8(54) * 2;
- record.gps.hdop = uint8(55) / 5.0;
- record.gps.h_error = uint16(58);
- record.gps.v_error = uint16(60);
-
- int n_tracking_reported = uint8(70);
- if (n_tracking_reported > 12)
- n_tracking_reported = 12;
- int n_tracking_actual = 0;
- for (int i = 0; i < n_tracking_reported; i++) {
- if (uint8(71 + i*2) != 0)
- n_tracking_actual++;
- }
- if (n_tracking_actual > 0) {
- record.gps.cc_gps_sat = new AltosGPSSat[n_tracking_actual];
-
- n_tracking_actual = 0;
- for (int i = 0; i < n_tracking_reported; i++) {
- int svid = uint8(71 + i*2);
- int c_n0 = uint8(72 + i*2);
- if (svid != 0)
- record.gps.cc_gps_sat[n_tracking_actual++] = new AltosGPSSat(svid, c_n0);
- }
- }
- }
-
- record.time = 0.0;
- }
-
- public AltosRecord update_state(AltosRecord previous) {
- return record;
- }
-}
+++ /dev/null
-/*
- * Copyright © 2011 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-package org.altusmetrum.altoslib_1;
-
-
-public class AltosTelemetryRecordLocation extends AltosTelemetryRecordRaw {
- int flags;
- int altitude;
- int latitude;
- int longitude;
- int year;
- int month;
- int day;
- int hour;
- int minute;
- int second;
- int pdop;
- int hdop;
- int vdop;
- int mode;
- int ground_speed;
- int climb_rate;
- int course;
-
- public AltosTelemetryRecordLocation(int[] in_bytes, int rssi) {
- super(in_bytes, rssi);
-
- flags = uint8(5);
- altitude = int16(6);
- latitude = uint32(8);
- longitude = uint32(12);
- year = uint8(16);
- month = uint8(17);
- day = uint8(18);
- hour = uint8(19);
- minute = uint8(20);
- second = uint8(21);
- pdop = uint8(22);
- hdop = uint8(23);
- vdop = uint8(24);
- mode = uint8(25);
- ground_speed = uint16(26);
- climb_rate = int16(28);
- course = uint8(30);
- }
-
- public AltosRecord update_state(AltosRecord previous) {
- AltosRecord next = super.update_state(previous);
-
- if (next.gps == null)
- next.gps = new AltosGPS();
-
- next.gps.nsat = flags & 0xf;
- next.gps.locked = (flags & (1 << 4)) != 0;
- next.gps.connected = (flags & (1 << 5)) != 0;
-
- if (next.gps.locked) {
- next.gps.lat = latitude * 1.0e-7;
- next.gps.lon = longitude * 1.0e-7;
- next.gps.alt = altitude;
- next.gps.year = 2000 + year;
- next.gps.month = month;
- next.gps.day = day;
- next.gps.hour = hour;
- next.gps.minute = minute;
- next.gps.second = second;
- next.gps.ground_speed = ground_speed * 1.0e-2;
- next.gps.course = course * 2;
- next.gps.climb_rate = climb_rate * 1.0e-2;
- next.gps.hdop = hdop;
- next.gps.vdop = vdop;
- next.seen |= AltosRecord.seen_gps_time | AltosRecord.seen_gps_lat | AltosRecord.seen_gps_lon;
- next.gps_sequence++;
- }
-
- return next;
- }
-}
+++ /dev/null
-/*
- * Copyright © 2011 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-package org.altusmetrum.altoslib_1;
-
-
-public class AltosTelemetryRecordMegaData extends AltosTelemetryRecordRaw {
-
- int state;
-
- int v_batt;
- int v_pyro;
- int sense[];
-
- int ground_pres;
- int ground_accel;
- int accel_plus_g;
- int accel_minus_g;
-
- int acceleration;
- int speed;
- int height;
-
- public AltosTelemetryRecordMegaData(int[] in_bytes, int rssi) {
- super(in_bytes, rssi);
-
- state = int8(5);
-
- v_batt = int16(6);
- v_pyro = int16(8);
-
- sense = new int[6];
-
- for (int i = 0; i < 6; i++) {
- sense[i] = int8(10 + i) << 4;
- sense[i] |= sense[i] >> 8;
- }
-
- ground_pres = int32(16);
- ground_accel = int16(20);
- accel_plus_g = int16(22);
- accel_minus_g = int16(24);
-
- acceleration = int16(26);
- speed = int16(28);
- height = int16(30);
- }
-
- public AltosRecord update_state(AltosRecord previous) {
- AltosRecord n = super.update_state(previous);
-
- AltosRecordMM next;
- if (!(n instanceof AltosRecordMM)) {
- next = new AltosRecordMM(n);
- } else {
- next = (AltosRecordMM) n;
- }
-
- next.state = state;
-
- next.v_batt = v_batt;
- next.v_pyro = v_pyro;
-
- for (int i = 0; i < 6; i++)
- next.sense[i] = sense[i];
-
- next.ground_accel = ground_accel;
- next.ground_pres = ground_pres;
- next.accel_plus_g = accel_plus_g;
- next.accel_minus_g = accel_minus_g;
-
- next.kalman_acceleration = acceleration / 16.0;
- next.kalman_speed = speed / 16.0;
- next.kalman_height = height;
-
- next.seen |= AltosRecord.seen_sensor | AltosRecord.seen_temp_volt;
-
- return next;
- }
-}
+++ /dev/null
-/*
- * Copyright © 2011 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-package org.altusmetrum.altoslib_1;
-
-
-public class AltosTelemetryRecordMegaSensor extends AltosTelemetryRecordRaw {
- int accel;
- int pres;
- int temp;
-
- int accel_x;
- int accel_y;
- int accel_z;
-
- int gyro_x;
- int gyro_y;
- int gyro_z;
-
- int mag_x;
- int mag_y;
- int mag_z;
-
- public AltosTelemetryRecordMegaSensor(int[] in_bytes, int rssi) {
- super(in_bytes, rssi);
-
- accel = int16(6);
- pres = int32(8);
- temp = int16(12);
-
- accel_x = int16(14);
- accel_y = int16(16);
- accel_z = int16(18);
-
- gyro_x = int16(20);
- gyro_y = int16(22);
- gyro_z = int16(24);
-
- mag_x = int16(26);
- mag_y = int16(28);
- mag_z = int16(30);
- }
-
- public AltosRecord update_state(AltosRecord previous) {
- AltosRecord n = super.update_state(previous);
-
- AltosRecordMM next;
- if (!(n instanceof AltosRecordMM)) {
- next = new AltosRecordMM(n);
- } else {
- next = (AltosRecordMM) n;
- }
-
- next.accel = accel;
- next.pres = pres;
- next.temp = temp;
-
- next.imu.accel_x = accel_x;
- next.imu.accel_y = accel_y;
- next.imu.accel_z = accel_z;
-
- next.imu.gyro_x = gyro_x;
- next.imu.gyro_y = gyro_y;
- next.imu.gyro_z = gyro_z;
-
- next.mag.x = mag_x;
- next.mag.y = mag_y;
- next.mag.z = mag_z;
-
- next.seen |= AltosRecord.seen_sensor;
-
- return next;
- }
-}
+++ /dev/null
-/*
- * Copyright © 2011 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-package org.altusmetrum.altoslib_1;
-
-public class AltosTelemetryRecordRaw extends AltosTelemetryRecord {
- int[] bytes;
- int serial;
- int tick;
- int type;
- int rssi;
-
- long received_time;
-
- public int int8(int off) {
- return AltosLib.int8(bytes, off + 1);
- }
-
- public int uint8(int off) {
- return AltosLib.uint8(bytes, off + 1);
- }
-
- public int int16(int off) {
- return AltosLib.int16(bytes, off + 1);
- }
-
- public int uint16(int off) {
- return AltosLib.uint16(bytes, off + 1);
- }
-
- public int uint32(int off) {
- return AltosLib.uint32(bytes, off + 1);
- }
-
- public int int32(int off) {
- return AltosLib.int32(bytes, off + 1);
- }
-
- public String string(int off, int l) {
- return AltosLib.string(bytes, off + 1, l);
- }
-
- public AltosTelemetryRecordRaw(int[] in_bytes, int in_rssi) {
- bytes = in_bytes;
- serial = uint16(0);
- tick = uint16(2);
- type = uint8(4);
- rssi = in_rssi;
- }
-
- public AltosRecord update_state(AltosRecord previous) {
- AltosRecord next;
-
- if (previous != null && previous.serial == serial)
- next = previous.clone();
- else
- next = new AltosRecordNone();
- next.serial = serial;
- next.tick = tick;
- next.rssi = rssi;
- return next;
- }
-
- public long received_time() {
- return received_time;
- }
-}
+++ /dev/null
-/*
- * Copyright © 2011 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-package org.altusmetrum.altoslib_1;
-
-public class AltosTelemetryRecordSatellite extends AltosTelemetryRecordRaw {
- int channels;
- AltosGPSSat[] sats;
-
- public AltosTelemetryRecordSatellite(int[] in_bytes, int rssi) {
- super(in_bytes, rssi);
-
- channels = uint8(5);
- if (channels > 12)
- channels = 12;
- if (channels == 0)
- sats = null;
- else {
- sats = new AltosGPSSat[channels];
- for (int i = 0; i < channels; i++) {
- int svid = uint8(6 + i * 2 + 0);
- int c_n_1 = uint8(6 + i * 2 + 1);
- sats[i] = new AltosGPSSat(svid, c_n_1);
- }
- }
- }
-
- public AltosRecord update_state(AltosRecord previous) {
- AltosRecord next = super.update_state(previous);
-
- if (next.gps == null)
- next.gps = new AltosGPS();
-
- next.gps.cc_gps_sat = sats;
-
- return next;
- }
-}
+++ /dev/null
-/*
- * Copyright © 2011 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-package org.altusmetrum.altoslib_1;
-
-
-public class AltosTelemetryRecordSensor extends AltosTelemetryRecordRaw {
- int state;
- int accel;
- int pres;
- int temp;
- int v_batt;
- int sense_d;
- int sense_m;
-
- int acceleration;
- int speed;
- int height;
-
- int ground_accel;
- int ground_pres;
- int accel_plus_g;
- int accel_minus_g;
-
- public AltosTelemetryRecordSensor(int[] in_bytes, int rssi) {
- super(in_bytes, rssi);
- state = uint8(5);
-
- accel = int16(6);
- pres = int16(8);
- temp = int16(10);
- v_batt = int16(12);
- sense_d = int16(14);
- sense_m = int16(16);
-
- acceleration = int16(18);
- speed = int16(20);
- height = int16(22);
-
- ground_pres = int16(24);
- ground_accel = int16(26);
- accel_plus_g = int16(28);
- accel_minus_g = int16(30);
- }
-
- public AltosRecord update_state(AltosRecord prev) {
- AltosRecord n = super.update_state(prev);
-
- AltosRecordTM next;
- if (!(n instanceof AltosRecordTM))
- next = new AltosRecordTM(n);
- else
- next = (AltosRecordTM) n;
-
- next.state = state;
- if (type == packet_type_TM_sensor)
- next.accel = accel;
- else
- next.accel = AltosRecord.MISSING;
- next.pres = pres;
- next.temp = temp;
- next.batt = v_batt;
- if (type == packet_type_TM_sensor || type == packet_type_Tm_sensor) {
- next.drogue = sense_d;
- next.main = sense_m;
- } else {
- next.drogue = AltosRecord.MISSING;
- next.main = AltosRecord.MISSING;
- }
-
- next.kalman_acceleration = acceleration / 16.0;
- next.kalman_speed = speed / 16.0;
- next.kalman_height = height;
-
- next.ground_pres = ground_pres;
- if (type == packet_type_TM_sensor) {
- next.ground_accel = ground_accel;
- next.accel_plus_g = accel_plus_g;
- next.accel_minus_g = accel_minus_g;
- } else {
- next.ground_accel = AltosRecord.MISSING;
- next.accel_plus_g = AltosRecord.MISSING;
- next.accel_minus_g = AltosRecord.MISSING;
- }
-
- next.seen |= AltosRecord.seen_sensor | AltosRecord.seen_temp_volt;
-
- return next;
- }
-}
--- /dev/null
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+public class AltosTelemetrySatellite extends AltosTelemetryStandard {
+ int channels;
+ AltosGPSSat[] sats;
+
+ public AltosTelemetrySatellite(int[] bytes) {
+ super(bytes);
+
+ channels = uint8(5);
+ if (channels > 12)
+ channels = 12;
+ if (channels == 0)
+ sats = null;
+ else {
+ sats = new AltosGPSSat[channels];
+ for (int i = 0; i < channels; i++) {
+ int svid = uint8(6 + i * 2 + 0);
+ int c_n_1 = uint8(6 + i * 2 + 1);
+ sats[i] = new AltosGPSSat(svid, c_n_1);
+ }
+ }
+ }
+
+ public void update_state(AltosState state) {
+ super.update_state(state);
+
+ AltosGPS gps = state.make_temp_gps(true);
+
+ gps.cc_gps_sat = sats;
+ state.set_temp_gps();
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+
+public class AltosTelemetrySensor extends AltosTelemetryStandard {
+ int state;
+ int accel;
+ int pres;
+ int temp;
+ int v_batt;
+ int sense_d;
+ int sense_m;
+
+ int acceleration;
+ int speed;
+ int height;
+
+ int ground_accel;
+ int ground_pres;
+ int accel_plus_g;
+ int accel_minus_g;
+
+ public AltosTelemetrySensor(int[] bytes) {
+ super(bytes);
+ state = uint8(5);
+
+ accel = int16(6);
+ pres = int16(8);
+ temp = int16(10);
+ v_batt = int16(12);
+ sense_d = int16(14);
+ sense_m = int16(16);
+
+ acceleration = int16(18);
+ speed = int16(20);
+ height = int16(22);
+
+ ground_pres = int16(24);
+ ground_accel = int16(26);
+ accel_plus_g = int16(28);
+ accel_minus_g = int16(30);
+ }
+
+ public void update_state(AltosState state) {
+ super.update_state(state);
+
+ state.set_state(this.state);
+ if (type == packet_type_TM_sensor) {
+ state.set_ground_accel(ground_accel);
+ state.set_accel_g(accel_plus_g, accel_minus_g);
+ state.set_accel(accel);
+ }
+ state.set_ground_pressure(AltosConvert.barometer_to_pressure(ground_pres));
+ state.set_pressure(AltosConvert.barometer_to_pressure(pres));
+ state.set_temperature(AltosConvert.thermometer_to_temperature(temp));
+ state.set_battery_voltage(AltosConvert.cc_battery_to_voltage(v_batt));
+ if (type == packet_type_TM_sensor || type == packet_type_Tm_sensor) {
+ state.set_apogee_voltage(AltosConvert.cc_ignitor_to_voltage(sense_d));
+ state.set_main_voltage(AltosConvert.cc_ignitor_to_voltage(sense_m));
+ }
+
+ state.set_kalman(height, speed/16.0, acceleration / 16.0);
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+public abstract class AltosTelemetryStandard extends AltosTelemetry {
+ int[] bytes;
+ int type;
+
+ public int int8(int off) {
+ return AltosLib.int8(bytes, off + 1);
+ }
+
+ public int uint8(int off) {
+ return AltosLib.uint8(bytes, off + 1);
+ }
+
+ public int int16(int off) {
+ return AltosLib.int16(bytes, off + 1);
+ }
+
+ public int uint16(int off) {
+ return AltosLib.uint16(bytes, off + 1);
+ }
+
+ public int uint32(int off) {
+ return AltosLib.uint32(bytes, off + 1);
+ }
+
+ public int int32(int off) {
+ return AltosLib.int32(bytes, off + 1);
+ }
+
+ public String string(int off, int l) {
+ return AltosLib.string(bytes, off + 1, l);
+ }
+
+ public static AltosTelemetry parse_hex(int[] bytes) {
+ int type = AltosLib.uint8(bytes, 4 + 1);
+
+ AltosTelemetry telem;
+ switch (type) {
+ case packet_type_TM_sensor:
+ case packet_type_Tm_sensor:
+ case packet_type_Tn_sensor:
+ telem = new AltosTelemetrySensor(bytes);
+ break;
+ case packet_type_configuration:
+ telem = new AltosTelemetryConfiguration(bytes);
+ break;
+ case packet_type_location:
+ telem = new AltosTelemetryLocation(bytes);
+ break;
+ case packet_type_satellite:
+ telem = new AltosTelemetrySatellite(bytes);
+ break;
+/*
+ case packet_type_companion:
+ telem = new AltosTelemetryCompanion(bytes);
+ break;
+*/
+ case packet_type_mega_sensor:
+ telem = new AltosTelemetryMegaSensor(bytes);
+ break;
+ case packet_type_mega_data:
+ telem = new AltosTelemetryMegaData(bytes);
+ break;
+ case packet_type_metrum_sensor:
+ telem = new AltosTelemetryMetrumSensor(bytes);
+ break;
+ case packet_type_metrum_data:
+ telem = new AltosTelemetryMetrumData(bytes);
+ break;
+ case packet_type_mini:
+ telem = new AltosTelemetryMini(bytes);
+ break;
+ default:
+ telem = new AltosTelemetryRaw(bytes);
+ break;
+ }
+ return telem;
+ }
+
+ public AltosTelemetryStandard(int[] bytes) {
+ this.bytes = bytes;
+
+ serial = uint16(0);
+ tick = uint16(2);
+ type = uint8(4);
+ }
+
+ public void update_state(AltosState state) {
+ super.update_state(state);
+ }
+}
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
public class AltosTemperature extends AltosUnits {
- public double value(double v) {
- if (AltosConvert.imperial_units)
+ public double value(double v, boolean imperial_units) {
+ if (imperial_units)
return AltosConvert.c_to_f(v);
return v;
}
- public String show_units() {
- if (AltosConvert.imperial_units)
+ public double inverse(double v, boolean imperial_units) {
+ if (imperial_units)
+ return AltosConvert.f_to_c(v);
+ return v;
+ }
+
+ public String show_units(boolean imperial_units) {
+ if (imperial_units)
return "°F";
return "°C";
}
- public String say_units() {
- if (AltosConvert.imperial_units)
+ public String say_units(boolean imperial_units) {
+ if (imperial_units)
return "degrees farenheit";
return "degrees celsius";
}
- public int show_fraction(int width) {
+ public int show_fraction(int width, boolean imperial_units) {
return width / 3;
}
}
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
public abstract class AltosUnits {
- public abstract double value(double v);
+ public abstract double value(double v, boolean imperial_units);
- public abstract String show_units();
+ public abstract double inverse(double v, boolean imperial_units);
- public abstract String say_units();
+ public abstract String show_units(boolean imperial_units);
- public abstract int show_fraction(int width);
+ public abstract String say_units(boolean imperial_units);
- int say_fraction() {
+ public abstract int show_fraction(int width, boolean imperial_units);
+
+ public double parse(String s, boolean imperial_units) throws NumberFormatException {
+ double v = Double.parseDouble(s);
+ return inverse(v, imperial_units);
+ }
+
+ public double parse(String s) throws NumberFormatException {
+ return parse(s, AltosConvert.imperial_units);
+ }
+
+ public double value(double v) {
+ return value(v, AltosConvert.imperial_units);
+ }
+
+ public double inverse(double v) {
+ return inverse(v, AltosConvert.imperial_units);
+ }
+
+ public String show_units() {
+ return show_units(AltosConvert.imperial_units);
+ }
+
+ public String say_units() {
+ return say_units(AltosConvert.imperial_units);
+ }
+
+ public int show_fraction(int width) {
+ return show_fraction(width, AltosConvert.imperial_units);
+ }
+
+ int say_fraction(boolean imperial_units) {
return 0;
}
- private String show_format(int width) {
- return String.format("%%%d.%df %s", width, show_fraction(width), show_units());
+ private String show_format(int width, boolean imperial_units) {
+ return String.format("%%%d.%df %s", width, show_fraction(width, imperial_units), show_units(imperial_units));
+ }
+
+ private String say_format(boolean imperial_units) {
+ return String.format("%%1.%df", say_fraction(imperial_units));
}
- private String say_format() {
- return String.format("%%1.%df", say_fraction());
+ private String say_units_format(boolean imperial_units) {
+ return String.format("%%1.%df %s", say_fraction(imperial_units), say_units(imperial_units));
}
- private String say_units_format() {
- return String.format("%%1.%df %s", say_fraction(), say_units());
+ public String graph_format(int width, boolean imperial_units) {
+ return String.format(String.format("%%%d.%df", width, show_fraction(width, imperial_units)), 0.0);
}
public String graph_format(int width) {
- return String.format(String.format("%%%d.%df", width, show_fraction(width)), 0.0);
+ return graph_format(width, AltosConvert.imperial_units);
+ }
+
+ public String show(int width, double v, boolean imperial_units) {
+ return String.format(show_format(width, imperial_units), value(v, imperial_units));
}
public String show(int width, double v) {
- return String.format(show_format(width), value(v));
+ return show(width, v, AltosConvert.imperial_units);
+ }
+
+ public String say(double v, boolean imperial_units) {
+ return String.format(say_format(imperial_units), value(v, imperial_units));
}
public String say(double v) {
- return String.format(say_format(), value(v));
+ return say(v, AltosConvert.imperial_units);
+ }
+
+ public String say_units(double v, boolean imperial_units) {
+ return String.format(say_units_format(imperial_units), value(v, imperial_units));
}
public String say_units(double v) {
- return String.format(say_units_format(), value(v));
+ return say_units(v, AltosConvert.imperial_units);
}
}
\ No newline at end of file
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
public interface AltosUnitsListener {
public void units_changed(boolean imperial_units);
-AM_JAVACFLAGS=-encoding UTF-8 -Xlint:deprecation
+AM_JAVACFLAGS=-target 1.6 -encoding UTF-8 -Xlint:deprecation -source 6
JAVAROOT=bin
SRC=.
altoslibdir = $(datadir)/java
+record_files = \
+ AltosEepromRecord.java \
+ AltosEepromTeleScience.java \
+ AltosRecordCompanion.java \
+ AltosRecordIterable.java \
+ AltosOrderedRecord.java \
+ AltosOrderedMegaRecord.java \
+ AltosOrderedMiniRecord.java \
+ AltosRecord.java \
+ AltosRecordNone.java \
+ AltosRecordTM.java \
+ AltosRecordMM.java \
+ AltosRecordMini.java
+
altoslib_JAVA = \
AltosLib.java \
+ AltosCompanion.java \
AltosConfigData.java \
AltosConfigValues.java \
AltosConvert.java \
AltosCRCException.java \
AltosDebug.java \
+ AltosEeprom.java \
AltosEepromChunk.java \
+ AltosEepromDownload.java \
+ AltosEepromFile.java \
+ AltosEepromTM.java \
+ AltosEepromTm.java \
+ AltosEepromHeader.java \
AltosEepromIterable.java \
+ AltosEepromList.java \
AltosEepromLog.java \
AltosEepromMega.java \
- AltosEepromMegaIterable.java \
- AltosEepromRecord.java \
- AltosEepromTeleScience.java \
+ AltosEepromMetrum2.java \
+ AltosEepromMini.java \
+ AltosEepromMonitor.java \
AltosFile.java \
AltosFlash.java \
AltosFlashListener.java \
AltosFlightReader.java \
AltosFrequency.java \
AltosGPS.java \
- AltosGPSQuery.java \
AltosGPSSat.java \
AltosGreatCircle.java \
AltosHexfile.java \
+ AltosHexsym.java \
+ AltosIdle.java \
+ AltosIdleFetch.java \
AltosIdleMonitor.java \
AltosIdleMonitorListener.java \
AltosIgnite.java \
AltosIMU.java \
- AltosIMUQuery.java \
AltosLine.java \
AltosLink.java \
AltosListenerState.java \
AltosLog.java \
+ AltosMag.java \
+ AltosMma655x.java \
AltosMs5607.java \
- AltosMs5607Query.java \
- AltosOrderedRecord.java \
- AltosOrderedMegaRecord.java \
+ AltosNoSymbol.java \
AltosParse.java \
AltosPreferences.java \
AltosPreferencesBackend.java \
- AltosRecordCompanion.java \
- AltosRecordIterable.java \
- AltosRecord.java \
- AltosRecordNone.java \
- AltosRecordTM.java \
- AltosRecordMM.java \
+ AltosProgrammer.java \
AltosReplayReader.java \
AltosRomconfig.java \
+ AltosSelfFlash.java \
AltosSensorMM.java \
+ AltosSensorEMini.java \
AltosSensorTM.java \
+ AltosSensorTMini.java \
+ AltosSensorMega.java \
+ AltosSensorMetrum.java \
AltosState.java \
+ AltosStateIterable.java \
+ AltosStateUpdate.java \
AltosTelemetry.java \
+ AltosTelemetryConfiguration.java \
+ AltosTelemetryFile.java \
AltosTelemetryIterable.java \
+ AltosTelemetryLegacy.java \
+ AltosTelemetryLocation.java \
AltosTelemetryMap.java \
+ AltosTelemetryMegaSensor.java \
+ AltosTelemetryMegaData.java \
+ AltosTelemetryMini.java \
+ AltosTelemetryMetrumSensor.java \
+ AltosTelemetryMetrumData.java \
AltosTelemetryReader.java \
- AltosTelemetryRecordCompanion.java \
- AltosTelemetryRecordConfiguration.java \
- AltosTelemetryRecordGeneral.java \
- AltosTelemetryRecord.java \
- AltosTelemetryRecordLegacy.java \
- AltosTelemetryRecordLocation.java \
- AltosTelemetryRecordRaw.java \
- AltosTelemetryRecordSatellite.java \
- AltosTelemetryRecordSensor.java \
- AltosTelemetryRecordMegaSensor.java \
- AltosTelemetryRecordMegaData.java \
+ AltosTelemetryRaw.java \
+ AltosTelemetrySensor.java \
+ AltosTelemetrySatellite.java \
+ AltosTelemetryStandard.java \
AltosUnitsListener.java \
AltosMs5607.java \
AltosIMU.java \
*.so
*.jar
*.class
+*.dmg
import java.awt.*;
import libaltosJNI.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
import org.altusmetrum.altosuilib_1.*;
public class Altos extends AltosUILib {
import java.awt.*;
import javax.swing.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
public class AltosAscent extends JComponent implements AltosFlightDisplay {
GridBagLayout layout;
void reset() {
value.setText("");
max_value.setText("");
- max = AltosRecord.MISSING;
+ max = AltosLib.MISSING;
}
void set_font() {
}
void show(AltosUnits units, double v) {
- if (v == AltosRecord.MISSING) {
+ if (v == AltosLib.MISSING) {
value.setText("Missing");
max_value.setText("Missing");
} else {
value.setText(units.show(8, v));
- if (v > max || max == AltosRecord.MISSING) {
+ if (v > max || max == AltosLib.MISSING) {
max_value.setText(units.show(8, v));
max = v;
}
class Height extends AscentValueHold {
void show (AltosState state, AltosListenerState listener_state) {
- show(AltosConvert.height, state.height);
+ show(AltosConvert.height, state.height());
}
public Height (GridBagLayout layout, int y) {
super (layout, y, "Height");
class Speed extends AscentValueHold {
void show (AltosState state, AltosListenerState listener_state) {
- double speed = state.accel_speed;
- if (!state.ascent)
- speed = state.baro_speed;
- show(AltosConvert.speed, speed);
+ show(AltosConvert.speed, state.speed());
}
public Speed (GridBagLayout layout, int y) {
super (layout, y, "Speed");
class Accel extends AscentValueHold {
void show (AltosState state, AltosListenerState listener_state) {
- show(AltosConvert.accel, state.acceleration);
+ show(AltosConvert.accel, state.acceleration());
}
public Accel (GridBagLayout layout, int y) {
super (layout, y, "Acceleration");
class Apogee extends AscentStatus {
void show (AltosState state, AltosListenerState listener_state) {
- show("%4.2f V", state.drogue_sense);
- lights.set(state.drogue_sense > 3.2);
+ show("%4.2f V", state.apogee_voltage);
+ lights.set(state.apogee_voltage >= AltosLib.ao_igniter_good);
}
public Apogee (GridBagLayout layout, int y) {
super(layout, y, "Apogee Igniter Voltage");
class Main extends AscentStatus {
void show (AltosState state, AltosListenerState listener_state) {
- show("%4.2f V", state.main_sense);
- lights.set(state.main_sense > 3.2);
+ show("%4.2f V", state.main_voltage);
+ lights.set(state.main_voltage >= AltosLib.ao_igniter_good);
}
public Main (GridBagLayout layout, int y) {
super(layout, y, "Main Igniter Voltage");
class Lat extends AscentValue {
void show (AltosState state, AltosListenerState listener_state) {
- if (state.gps != null)
+ if (state.gps != null && state.gps.connected && state.gps.lat != AltosLib.MISSING)
show(pos(state.gps.lat,"N", "S"));
else
show("???");
class Lon extends AscentValue {
void show (AltosState state, AltosListenerState listener_state) {
- if (state.gps != null)
+ if (state.gps != null && state.gps.connected && state.gps.lon != AltosLib.MISSING)
show(pos(state.gps.lon,"E", "W"));
else
show("???");
lon.hide();
}
height.show(state, listener_state);
- if (state.main_sense != AltosRecord.MISSING)
+ if (state.main_voltage != AltosLib.MISSING)
main.show(state, listener_state);
else
main.hide();
- if (state.drogue_sense != AltosRecord.MISSING)
+ if (state.apogee_voltage != AltosLib.MISSING)
apogee.show(state, listener_state);
else
apogee.hide();
package altosui;
import java.util.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
import org.altusmetrum.altosuilib_1.*;
public class AltosBTKnown implements Iterable<AltosBTDevice> {
return devices.iterator();
}
- public java.util.List<AltosBTDevice> selected_list() {
+ public java.util.List<AltosBTDevice> selected_list() throws InterruptedException {
java.util.LinkedList<AltosBTDevice> l = new java.util.LinkedList<AltosBTDevice>();
Object[] a = getSelectedValues();
for (int i = 0; i < a.length; i++)
}
public void add_known() {
- for (AltosBTDevice device : visible_devices.selected_list()) {
- known_devices.add(device);
- visible_devices.remove(device);
+ try {
+ for (AltosBTDevice device : visible_devices.selected_list()) {
+ known_devices.add(device);
+ visible_devices.remove(device);
+ }
+ } catch (InterruptedException ie) {
}
}
public void remove_known() {
- for (AltosBTDevice device : known_devices.selected_list()) {
- known_devices.remove(device);
- visible_devices.add(device);
+ try {
+ for (AltosBTDevice device : known_devices.selected_list()) {
+ known_devices.remove(device);
+ visible_devices.add(device);
+ }
+ } catch (InterruptedException ie) {
}
}
import java.io.*;
import java.util.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
public class AltosCSV implements AltosWriter {
File name;
boolean header_written;
boolean seen_boost;
int boost_tick;
- LinkedList<AltosRecord> pad_records;
+ LinkedList<AltosState> pad_states;
AltosState state;
static final int ALTOS_CSV_VERSION = 5;
out.printf("version,serial,flight,call,time,clock,rssi,lqi");
}
- void write_general(AltosRecord record) {
+ void write_general(AltosState state) {
out.printf("%s, %d, %d, %s, %8.2f, %8.2f, %4d, %3d",
- ALTOS_CSV_VERSION, record.serial, record.flight, record.callsign,
- (double) record.time, (double) record.tick / 100.0,
- record.rssi,
- record.status & 0x7f);
+ ALTOS_CSV_VERSION, state.serial, state.flight, state.callsign,
+ (double) state.time, (double) state.tick / 100.0,
+ state.rssi,
+ state.status & 0x7f);
}
void write_flight_header() {
out.printf("state,state_name");
}
- void write_flight(AltosRecord record) {
- out.printf("%d,%8s", record.state, record.state());
+ void write_flight(AltosState state) {
+ out.printf("%d,%8s", state.state, state.state_name());
}
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) {
+ void write_basic(AltosState state) {
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(),
- state.accel_speed,
- state.baro_speed,
- record.temperature(),
- record.battery_voltage(),
- record.drogue_voltage(),
- record.main_voltage());
+ state.acceleration(),
+ state.pressure(),
+ state.altitude(),
+ state.height(),
+ state.speed(),
+ state.speed(),
+ state.temperature,
+ state.battery_voltage,
+ state.apogee_voltage,
+ state.main_voltage);
}
void write_advanced_header() {
out.printf("accel_x,accel_y,accel_z,gyro_x,gyro_y,gyro_z");
}
- void write_advanced(AltosRecord record) {
- AltosIMU imu = record.imu();
- AltosMag mag = record.mag();
+ void write_advanced(AltosState state) {
+ AltosIMU imu = state.imu;
+ AltosMag mag = state.mag;
if (imu == null)
imu = new AltosIMU();
out.printf("connected,locked,nsat,latitude,longitude,altitude,year,month,day,hour,minute,second,pad_dist,pad_range,pad_az,pad_el,hdop");
}
- void write_gps(AltosRecord record) {
- AltosGPS gps = record.gps;
+ void write_gps(AltosState state) {
+ AltosGPS gps = state.gps;
if (gps == null)
gps = new AltosGPS();
if (from_pad == null)
from_pad = new AltosGreatCircle();
- out.printf("%2d,%2d,%3d,%12.7f,%12.7f,%6d,%5d,%3d,%3d,%3d,%3d,%3d,%9.0f,%9.0f,%4.0f,%4.0f,%6.1f",
+ out.printf("%2d,%2d,%3d,%12.7f,%12.7f,%8.1f,%5d,%3d,%3d,%3d,%3d,%3d,%9.0f,%9.0f,%4.0f,%4.0f,%6.1f",
gps.connected?1:0,
gps.locked?1:0,
gps.nsat,
}
}
- void write_gps_sat(AltosRecord record) {
- AltosGPS gps = record.gps;
+ void write_gps_sat(AltosState state) {
+ AltosGPS gps = state.gps;
for(int i = 1; i <= 32; i++) {
int c_n0 = 0;
if (gps != null && gps.cc_gps_sat != null) {
out.printf(",companion_%02d", i);
}
- void write_companion(AltosRecord record) {
- AltosRecordCompanion companion = record.companion;
+ void write_companion(AltosState state) {
+ AltosCompanion companion = state.companion;
int channels_written = 0;
if (companion == null) {
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(",");
- if (record.imu() != null || record.mag() != null)
- write_advanced(record);
- if (record.gps != null) {
+ void write_one(AltosState state) {
+ write_general(state); out.printf(",");
+ write_flight(state); out.printf(",");
+ write_basic(state); out.printf(",");
+ if (state.imu != null || state.mag != null)
+ write_advanced(state);
+ if (state.gps != null) {
out.printf(",");
- write_gps(record); out.printf(",");
- write_gps_sat(record);
+ write_gps(state); out.printf(",");
+ write_gps_sat(state);
}
- if (record.companion != null) {
+ if (state.companion != null) {
out.printf(",");
- write_companion(record);
+ write_companion(state);
}
out.printf ("\n");
}
void flush_pad() {
- while (!pad_records.isEmpty()) {
- write_one (pad_records.remove());
+ while (!pad_states.isEmpty()) {
+ write_one (pad_states.remove());
}
}
- public void write(AltosRecord record) {
- if (record.state == Altos.ao_flight_startup)
+ public void write(AltosState state) {
+ if (state.state == Altos.ao_flight_startup)
return;
if (!header_written) {
- write_header(record.imu() != null || record.mag() != null,
- record.gps != null, record.companion != null);
+ write_header(state.imu != null || state.mag != null,
+ state.gps != null, state.companion != null);
header_written = true;
}
if (!seen_boost) {
- if (record.state >= Altos.ao_flight_boost) {
+ if (state.state >= Altos.ao_flight_boost) {
seen_boost = true;
- boost_tick = record.tick;
+ boost_tick = state.tick;
flush_pad();
}
}
if (seen_boost)
- write_one(record);
+ write_one(state);
else
- pad_records.add(record);
+ pad_states.add(state);
}
public PrintStream out() {
}
public void close() {
- if (!pad_records.isEmpty()) {
- boost_tick = pad_records.element().tick;
+ if (!pad_states.isEmpty()) {
+ boost_tick = pad_states.element().tick;
flush_pad();
}
out.close();
}
- public void write(AltosRecordIterable iterable) {
- iterable.write_comments(out());
- for (AltosRecord r : iterable)
- write(r);
+ public void write(AltosStateIterable states) {
+ states.write_comments(out());
+ for (AltosState state : states)
+ write(state);
}
public AltosCSV(PrintStream in_out, File in_name) {
name = in_name;
out = in_out;
- pad_records = new LinkedList<AltosRecord>();
+ pad_states = new LinkedList<AltosState>();
}
public AltosCSV(File in_name) throws FileNotFoundException {
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
import org.altusmetrum.altosuilib_1.*;
public class AltosCSVUI
JFileChooser csv_chooser;
JPanel accessory;
JComboBox combo_box;
- AltosRecordIterable iterable;
+ Iterable<AltosState> states;
AltosWriter writer;
static String[] combo_box_items = { "Comma Separated Values (.CSV)", "Googleearth Data (.KML)" };
set_default_file();
}
- public AltosCSVUI(JFrame frame, AltosRecordIterable in_iterable, File source_file) {
- iterable = in_iterable;
+ public AltosCSVUI(JFrame frame, AltosStateIterable states, File source_file) {
+ this.states = states;
csv_chooser = new JFileChooser(source_file);
accessory = new JPanel();
writer = new AltosCSV(file);
else
writer = new AltosKML(file);
- writer.write(iterable);
+ writer.write(states);
writer.close();
} catch (FileNotFoundException ee) {
JOptionPane.showMessageDialog(frame,
import java.awt.*;
import javax.swing.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
public class AltosCompanionInfo extends JTable {
private AltosFlightInfoTableModel model;
model.clear();
}
- AltosRecordCompanion companion;
+ AltosCompanion companion;
public String board_name() {
if (companion == null)
return "None";
switch (companion.board_id) {
- case AltosRecordCompanion.board_id_telescience:
+ case AltosCompanion.board_id_telescience:
return "TeleScience";
default:
return String.format("%02x\n", companion.board_id);
public void show(AltosState state, AltosListenerState listener_state) {
if (state == null)
return;
- if (state.data.companion != null)
- companion = state.data.companion;
+ if (state.companion != null)
+ companion = state.companion;
info_reset();
info_add_row(0, "Companion board", "%s", board_name());
if (companion != null) {
import java.io.*;
import java.util.concurrent.*;
import java.text.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
import org.altusmetrum.altosuilib_1.*;
public class AltosConfig implements ActionListener {
} finally {
try {
stop_serial();
+ serial_line.close();
} catch (InterruptedException ie) {
}
- serial_line.close();
}
}
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
import org.altusmetrum.altosuilib_1.*;
class AltosEditFreqUI extends AltosUIDialog implements ActionListener {
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
import org.altusmetrum.altosuilib_1.*;
public class AltosConfigPyroUI
extends AltosUIDialog
- implements ItemListener, DocumentListener
+ implements ItemListener, DocumentListener, AltosUnitsListener
{
AltosConfigUI owner;
Container pane;
}
}
- class PyroItem implements ItemListener, DocumentListener
+ class PyroItem implements ItemListener, DocumentListener, AltosUnitsListener
{
public int flag;
public JRadioButton enable;
public JTextField value;
public JComboBox combo;
AltosConfigPyroUI ui;
+ boolean setting;
public void set_enable(boolean enable) {
if (value != null)
public void itemStateChanged(ItemEvent e) {
set_enable(enable.isSelected());
- ui.set_dirty();
+ if (!setting)
+ ui.set_dirty();
}
public void changedUpdate(DocumentEvent e) {
- ui.set_dirty();
+ if (!setting)
+ ui.set_dirty();
}
public void insertUpdate(DocumentEvent e) {
- ui.set_dirty();
+ if (!setting)
+ ui.set_dirty();
}
public void removeUpdate(DocumentEvent e) {
- ui.set_dirty();
+ if (!setting)
+ ui.set_dirty();
+ }
+
+ public void units_changed(boolean imperial_units) {
+ AltosUnits units = AltosPyro.pyro_to_units(flag);
+
+ if (units != null) {
+ try {
+ double v = units.parse(value.getText(), !imperial_units);
+ set(enabled(), v);
+ } catch (NumberFormatException ne) {
+ set(enabled(), 0.0);
+ }
+ }
}
public void set(boolean new_enable, double new_value) {
+ setting = true;
enable.setSelected(new_enable);
set_enable(new_enable);
if (value != null) {
double scale = AltosPyro.pyro_to_scale(flag);
+ double unit_value = new_value;
+ AltosUnits units = AltosPyro.pyro_to_units(flag);
+ if (units != null)
+ unit_value = units.value(new_value);
String format = "%6.0f";
if (scale >= 10)
format = "%6.1f";
else if (scale >= 100)
format = "%6.2f";
- value.setText(String.format(format, new_value));
+ value.setText(String.format(format, unit_value));
}
if (combo != null)
if (new_value >= AltosLib.ao_flight_boost && new_value <= AltosLib.ao_flight_landed)
combo.setSelectedIndex((int) new_value - AltosLib.ao_flight_boost);
+ setting = false;
}
public boolean enabled() {
}
public double value() {
- if (value != null)
+ if (value != null) {
+ AltosUnits units = AltosPyro.pyro_to_units(flag);
+ if (units != null)
+ return units.parse(value.getText());
return Double.parseDouble(value.getText());
+ }
if (combo != null)
return combo.getSelectedIndex() + AltosLib.ao_flight_boost;
return 0;
}
}
- class PyroColumn {
+ class PyroColumn implements AltosUnitsListener {
public PyroItem[] items;
public JLabel label;
int channel;
for (int flag = 1; flag < AltosPyro.pyro_all; flag <<= 1) {
if ((AltosPyro.pyro_all & flag) != 0) {
if (items[row].enabled()) {
- System.out.printf ("Flag %x enabled\n", flag);
p.flags |= flag;
p.set_value(flag, items[row].value());
}
row++;
}
}
- System.out.printf ("Pyro %x %s\n", p.flags, p.toString());
return p;
}
+ public void units_changed(boolean imperial_units) {
+ int row = 0;
+ for (int flag = 1; flag < AltosPyro.pyro_all; flag <<= 1) {
+ if ((AltosPyro.pyro_all & flag) != 0) {
+ items[row].units_changed(imperial_units);
+ row++;
+ }
+ }
+ }
+
public PyroColumn(AltosConfigPyroUI ui, int x, int y, int in_channel) {
channel = in_channel;
}
PyroColumn[] columns;
+ JLabel[] labels;
public void set_pyros(AltosPyro[] pyros) {
for (int i = 0; i < pyros.length; i++) {
owner.set_dirty();
}
+ public void units_changed(boolean imperial_units) {
+ for (int c = 0; c < columns.length; c++)
+ columns[c].units_changed(imperial_units);
+ int r = 0;
+ for (int flag = 1; flag <= AltosPyro.pyro_all; flag <<= 1) {
+ String n = AltosPyro.pyro_to_name(flag);
+ if (n != null) {
+ labels[r].setText(n);
+ r++;
+ }
+ }
+ }
+
+ /* A window listener to catch closing events and tell the config code */
+ class ConfigListener extends WindowAdapter {
+ AltosConfigPyroUI ui;
+ AltosConfigUI owner;
+
+ public ConfigListener(AltosConfigPyroUI this_ui, AltosConfigUI this_owner) {
+ ui = this_ui;
+ owner = this_owner;
+ }
+
+ public void windowClosing(WindowEvent e) {
+ ui.setVisible(false);
+ }
+ }
+
public AltosConfigPyroUI(AltosConfigUI in_owner, AltosPyro[] pyros) {
super(in_owner, "Configure Pyro Channels", false);
pane = getContentPane();
pane.setLayout(new GridBagLayout());
+ int nrow = 0;
+ for (int flag = 1; flag < AltosPyro.pyro_all; flag <<= 1)
+ if ((flag & AltosPyro.pyro_all) != 0)
+ nrow++;
+
+ labels = new JLabel[nrow];
+
int row = 1;
for (int flag = 1; flag <= AltosPyro.pyro_all; flag <<= 1) {
c.insets = il;
JLabel label = new JLabel(n);
pane.add(label, c);
+ labels[row-1] = label;
row++;
}
}
columns[i] = new PyroColumn(this, i*2 + 1, 0, i);
columns[i].set(pyros[i]);
}
+ addWindowListener(new ConfigListener(this, owner));
+ AltosPreferences.register_units_listener(this);
+ }
+
+ public void dispose() {
+ AltosPreferences.unregister_units_listener(this);
+ super.dispose();
}
public void make_visible() {
import javax.swing.*;
import java.io.*;
import java.util.concurrent.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
import org.altusmetrum.altosuilib_1.*;
public class AltosConfigTD implements ActionListener {
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
import org.altusmetrum.altosuilib_1.*;
public class AltosConfigTDUI
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
import org.altusmetrum.altosuilib_1.*;
public class AltosConfigUI
extends AltosUIDialog
- implements ActionListener, ItemListener, DocumentListener, AltosConfigValues
+ implements ActionListener, ItemListener, DocumentListener, AltosConfigValues, AltosUnitsListener
{
Container pane;
ActionListener listener;
- static String[] main_deploy_values = {
+ static String[] main_deploy_values_m = {
"100", "150", "200", "250", "300", "350",
"400", "450", "500"
};
+ static String[] main_deploy_values_ft = {
+ "250", "500", "750", "1000", "1250", "1500",
+ "1750", "2000"
+ };
+
static String[] apogee_delay_values = {
"0", "1", "2", "3", "4", "5"
};
void set_pad_orientation_tool_tip() {
if (pad_orientation_value.isEnabled())
- pad_orientation_value.setToolTipText("How will TeleMetrum be mounted in the airframe");
+ pad_orientation_value.setToolTipText("How will the computer be mounted in the airframe");
else {
if (is_telemetrum())
pad_orientation_value.setToolTipText("Older TeleMetrum firmware must fly antenna forward");
/* Build the UI using a grid bag */
public AltosConfigUI(JFrame in_owner, boolean remote) {
- super (in_owner, "Configure TeleMetrum", false);
+ super (in_owner, "Configure Flight Computer", false);
owner = in_owner;
GridBagConstraints c;
c.anchor = GridBagConstraints.LINE_START;
c.insets = il;
c.ipady = 5;
- main_deploy_label = new JLabel("Main Deploy Altitude(m):");
+ main_deploy_label = new JLabel(get_main_deploy_label());
pane.add(main_deploy_label, c);
c = new GridBagConstraints();
c.anchor = GridBagConstraints.LINE_START;
c.insets = ir;
c.ipady = 5;
- main_deploy_value = new JComboBox(main_deploy_values);
+ main_deploy_value = new JComboBox(main_deploy_values());
main_deploy_value.setEditable(true);
main_deploy_value.addItemListener(this);
pane.add(main_deploy_value, c);
close.setActionCommand("Close");
addWindowListener(new ConfigListener(this));
+ AltosPreferences.register_units_listener(this);
}
/* Once the initial values are set, the config code will show the dialog */
AltosConfigPyroUI pyro_ui;
+ public void dispose() {
+ if (pyro_ui != null)
+ pyro_ui.dispose();
+ AltosPreferences.unregister_units_listener(this);
+ super.dispose();
+ }
+
/* Listen for events from our buttons */
public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand();
if (cmd.equals("Pyro")) {
- if (pyro_ui == null && pyros != null) {
+ if (pyro_ui == null && pyros != null)
pyro_ui = new AltosConfigPyroUI(this, pyros);
+ if (pyro_ui != null)
pyro_ui.make_visible();
- }
return;
}
}
public void set_main_deploy(int new_main_deploy) {
- main_deploy_value.setSelectedItem(Integer.toString(new_main_deploy));
+ main_deploy_value.setSelectedItem(AltosConvert.height.say(new_main_deploy));
main_deploy_value.setEnabled(new_main_deploy >= 0);
}
public int main_deploy() {
- return Integer.parseInt(main_deploy_value.getSelectedItem().toString());
+ return (int) (AltosConvert.height.parse(main_deploy_value.getSelectedItem().toString()) + 0.5);
+ }
+
+ String get_main_deploy_label() {
+ return String.format("Main Deploy Altitude(%s):", AltosConvert.height.show_units());
+ }
+
+ String[] main_deploy_values() {
+ if (AltosConvert.imperial_units)
+ return main_deploy_values_ft;
+ else
+ return main_deploy_values_m;
+ }
+
+ void set_main_deploy_values() {
+ String[] v = main_deploy_values();
+ while (main_deploy_value.getItemCount() > 0)
+ main_deploy_value.removeItemAt(0);
+ for (int i = 0; i < v.length; i++)
+ main_deploy_value.addItem(v[i]);
+ main_deploy_value.setMaximumRowCount(v.length);
+ }
+
+ public void units_changed(boolean imperial_units) {
+ String v = main_deploy_value.getSelectedItem().toString();
+ main_deploy_label.setText(get_main_deploy_label());
+ set_main_deploy_values();
+ int m = (int) (AltosConvert.height.parse(v, !imperial_units) + 0.5);
+ set_main_deploy(m);
}
public void set_apogee_delay(int new_apogee_delay) {
}
public void set_radio_frequency(double new_radio_frequency) {
- int i;
- for (i = 0; i < radio_frequency_value.getItemCount(); i++) {
- AltosFrequency f = (AltosFrequency) radio_frequency_value.getItemAt(i);
-
- if (f.close(new_radio_frequency)) {
- radio_frequency_value.setSelectedIndex(i);
- return;
- }
- }
- for (i = 0; i < radio_frequency_value.getItemCount(); i++) {
- AltosFrequency f = (AltosFrequency) radio_frequency_value.getItemAt(i);
-
- if (new_radio_frequency < f.frequency)
- break;
- }
- String description = String.format("%s serial %s",
- product_value.getText(),
- serial_value.getText());
- AltosFrequency new_frequency = new AltosFrequency(new_radio_frequency, description);
- AltosUIPreferences.add_common_frequency(new_frequency);
- radio_frequency_value.insertItemAt(new_frequency, i);
- radio_frequency_value.setSelectedIndex(i);
+ radio_frequency_value.set_frequency(new_radio_frequency);
}
public double radio_frequency() {
}
public void set_radio_calibration(int new_radio_calibration) {
- radio_calibration_value.setText(String.format("%d", new_radio_calibration));
+ radio_calibration_value.setVisible(new_radio_calibration >= 0);
+ if (new_radio_calibration < 0)
+ radio_calibration_value.setText("Disabled");
+ else
+ radio_calibration_value.setText(String.format("%d", new_radio_calibration));
}
public int radio_calibration() {
radio_enable_value.setEnabled(true);
} else {
radio_enable_value.setSelected(true);
+ radio_enable_value.setVisible(radio_frequency() > 0);
radio_enable_value.setEnabled(false);
}
set_radio_enable_tool_tip();
}
public void set_callsign(String new_callsign) {
+ callsign_value.setVisible(new_callsign != null);
callsign_value.setText(new_callsign);
}
if (new_pad_orientation >= pad_orientation_values.length)
new_pad_orientation = 0;
if (new_pad_orientation < 0) {
- pad_orientation_value.setEnabled(false);
+ pad_orientation_value.setVisible(false);
new_pad_orientation = 0;
} else {
- pad_orientation_value.setEnabled(true);
+ pad_orientation_value.setVisible(true);
}
pad_orientation_value.setSelectedIndex(new_pad_orientation);
set_pad_orientation_tool_tip();
public void set_pyros(AltosPyro[] new_pyros) {
pyros = new_pyros;
- pyro.setEnabled(pyros != null);
+ pyro.setVisible(pyros != null);
if (pyros != null && pyro_ui != null)
pyro_ui.set_pyros(pyros);
}
else
s = Integer.toString(new_aprs_interval);
aprs_interval_value.setSelectedItem(s);
- aprs_interval_value.setEnabled(new_aprs_interval >= 0);
+ aprs_interval_value.setVisible(new_aprs_interval >= 0);
set_aprs_interval_tool_tip();
}
import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter;
import java.io.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
import org.altusmetrum.altosuilib_1.*;
public class AltosDataChooser extends JFileChooser {
return file;
}
- public AltosRecordIterable runDialog() {
+ public AltosStateIterable runDialog() {
int ret;
ret = showOpenDialog(frame);
try {
if (filename.endsWith("eeprom")) {
FileInputStream in = new FileInputStream(file);
- return new AltosEepromIterable(in);
+ return new AltosEepromFile(in);
} else if (filename.endsWith("telem")) {
FileInputStream in = new FileInputStream(file);
- return new AltosTelemetryIterable(in);
- } else if (filename.endsWith("mega")) {
- FileInputStream in = new FileInputStream(file);
- return new AltosEepromMegaIterable(in);
+ return new AltosTelemetryFile(in);
} else {
throw new FileNotFoundException();
}
"telem"));
setFileFilter(new FileNameExtensionFilter("TeleMega eeprom file",
"mega"));
+ setFileFilter(new FileNameExtensionFilter("EasyMini eeprom file",
+ "mini"));
setFileFilter(new FileNameExtensionFilter("Flight data file",
- "telem", "eeprom", "mega"));
+ "telem", "eeprom", "mega", "mini"));
setCurrentDirectory(AltosUIPreferences.logdir());
}
}
import java.awt.*;
import javax.swing.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
public class AltosDescent extends JComponent implements AltosFlightDisplay {
GridBagLayout layout;
class Height extends DescentValue {
void show (AltosState state, AltosListenerState listener_state) {
- show(AltosConvert.height, state.height);
+ show(AltosConvert.height, state.height());
}
public Height (GridBagLayout layout, int x, int y) {
super (layout, x, y, "Height");
class Speed extends DescentValue {
void show (AltosState state, AltosListenerState listener_state) {
- double speed = state.accel_speed;
- if (!state.ascent)
- speed = state.baro_speed;
- show(AltosConvert.speed, speed);
+ show(AltosConvert.speed, state.speed());
}
public Speed (GridBagLayout layout, int x, int y) {
super (layout, x, y, "Speed");
class Lat extends DescentValue {
void show (AltosState state, AltosListenerState listener_state) {
- if (state.gps != null && state.gps.connected)
+ if (state.gps != null && state.gps.connected && state.gps.lat != AltosLib.MISSING)
show(pos(state.gps.lat,"N", "S"));
else
show("???");
class Lon extends DescentValue {
void show (AltosState state, AltosListenerState listener_state) {
- if (state.gps != null && state.gps.connected)
+ if (state.gps != null && state.gps.connected && state.gps.lon != AltosLib.MISSING)
show(pos(state.gps.lon,"W", "E"));
else
show("???");
class Apogee extends DescentStatus {
void show (AltosState state, AltosListenerState listener_state) {
- show("%4.2f V", state.drogue_sense);
- lights.set(state.drogue_sense > 3.2);
+ show("%4.2f V", state.apogee_voltage);
+ lights.set(state.apogee_voltage >= AltosLib.ao_igniter_good);
}
public Apogee (GridBagLayout layout, int y) {
super(layout, y, "Apogee Igniter Voltage");
class Main extends DescentStatus {
void show (AltosState state, AltosListenerState listener_state) {
- show("%4.2f V", state.main_sense);
- lights.set(state.main_sense > 3.2);
+ show("%4.2f V", state.main_voltage);
+ lights.set(state.main_voltage >= AltosLib.ao_igniter_good);
}
public Main (GridBagLayout layout, int y) {
super(layout, y, "Main Igniter Voltage");
lat.hide();
lon.hide();
}
- if (state.main_sense != AltosRecord.MISSING)
+ if (state.main_voltage != AltosLib.MISSING)
main.show(state, listener_state);
else
main.hide();
- if (state.drogue_sense != AltosRecord.MISSING)
+ if (state.apogee_voltage != AltosLib.MISSING)
apogee.show(state, listener_state);
else
apogee.hide();
import javax.swing.*;
import java.io.*;
import java.text.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
public class AltosDisplayThread extends Thread {
/* If the rocket isn't on the pad, then report height */
if (Altos.ao_flight_drogue <= state.state &&
state.state < Altos.ao_flight_landed &&
+ state.from_pad != null &&
state.range >= 0)
{
voice.speak("Height %s, bearing %s %d, elevation %d, range %s.\n",
- AltosConvert.height.say(state.height),
+ AltosConvert.height.say(state.height()),
state.from_pad.bearing_words(
AltosGreatCircle.BEARING_VOICE),
(int) (state.from_pad.bearing + 0.5),
(int) (state.elevation + 0.5),
AltosConvert.distance.say(state.range));
} else if (state.state > Altos.ao_flight_pad) {
- voice.speak(AltosConvert.height.say_units(state.height));
+ voice.speak(AltosConvert.height.say_units(state.height()));
} else {
reported_landing = 0;
}
*/
if (state.state >= Altos.ao_flight_drogue &&
(last ||
- System.currentTimeMillis() - state.report_time >= 15000 ||
+ System.currentTimeMillis() - state.received_time >= 15000 ||
state.state == Altos.ao_flight_landed))
{
- if (Math.abs(state.baro_speed) < 20 && state.height < 100)
+ if (Math.abs(state.speed()) < 20 && state.height() < 100)
voice.speak("rocket landed safely");
else
voice.speak("rocket may have crashed");
synchronized boolean tell() {
boolean ret = false;
if (old_state == null || old_state.state != state.state) {
- voice.speak(state.data.state());
+ voice.speak(state.state_name());
if ((old_state == null || old_state.state <= Altos.ao_flight_boost) &&
state.state > Altos.ao_flight_boost) {
voice.speak("max speed: %s.",
- AltosConvert.speed.say_units(state.max_accel_speed + 0.5));
+ AltosConvert.speed.say_units(state.max_speed() + 0.5));
ret = true;
} else if ((old_state == null || old_state.state < Altos.ao_flight_drogue) &&
state.state >= Altos.ao_flight_drogue) {
voice.speak("max height: %s.",
- AltosConvert.height.say_units(state.max_height + 0.5));
+ AltosConvert.height.say_units(state.max_height() + 0.5));
ret = true;
}
}
try {
for (;;) {
try {
- AltosRecord record = reader.read();
- if (record == null)
+ state = reader.read();
+ if (state == null)
break;
- old_state = state;
- state = new AltosState(record, state);
reader.update(state);
show_safely();
told = tell();
import javax.swing.*;
import java.io.*;
import java.util.concurrent.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
public class AltosEepromDelete implements Runnable {
AltosEepromList flights;
+++ /dev/null
-/*
- * 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.event.*;
-import javax.swing.*;
-import java.io.*;
-import java.util.*;
-import java.text.*;
-import java.util.concurrent.*;
-import org.altusmetrum.altoslib_1.*;
-
-public class AltosEepromDownload implements Runnable {
-
- JFrame frame;
- AltosSerial serial_line;
- boolean remote;
- Thread eeprom_thread;
- AltosEepromMonitor monitor;
-
- int flight;
- int serial;
- int year, month, day;
- boolean want_file;
- FileWriter eeprom_file;
- LinkedList<String> eeprom_pending;
-
- AltosEepromList flights;
- ActionListener listener;
- boolean success;
- ParseException parse_exception;
- String extension;
-
- private void FlushPending() throws IOException {
- for (String s : flights.config_data) {
- eeprom_file.write(s);
- eeprom_file.write('\n');
- }
-
- for (String s : eeprom_pending)
- eeprom_file.write(s);
- }
-
- private void CheckFile(boolean force) throws IOException {
- if (eeprom_file != null)
- return;
- if (force || (flight != 0 && want_file)) {
- AltosFile eeprom_name;
-
- if (extension == null)
- extension = "data";
- if (year != 0 && month != 0 && day != 0)
- eeprom_name = new AltosFile(year, month, day, serial, flight, extension);
- else
- eeprom_name = new AltosFile(serial, flight, extension);
-
- eeprom_file = new FileWriter(eeprom_name);
- if (eeprom_file != null) {
- monitor.set_file(eeprom_name.getName());
- FlushPending();
- eeprom_pending = null;
- }
- }
- }
-
- void Log(AltosEepromRecord r) throws IOException {
- if (r.cmd != Altos.AO_LOG_INVALID) {
- String log_line = String.format("%c %4x %4x %4x\n",
- r.cmd, r.tick, r.a, r.b);
- if (eeprom_file != null)
- eeprom_file.write(log_line);
- else
- eeprom_pending.add(log_line);
- }
- }
-
- void set_serial(int in_serial) {
- serial = in_serial;
- monitor.set_serial(serial);
- }
-
- void set_flight(int in_flight) {
- flight = in_flight;
- monitor.set_flight(flight);
- }
-
- boolean done;
- int state;
-
- void CaptureFull(AltosEepromChunk eechunk) throws IOException {
- boolean any_valid = false;
-
- extension = "eeprom";
- set_serial(flights.config_data.serial);
- for (int i = 0; i < AltosEepromChunk.chunk_size && !done; i += AltosEepromRecord.record_length) {
- try {
- AltosEepromRecord r = new AltosEepromRecord(eechunk, i);
- if (r.cmd == Altos.AO_LOG_FLIGHT)
- set_flight(r.b);
-
- /* Monitor state transitions to update display */
- if (r.cmd == Altos.AO_LOG_STATE && r.a <= Altos.ao_flight_landed) {
- state = r.a;
- if (state > Altos.ao_flight_pad)
- want_file = true;
- }
-
- if (r.cmd == Altos.AO_LOG_GPS_DATE) {
- year = 2000 + (r.a & 0xff);
- month = (r.a >> 8) & 0xff;
- day = (r.b & 0xff);
- want_file = true;
- }
- if (r.cmd == Altos.AO_LOG_STATE && r.a == Altos.ao_flight_landed)
- done = true;
- if (r.cmd != AltosLib.AO_LOG_INVALID)
- any_valid = true;
- Log(r);
- } catch (ParseException pe) {
- if (parse_exception == null)
- parse_exception = pe;
- }
- }
-
- if (!any_valid)
- done = true;
-
- CheckFile(false);
- }
-
- boolean start;
- int tiny_tick;
-
- void CaptureTiny (AltosEepromChunk eechunk) throws IOException {
- boolean any_valid = false;
-
- extension = "eeprom";
- set_serial(flights.config_data.serial);
- for (int i = 0; i < eechunk.data.length && !done; i += 2) {
- int v = eechunk.data16(i);
- AltosEepromRecord r;
-
- if (i == 0 && start) {
- tiny_tick = 0;
- start = false;
- set_flight(v);
- r = new AltosEepromRecord(Altos.AO_LOG_FLIGHT, tiny_tick, 0, v);
- any_valid = true;
- } else {
- int s = v ^ 0x8000;
-
- if (Altos.ao_flight_startup <= s && s <= Altos.ao_flight_invalid) {
- state = s;
- r = new AltosEepromRecord(Altos.AO_LOG_STATE, tiny_tick, state, 0);
- if (state == Altos.ao_flight_landed)
- done = true;
- state = s;
- any_valid = true;
- } else {
- if (v != 0xffff)
- any_valid = true;
-
- r = new AltosEepromRecord(Altos.AO_LOG_PRESSURE, tiny_tick, 0, v);
-
- /*
- * The flight software records ascent data every 100ms, and descent
- * data every 1s.
- */
- if (state < Altos.ao_flight_drogue)
- tiny_tick += 10;
- else
- tiny_tick += 100;
- }
- }
- Log(r);
- }
- CheckFile(false);
- if (!any_valid)
- done = true;
- }
-
- void LogTeleScience(AltosEepromTeleScience r) throws IOException {
- if (r.type != Altos.AO_LOG_INVALID) {
- String log_line = String.format("%c %4x %4x %d %5d %5d %5d %5d %5d %5d %5d %5d %5d %5d %5d %5d\n",
- r.type, r.tick, r.tm_tick, r.tm_state,
- r.data[0], r.data[1], r.data[2], r.data[3],
- r.data[4], r.data[5], r.data[6], r.data[7],
- r.data[8], r.data[9], r.data[10], r.data[11]);
- if (eeprom_file != null)
- eeprom_file.write(log_line);
- else
- eeprom_pending.add(log_line);
- }
- }
-
- boolean telescience_start;
-
- void CaptureTeleScience (AltosEepromChunk eechunk) throws IOException {
- boolean any_valid = false;
-
- extension = "science";
- for (int i = 0; i < AltosEepromChunk.chunk_size && !done; i += AltosEepromTeleScience.record_length) {
- try {
- AltosEepromTeleScience r = new AltosEepromTeleScience(eechunk, i);
- if (r.type == AltosEepromTeleScience.AO_LOG_TELESCIENCE_START) {
- if (telescience_start) {
- done = true;
- break;
- }
- set_serial(r.data[0]);
- set_flight(r.data[1]);
- telescience_start = true;
- } else {
- if (!telescience_start)
- break;
- }
- state = r.tm_state;
- want_file =true;
- any_valid = true;
- LogTeleScience(r);
- } catch (ParseException pe) {
- if (parse_exception == null)
- parse_exception = pe;
- }
- }
-
- CheckFile(false);
- if (!any_valid)
- done = true;
- }
-
- void LogMega(AltosEepromMega r) throws IOException {
- if (r.cmd != Altos.AO_LOG_INVALID) {
- String log_line = String.format("%c %4x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x\n",
- r.cmd, r.tick,
- r.data8[0], r.data8[1], r.data8[2], r.data8[3],
- r.data8[4], r.data8[5], r.data8[6], r.data8[7],
- r.data8[8], r.data8[9], r.data8[10], r.data8[11],
- r.data8[12], r.data8[13], r.data8[14], r.data8[15],
- r.data8[16], r.data8[17], r.data8[18], r.data8[19],
- r.data8[20], r.data8[21], r.data8[22], r.data8[23],
- r.data8[24], r.data8[25], r.data8[26], r.data8[27]);
- if (eeprom_file != null)
- eeprom_file.write(log_line);
- else
- eeprom_pending.add(log_line);
- }
- }
-
- void CaptureMega(AltosEepromChunk eechunk) throws IOException {
- boolean any_valid = false;
-
- extension = "mega";
- set_serial(flights.config_data.serial);
- for (int i = 0; i < AltosEepromChunk.chunk_size && !done; i += AltosEepromMega.record_length) {
- try {
- AltosEepromMega r = new AltosEepromMega(eechunk, i);
- if (r.cmd == Altos.AO_LOG_FLIGHT)
- set_flight(r.data16(0));
-
- /* Monitor state transitions to update display */
- if (r.cmd == Altos.AO_LOG_STATE && r.data16(0) <= Altos.ao_flight_landed) {
- state = r.data16(0);
- if (state > Altos.ao_flight_pad)
- want_file = true;
- }
-
- if (r.cmd == Altos.AO_LOG_GPS_TIME) {
- year = 2000 + r.data8(14);
- month = r.data8(15);
- day = r.data8(16);
- want_file = true;
- }
-
- if (r.cmd == Altos.AO_LOG_STATE && r.data16(0) == Altos.ao_flight_landed)
- done = true;
- any_valid = true;
- LogMega(r);
- } catch (ParseException pe) {
- if (parse_exception == null)
- parse_exception = pe;
- }
- }
- if (!any_valid)
- done = true;
-
- CheckFile(false);
- }
-
- void CaptureTelemetry(AltosEepromChunk eechunk) throws IOException {
-
- }
-
- void CaptureLog(AltosEepromLog log) throws IOException, InterruptedException, TimeoutException {
- int block, state_block = 0;
- int log_format = flights.config_data.log_format;
-
- state = 0;
- done = false;
- start = true;
-
- if (flights.config_data.serial < 0)
- throw new IOException("no serial number found");
-
- /* Reset per-capture variables */
- flight = 0;
- year = 0;
- month = 0;
- day = 0;
- want_file = false;
- eeprom_file = null;
- eeprom_pending = new LinkedList<String>();
-
- /* Set serial number in the monitor dialog window */
- /* Now scan the eeprom, reading blocks of data and converting to .eeprom file form */
-
- state = 0; state_block = log.start_block;
- for (block = log.start_block; !done && block < log.end_block; block++) {
- monitor.set_value(AltosLib.state_name(state), state, block - state_block, block - log.start_block);
-
- AltosEepromChunk eechunk = new AltosEepromChunk(serial_line, block, block == log.start_block);
-
- /*
- * Guess what kind of data is there if the device
- * didn't tell us
- */
-
- if (log_format == Altos.AO_LOG_FORMAT_UNKNOWN) {
- if (block == log.start_block) {
- if (eechunk.data(0) == Altos.AO_LOG_FLIGHT)
- log_format = Altos.AO_LOG_FORMAT_FULL;
- else
- log_format = Altos.AO_LOG_FORMAT_TINY;
- }
- }
-
- switch (log_format) {
- case AltosLib.AO_LOG_FORMAT_FULL:
- extension = "eeprom";
- CaptureFull(eechunk);
- break;
- case AltosLib.AO_LOG_FORMAT_TINY:
- extension = "eeprom";
- CaptureTiny(eechunk);
- break;
- case AltosLib.AO_LOG_FORMAT_TELEMETRY:
- extension = "telem";
- CaptureTelemetry(eechunk);
- break;
- case AltosLib.AO_LOG_FORMAT_TELESCIENCE:
- extension = "science";
- CaptureTeleScience(eechunk);
- break;
- case AltosLib.AO_LOG_FORMAT_TELEMEGA:
- extension = "mega";
- CaptureMega(eechunk);
- }
- }
- CheckFile(true);
- if (eeprom_file != null) {
- eeprom_file.flush();
- eeprom_file.close();
- }
- }
-
- private void show_message_internal(String message, String title, int message_type) {
- JOptionPane.showMessageDialog(frame,
- message,
- title,
- message_type);
- }
-
- private void show_message(String in_message, String in_title, int in_message_type) {
- final String message = in_message;
- final String title = in_title;
- final int message_type = in_message_type;
- Runnable r = new Runnable() {
- public void run() {
- try {
- show_message_internal(message, title, message_type);
- } catch (Exception ex) {
- }
- }
- };
- SwingUtilities.invokeLater(r);
- }
-
- public void run () {
- try {
- boolean failed = false;
- if (remote)
- serial_line.start_remote();
-
- for (AltosEepromLog log : flights) {
- parse_exception = null;
- if (log.selected) {
- monitor.reset();
- CaptureLog(log);
- }
- if (parse_exception != null) {
- failed = true;
- show_message(String.format("Flight %d download error\n%s\nValid log data saved",
- log.flight,
- parse_exception.getMessage()),
- serial_line.device.toShortString(),
- JOptionPane.WARNING_MESSAGE);
- }
- }
- success = !failed;
- } catch (IOException ee) {
- show_message(ee.getLocalizedMessage(),
- serial_line.device.toShortString(),
- JOptionPane.ERROR_MESSAGE);
- } catch (InterruptedException ie) {
- System.out.printf("download interrupted\n");
- } catch (TimeoutException te) {
- show_message(String.format("Connection to \"%s\" failed",
- serial_line.device.toShortString()),
- "Connection Failed",
- JOptionPane.ERROR_MESSAGE);
- } finally {
- if (remote) {
- try {
- serial_line.stop_remote();
- } catch (InterruptedException ie) {
- }
- }
- serial_line.flush_output();
- }
- monitor.done();
- if (listener != null) {
- Runnable r = new Runnable() {
- public void run() {
- try {
- listener.actionPerformed(new ActionEvent(this,
- success ? 1 : 0,
- "download"));
- } catch (Exception ex) {
- }
- }
- };
- SwingUtilities.invokeLater(r);
- }
- }
-
- public void start() {
- eeprom_thread = new Thread(this);
- eeprom_thread.start();
- }
-
- public void addActionListener(ActionListener l) {
- listener = l;
- }
-
- public AltosEepromDownload(JFrame given_frame,
- AltosSerial given_serial_line,
- boolean given_remote,
- AltosEepromList given_flights) {
-
- frame = given_frame;
- serial_line = given_serial_line;
- serial_line.set_frame(frame);
- remote = given_remote;
- flights = given_flights;
- success = false;
-
- monitor = new AltosEepromMonitor(frame, Altos.ao_flight_boost, Altos.ao_flight_landed);
- monitor.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- if (eeprom_thread != null)
- eeprom_thread.interrupt();
- }
- });
- }
-}
+++ /dev/null
-/*
- * Copyright © 2011 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-package altosui;
-
-import java.io.*;
-import java.util.*;
-import java.text.*;
-import java.util.concurrent.*;
-import org.altusmetrum.altoslib_1.*;
-
-/*
- * Temporary structure to hold the list of stored flights;
- * each of these will be queried in turn to generate more
- * complete information
- */
-
-class AltosEepromFlight {
- int flight;
- int start;
- int end;
-
- public AltosEepromFlight(int in_flight, int in_start, int in_end) {
- flight = in_flight;
- start = in_start;
- end = in_end;
- }
-}
-
-/*
- * Construct a list of flights available in a connected device
- */
-
-public class AltosEepromList extends ArrayList<AltosEepromLog> {
- AltosConfigData config_data;
-
- public AltosEepromList (AltosSerial serial_line, boolean remote)
- throws IOException, InterruptedException, TimeoutException
- {
- try {
- if (remote)
- serial_line.start_remote();
- config_data = new AltosConfigData (serial_line);
-// if (config_data.serial == 0)
-// throw new IOException("no serial number found");
-
- ArrayList<AltosEepromFlight> flights = new ArrayList<AltosEepromFlight>();
-
- if (config_data.flight_log_max != 0 || config_data.log_format != 0) {
-
- /* Devices with newer firmware will support the 'l'
- * command which will list the region of storage
- * occupied by each available flight
- */
- serial_line.printf("l\n");
- for (;;) {
- String line = serial_line.get_reply(5000);
- if (line == null)
- throw new TimeoutException();
- if (line.contains("done"))
- break;
- if (line.contains("Syntax"))
- continue;
- String[] tokens = line.split("\\s+");
- if (tokens.length < 6)
- break;
-
- int flight = -1, start = -1, end = -1;
- try {
- if (tokens[0].equals("flight"))
- flight = AltosParse.parse_int(tokens[1]);
- if (tokens[2].equals("start"))
- start = AltosParse.parse_hex(tokens[3]);
- if (tokens[4].equals("end"))
- end = AltosParse.parse_hex(tokens[5]);
- if (flight > 0 && start >= 0 && end > 0)
- flights.add(new AltosEepromFlight(flight, start, end));
- } catch (ParseException pe) { System.out.printf("Parse error %s\n", pe.toString()); }
- }
- } else {
-
- /* Older devices will hold only a single
- * flight. This also assumes that any older
- * device will have a 1MB flash device
- */
- flights.add(new AltosEepromFlight(0, 0, 0xfff));
- }
-
- /* With the list of flights collected, collect more complete
- * information on them by reading the first block or two of
- * data. This will add GPS coordinates and a date. For older
- * firmware, this will also extract the flight number.
- */
- for (AltosEepromFlight flight : flights) {
- add(new AltosEepromLog(config_data, serial_line,
- flight.flight, flight.start, flight.end));
- }
- } finally {
- if (remote)
- serial_line.stop_remote();
- serial_line.flush_output();
- }
- }
-}
\ No newline at end of file
import javax.swing.*;
import java.io.*;
import java.util.concurrent.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
import org.altusmetrum.altosuilib_1.*;
public class AltosEepromManage implements ActionListener {
for (AltosEepromLog flight : flights)
any_selected = any_selected || flight.selected;
if (any_selected) {
- download = new AltosEepromDownload(frame,
+ AltosEepromMonitorUI monitor = new AltosEepromMonitorUI(frame);
+ monitor.addActionListener(this);
+ serial_line.set_frame(frame);
+ download = new AltosEepromDownload(monitor,
serial_line,
remote,
flights);
- download.addActionListener(this);
/*
* Start flight log download
*/
--- /dev/null
+/*
+ * 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 org.altusmetrum.altosuilib_1.*;
+import org.altusmetrum.altoslib_2.*;
+
+public class AltosEepromMonitorUI extends AltosUIDialog implements AltosEepromMonitor {
+ JFrame owner;
+ Container pane;
+ Box box;
+ JLabel serial_label;
+ JLabel flight_label;
+ JLabel file_label;
+ JLabel serial_value;
+ JLabel flight_value;
+ JLabel file_value;
+ JButton cancel;
+ JProgressBar pbar;
+ int min_state, max_state;
+ ActionListener listener;
+
+ public AltosEepromMonitorUI(JFrame owner) {
+ super (owner, "Download Flight Data", false);
+
+ this.owner = 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());
+
+ c = new GridBagConstraints();
+ c.gridx = 0; c.gridy = 0;
+ c.fill = GridBagConstraints.NONE;
+ c.anchor = GridBagConstraints.LINE_START;
+ c.insets = il;
+ serial_label = new JLabel("Serial:");
+ pane.add(serial_label, c);
+
+ c = new GridBagConstraints();
+ c.gridx = 1; c.gridy = 0;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.weightx = 1;
+ c.anchor = GridBagConstraints.LINE_START;
+ c.insets = ir;
+ serial_value = new JLabel("");
+ pane.add(serial_value, c);
+
+ c = new GridBagConstraints();
+ c.fill = GridBagConstraints.NONE;
+ c.gridx = 0; c.gridy = 1;
+ c.anchor = GridBagConstraints.LINE_START;
+ c.insets = il;
+ flight_label = new JLabel("Flight:");
+ pane.add(flight_label, c);
+
+ c = new GridBagConstraints();
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.weightx = 1;
+ c.gridx = 1; c.gridy = 1;
+ c.anchor = GridBagConstraints.LINE_START;
+ c.insets = ir;
+ flight_value = new JLabel("");
+ pane.add(flight_value, c);
+
+ c = new GridBagConstraints();
+ c.fill = GridBagConstraints.NONE;
+ c.gridx = 0; c.gridy = 2;
+ c.anchor = GridBagConstraints.LINE_START;
+ c.insets = il;
+ file_label = new JLabel("File:");
+ pane.add(file_label, c);
+
+ c = new GridBagConstraints();
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.weightx = 1;
+ c.gridx = 1; c.gridy = 2;
+ c.anchor = GridBagConstraints.LINE_START;
+ c.insets = ir;
+ file_value = new JLabel("");
+ pane.add(file_value, c);
+
+ pbar = new JProgressBar();
+ pbar.setMinimum(0);
+ pbar.setMaximum(1000);
+ pbar.setValue(0);
+ pbar.setString("startup");
+ pbar.setStringPainted(true);
+ pbar.setPreferredSize(new Dimension(600, 20));
+ c = new GridBagConstraints();
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.anchor = GridBagConstraints.CENTER;
+ c.gridx = 0; c.gridy = 3;
+ c.gridwidth = GridBagConstraints.REMAINDER;
+ Insets ib = new Insets(4,4,4,4);
+ c.insets = ib;
+ pane.add(pbar, c);
+
+
+ cancel = new JButton("Cancel");
+ c = new GridBagConstraints();
+ c.fill = GridBagConstraints.NONE;
+ c.anchor = GridBagConstraints.CENTER;
+ c.gridx = 0; c.gridy = 4;
+ c.gridwidth = GridBagConstraints.REMAINDER;
+ Insets ic = new Insets(4,4,4,4);
+ c.insets = ic;
+ pane.add(cancel, c);
+
+ pack();
+ setLocationRelativeTo(owner);
+ }
+
+ public void addActionListener(ActionListener l) {
+ listener = l;
+ }
+
+ public void set_states(int min_state, int max_state) {
+ this.min_state = min_state;
+ this.max_state = max_state;
+ }
+
+ public void set_thread(Thread in_eeprom_thread) {
+ final Thread eeprom_thread = in_eeprom_thread;
+ cancel.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ if (eeprom_thread != null)
+ eeprom_thread.interrupt();
+ }
+ });
+ }
+
+ public void start() {
+ setVisible(true);
+ }
+
+ private void set_value_internal(String state_name, int state, int state_block, int block) {
+ if (state_block > 100)
+ state_block = 100;
+ if (state < min_state) state = min_state;
+ if (state >= max_state) state = max_state - 1;
+ state -= min_state;
+
+ int pos = state * 100 + state_block;
+
+ pbar.setString(String.format("block %d state %s", block, state_name));
+ pbar.setValue(pos);
+ }
+
+ public void set_value(String in_state_name, int in_state, int in_state_block, int in_block) {
+ final String state_name = in_state_name;
+ final int state = in_state;
+ final int state_block = in_state_block;
+ final int block = in_block;
+ Runnable r = new Runnable() {
+ public void run() {
+ try {
+ set_value_internal(state_name, state, state_block, block);
+ } catch (Exception ex) {
+ }
+ }
+ };
+ SwingUtilities.invokeLater(r);
+ }
+
+ private void set_serial_internal(int serial) {
+ serial_value.setText(String.format("%d", serial));
+ }
+
+ public void set_serial(int in_serial) {
+ final int serial = in_serial;
+ Runnable r = new Runnable() {
+ public void run() {
+ try {
+ set_serial_internal(serial);
+ } catch (Exception ex) {
+ }
+ }
+ };
+ SwingUtilities.invokeLater(r);
+ }
+
+ private void set_flight_internal(int flight) {
+ flight_value.setText(String.format("%d", flight));
+ }
+
+ public void set_flight(int in_flight) {
+ final int flight = in_flight;
+ Runnable r = new Runnable() {
+ public void run() {
+ try {
+ set_flight_internal(flight);
+ } catch (Exception ex) {
+ }
+ }
+ };
+ SwingUtilities.invokeLater(r);
+ }
+
+ private void set_filename_internal(String filename) {
+ file_value.setText(String.format("%s", filename));
+ }
+
+ public void set_filename(String in_filename) {
+ final String filename = in_filename;
+ Runnable r = new Runnable() {
+ public void run() {
+ try {
+ set_filename_internal(filename);
+ } catch (Exception ex) {
+ }
+ }
+ };
+ SwingUtilities.invokeLater(r);
+ }
+
+ private void done_internal(boolean success) {
+ listener.actionPerformed(new ActionEvent(this,
+ success ? 1 : 0,
+ "download"));
+ setVisible(false);
+ dispose();
+ }
+
+ public void done(boolean in_success) {
+ final boolean success = in_success;
+ Runnable r = new Runnable() {
+ public void run() {
+ try {
+ done_internal(success);
+ } catch (Exception ex) {
+ }
+ }
+ };
+ SwingUtilities.invokeLater(r);
+ }
+
+ private void reset_internal() {
+ set_value_internal("startup",min_state,0, 0);
+ set_flight_internal(0);
+ set_filename_internal("");
+ }
+
+ public void reset() {
+ Runnable r = new Runnable() {
+ public void run() {
+ try {
+ reset_internal();
+ } catch (Exception ex) {
+ }
+ }
+ };
+ SwingUtilities.invokeLater(r);
+ }
+
+ private void show_message_internal(String message, String title, int message_type) {
+ int joption_message_type = JOptionPane.ERROR_MESSAGE;
+
+ switch (message_type) {
+ case INFO_MESSAGE:
+ joption_message_type = JOptionPane.INFORMATION_MESSAGE;
+ break;
+ case WARNING_MESSAGE:
+ joption_message_type = JOptionPane.WARNING_MESSAGE;
+ break;
+ case ERROR_MESSAGE:
+ joption_message_type = JOptionPane.ERROR_MESSAGE;
+ break;
+ }
+ JOptionPane.showMessageDialog(owner,
+ message,
+ title,
+ joption_message_type);
+ }
+
+ public void show_message(String in_message, String in_title, int in_message_type) {
+ final String message = in_message;
+ final String title = in_title;
+ final int message_type = in_message_type;
+ Runnable r = new Runnable() {
+ public void run() {
+ try {
+ show_message_internal(message, title, message_type);
+ } catch (Exception ex) {
+ }
+ }
+ };
+ SwingUtilities.invokeLater(r);
+ }
+}
import javax.swing.border.*;
import java.awt.*;
import java.awt.event.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
import org.altusmetrum.altosuilib_1.*;
class AltosEepromItem implements ActionListener {
import javax.swing.filechooser.FileNameExtensionFilter;
import java.io.*;
import java.util.concurrent.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
import org.altusmetrum.altosuilib_1.*;
public class AltosFlashUI
File file;
// Debug connection
- AltosDevice debug_dongle;
+ AltosDevice device;
+
+ AltosLink link;
// Desired Rom configuration
AltosRomconfig rom_config;
// Flash controller
- AltosFlash flash;
+ AltosProgrammer programmer;
+
+ private static String[] pair_programmed = {
+ "teleballoon",
+ "telebt",
+ "teledongle",
+ "telefire",
+ "telemetrum-v0",
+ "telemetrum-v1",
+ "telemini",
+ "telenano",
+ "teleshield",
+ "teleterra"
+ };
+
+ private boolean is_pair_programmed() {
+
+ if (file != null) {
+ String name = file.getName();
+ for (int i = 0; i < pair_programmed.length; i++) {
+ if (name.startsWith(pair_programmed[i]))
+ return true;
+ }
+ }
+ if (device != null) {
+ if (!device.matchProduct(AltosLib.product_altusmetrum) &&
+ (device.matchProduct(AltosLib.product_teledongle) ||
+ device.matchProduct(AltosLib.product_telebt)))
+ return true;
+ }
+ return false;
+ }
public void actionPerformed(ActionEvent e) {
if (e.getSource() == cancel) {
- if (flash != null)
- flash.abort();
+ if (programmer != null)
+ programmer.abort();
setVisible(false);
dispose();
} else {
serial_value.setText(String.format("%d", serial_number));
}
+ static class AltosHexfileFilter extends javax.swing.filechooser.FileFilter {
+ int product;
+ String head;
+ String description;
+
+ public AltosHexfileFilter(int product, String head, String description) {
+ this.product = product;
+ this.head = head;
+ this.description = description;
+ }
+
+ public boolean accept(File file) {
+ return !file.isFile() || (file.getName().startsWith(head) && file.getName().endsWith(".ihx"));
+ }
+
+ public String getDescription() {
+ return description;
+ }
+ }
+
+ static AltosHexfileFilter[] filters = {
+ new AltosHexfileFilter(AltosLib.product_telemetrum, "telemetrum", "TeleMetrum Image"),
+ new AltosHexfileFilter(AltosLib.product_teledongle, "teledongle", "TeleDongle Image"),
+ new AltosHexfileFilter(AltosLib.product_telemega, "telemega", "TeleMega Image"),
+ new AltosHexfileFilter(AltosLib.product_easymini, "easymini", "EasyMini Image"),
+ };
+
boolean select_source_file() {
JFileChooser hexfile_chooser = new JFileChooser();
hexfile_chooser.setCurrentDirectory(firmwaredir);
hexfile_chooser.setDialogTitle("Select Flash Image");
- hexfile_chooser.setFileFilter(new FileNameExtensionFilter("Flash Image", "ihx"));
+
+ for (int i = 0; i < filters.length; i++) {
+ hexfile_chooser.addChoosableFileFilter(filters[i]);
+ }
+ javax.swing.filechooser.FileFilter ihx_filter = new FileNameExtensionFilter("Flash Image", "ihx");
+ hexfile_chooser.addChoosableFileFilter(ihx_filter);
+ hexfile_chooser.setFileFilter(ihx_filter);
+
+ if (!is_pair_programmed() && !device.matchProduct(AltosLib.product_altusmetrum)) {
+ for (int i = 0; i < filters.length; i++) {
+ if (device != null && device.matchProduct(filters[i].product))
+ hexfile_chooser.setFileFilter(filters[i]);
+ }
+ }
+
int returnVal = hexfile_chooser.showOpenDialog(frame);
if (returnVal != JFileChooser.APPROVE_OPTION)
if (file == null)
return false;
AltosUIPreferences.set_firmwaredir(file.getParentFile());
+
return true;
}
- boolean select_debug_dongle() {
- debug_dongle = AltosDeviceUIDialog.show(frame, Altos.product_any);
+ boolean select_device() {
+ int product = Altos.product_any;
- if (debug_dongle == null)
+ device = AltosDeviceUIDialog.show(frame, Altos.product_any);
+
+ if (device == null)
return false;
return true;
}
} else if (e instanceof AltosSerialInUseException) {
JOptionPane.showMessageDialog(frame,
String.format("Device \"%s\" already in use",
- debug_dongle.toShortString()),
+ device.toShortString()),
"Device in use",
JOptionPane.ERROR_MESSAGE);
} else if (e instanceof IOException) {
class flash_task implements Runnable, AltosFlashListener {
AltosFlashUI ui;
Thread t;
- AltosFlash flash;
+ AltosProgrammer programmer;
public void position(String in_s, int in_percent) {
final String s = in_s;
public void run () {
try {
- flash = new AltosFlash(ui.file, new AltosSerial(ui.debug_dongle), this);
+ if (ui.is_pair_programmed())
+ programmer = new AltosFlash(ui.file, link, this);
+ else
+ programmer = new AltosSelfFlash(ui.file, link, this);
- final AltosRomconfig current_config = flash.romconfig();
+ final AltosRomconfig current_config = programmer.romconfig();
final Semaphore await_rom_config = new Semaphore(0);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
- ui.flash = flash;
+ ui.programmer = programmer;
ui.update_rom_config_info(current_config);
await_rom_config.release();
}
await_rom_config.acquire();
if (ui.rom_config != null) {
- flash.set_romconfig(ui.rom_config);
- flash.flash();
+ programmer.set_romconfig(ui.rom_config);
+ programmer.flash();
}
} catch (InterruptedException ee) {
final Exception e = ee;
ui.exception(e);
}
});
- } catch (AltosSerialInUseException ee) {
- final Exception e = ee;
- SwingUtilities.invokeLater(new Runnable() {
- public void run() {
- ui.exception(e);
- }
- });
} finally {
- if (flash != null)
- flash.close();
+ if (programmer != null)
+ programmer.close();
}
}
flash_task flasher;
+ private boolean open_device() throws InterruptedException {
+ try {
+ link = new AltosSerial(device);
+ if (is_pair_programmed())
+ return true;
+
+ if (link == null)
+ throw new IOException(String.format("%s: open failed", device.toShortString()));
+
+ while (!link.is_loader()) {
+ link.to_loader();
+
+ java.util.List<AltosDevice> devices = AltosUSBDevice.list(AltosLib.product_altusmetrum);
+ if (devices.size() == 1)
+ device = devices.get(0);
+ else {
+ device = AltosDeviceUIDialog.show(frame, AltosLib.product_altusmetrum);
+ if (device == null)
+ return false;
+ }
+ link = new AltosSerial(device);
+ }
+ return true;
+ } catch (AltosSerialInUseException ee) {
+ exception(ee);
+ } catch (FileNotFoundException fe) {
+ exception(fe);
+ } catch (IOException ie) {
+ exception (ie);
+ }
+ return false;
+ }
+
/*
* Execute the steps for flashing
* a device. Note that this returns immediately;
* this dialog is not modal
*/
void showDialog() {
- if (!select_debug_dongle())
+ if (!select_device())
return;
if (!select_source_file())
return;
+ try {
+ if (!open_device())
+ return;
+ } catch (InterruptedException ie) {
+ return;
+ }
build_dialog();
flash_task f = new flash_task(this);
}
package altosui;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
public interface AltosFlightDisplay {
void reset();
package altosui;
import java.io.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
public class AltosFlightStats {
double max_height;
double max_speed;
double max_acceleration;
- double[] state_accel_speed = new double[Altos.ao_flight_invalid + 1];
- double[] state_baro_speed = new double[Altos.ao_flight_invalid + 1];
+ double[] state_speed = new double[Altos.ao_flight_invalid + 1];
double[] state_accel = new double[Altos.ao_flight_invalid + 1];
int[] state_count = new int[Altos.ao_flight_invalid + 1];
double[] state_start = new double[Altos.ao_flight_invalid + 1];
boolean has_other_adc;
boolean has_rssi;
- double landed_time(AltosRecordIterable iterable) {
- AltosState state = null;
- for (AltosRecord record : iterable) {
- state = new AltosState(record, state);
+ double landed_time(AltosStateIterable states) {
+ AltosState state = null;
+ for (AltosState s : states) {
+ state = s;
if (state.state == Altos.ao_flight_landed)
break;
}
- double landed_height = state.height;
+ if (state == null)
+ return 0;
+
+ double landed_height = state.height();
state = null;
double landed_time = -1000;
- for (AltosRecord record : iterable) {
- state = new AltosState(record, state);
+ for (AltosState s : states) {
+ state = s;
- if (state.height > landed_height + 10) {
+ if (state.height() > landed_height + 10) {
above = true;
} else {
- if (above && state.height < landed_height + 2) {
+ if (above && state.height() < landed_height + 2) {
above = false;
landed_time = state.time;
}
return landed_time;
}
- double boost_time(AltosRecordIterable iterable) {
- double boost_time = -1000;
-
- AltosState state = null;
+ double boost_time(AltosStateIterable states) {
+ double boost_time = AltosLib.MISSING;
+ AltosState state = null;
- for (AltosRecord record : iterable) {
- state = new AltosState(record, state);
-
- if (state.acceleration < 1)
+ for (AltosState s : states) {
+ state = s;
+ if (state.acceleration() < 1)
boost_time = state.time;
- if (state.state >= Altos.ao_flight_boost)
+ if (state.state >= AltosLib.ao_flight_boost && state.state <= AltosLib.ao_flight_landed)
break;
}
- if (boost_time == -1000)
+ if (state == null)
+ return 0;
+
+ if (boost_time == AltosLib.MISSING)
boost_time = state.time;
return boost_time;
}
- public AltosFlightStats(AltosRecordIterable iterable) throws InterruptedException, IOException {
- AltosState state = null;
- AltosState new_state = null;
- double boost_time = boost_time(iterable);
+ public AltosFlightStats(AltosStateIterable states) throws InterruptedException, IOException {
+ double boost_time = boost_time(states);
double end_time = 0;
- double landed_time = landed_time(iterable);
+ double landed_time = landed_time(states);
- year = month = day = -1;
- hour = minute = second = -1;
- serial = flight = -1;
- lat = lon = -1;
+ year = month = day = AltosLib.MISSING;
+ hour = minute = second = AltosLib.MISSING;
+ serial = flight = AltosLib.MISSING;
+ lat = lon = AltosLib.MISSING;
has_gps = false;
has_other_adc = false;
has_rssi = false;
- for (AltosRecord record : iterable) {
- if (serial < 0)
- serial = record.serial;
- if ((record.seen & AltosRecord.seen_flight) != 0 && flight < 0)
- flight = record.flight;
- if ((record.seen & AltosRecord.seen_temp_volt) != 0)
+ for (AltosState state : states) {
+ if (serial == AltosLib.MISSING && state.serial != AltosLib.MISSING)
+ serial = state.serial;
+ if (flight == AltosLib.MISSING && state.flight != AltosLib.MISSING)
+ flight = state.flight;
+ if (state.battery_voltage != AltosLib.MISSING)
has_other_adc = true;
- if (record.rssi != 0)
+ if (state.rssi != AltosLib.MISSING)
has_rssi = true;
- new_state = new AltosState(record, state);
- end_time = new_state.time;
- state = new_state;
- if (state.time >= boost_time && state.state < Altos.ao_flight_boost)
- state.state = Altos.ao_flight_boost;
- if (state.time >= landed_time && state.state < Altos.ao_flight_landed)
- state.state = Altos.ao_flight_landed;
- if (0 <= state.state && state.state < Altos.ao_flight_invalid) {
- if (state.state >= Altos.ao_flight_boost) {
- if (state.gps != null && state.gps.locked &&
- year < 0) {
- year = state.gps.year;
- month = state.gps.month;
- day = state.gps.day;
- hour = state.gps.hour;
- minute = state.gps.minute;
- second = state.gps.second;
- }
+ end_time = state.time;
+
+ int state_id = state.state;
+ if (state.time >= boost_time && state_id < Altos.ao_flight_boost)
+ state_id = Altos.ao_flight_boost;
+ if (state.time >= landed_time && state_id < Altos.ao_flight_landed)
+ state_id = Altos.ao_flight_landed;
+ if (state.gps != null && state.gps.locked) {
+ year = state.gps.year;
+ month = state.gps.month;
+ day = state.gps.day;
+ hour = state.gps.hour;
+ minute = state.gps.minute;
+ second = state.gps.second;
+ }
+ if (0 <= state_id && state_id < Altos.ao_flight_invalid) {
+ double acceleration = state.acceleration();
+ double speed = state.speed();
+ if (acceleration != AltosLib.MISSING && speed != AltosLib.MISSING) {
+ state_accel[state_id] += acceleration;
+ state_speed[state_id] += speed;
+ state_count[state_id]++;
}
- state_accel[state.state] += state.acceleration;
- state_accel_speed[state.state] += state.accel_speed;
- state_baro_speed[state.state] += state.baro_speed;
- state_count[state.state]++;
- if (state_start[state.state] == 0.0)
- state_start[state.state] = state.time;
- if (state_end[state.state] < state.time)
- state_end[state.state] = state.time;
- max_height = state.max_height;
- if (state.max_accel_speed != 0)
- max_speed = state.max_accel_speed;
- else
- max_speed = state.max_baro_speed;
- max_acceleration = state.max_acceleration;
+ if (state_start[state_id] == 0.0)
+ state_start[state_id] = state.time;
+ if (state_end[state_id] < state.time)
+ state_end[state_id] = state.time;
+ max_height = state.max_height();
+ max_speed = state.max_speed();
+ max_acceleration = state.max_acceleration();
}
if (state.gps != null && state.gps.locked && state.gps.nsat >= 4) {
- if (state.state <= Altos.ao_flight_pad) {
+ if (state_id <= Altos.ao_flight_pad) {
pad_lat = state.gps.lat;
pad_lon = state.gps.lon;
}
}
for (int s = Altos.ao_flight_startup; s <= Altos.ao_flight_landed; s++) {
if (state_count[s] > 0) {
- state_accel_speed[s] /= state_count[s];
- state_baro_speed[s] /= state_count[s];
+ state_speed[s] /= state_count[s];
state_accel[s] /= state_count[s];
}
if (state_start[s] == 0)
import java.awt.*;
import javax.swing.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
public class AltosFlightStatsTable extends JComponent {
GridBagLayout layout;
int y = 0;
new FlightStat(layout, y++, "Serial", String.format("%d", stats.serial));
new FlightStat(layout, y++, "Flight", String.format("%d", stats.flight));
- if (stats.year > 0 && stats.hour > 0)
+ if (stats.year != AltosLib.MISSING && stats.hour != AltosLib.MISSING)
new FlightStat(layout, y++, "Date/Time",
String.format("%04d-%02d-%02d", stats.year, stats.month, stats.day),
String.format("%02d:%02d:%02d UTC", stats.hour, stats.minute, stats.second));
else {
- if (stats.year > 0)
+ if (stats.year != AltosLib.MISSING)
new FlightStat(layout, y++, "Date",
String.format("%04d-%02d-%02d", stats.year, stats.month, stats.day));
- if (stats.hour > 0)
+ if (stats.hour != AltosLib.MISSING)
new FlightStat(layout, y++, "Time",
String.format("%02d:%02d:%02d UTC", stats.hour, stats.minute, stats.second));
}
String.format("%5.0f m/s", stats.max_speed),
String.format("%5.0f mph", AltosConvert.meters_to_mph(stats.max_speed)),
String.format("Mach %4.1f", AltosConvert.meters_to_mach(stats.max_speed)));
- if (stats.max_acceleration != AltosRecord.MISSING) {
+ if (stats.max_acceleration != AltosLib.MISSING) {
new FlightStat(layout, y++, "Maximum boost acceleration",
String.format("%5.0f m/s²", stats.max_acceleration),
String.format("%5.0f ft/s²", AltosConvert.meters_to_feet(stats.max_acceleration)),
String.format("%5.0f G", AltosConvert.meters_to_g(stats.state_accel[Altos.ao_flight_boost])));
}
new FlightStat(layout, y++, "Drogue descent rate",
- String.format("%5.0f m/s", stats.state_baro_speed[Altos.ao_flight_drogue]),
- String.format("%5.0f ft/s", AltosConvert.meters_to_feet(stats.state_baro_speed[Altos.ao_flight_drogue])));
+ String.format("%5.0f m/s", stats.state_speed[Altos.ao_flight_drogue]),
+ String.format("%5.0f ft/s", AltosConvert.meters_to_feet(stats.state_speed[Altos.ao_flight_drogue])));
new FlightStat(layout, y++, "Main descent rate",
- String.format("%5.0f m/s", stats.state_baro_speed[Altos.ao_flight_main]),
- String.format("%5.0f ft/s", AltosConvert.meters_to_feet(stats.state_baro_speed[Altos.ao_flight_main])));
+ String.format("%5.0f m/s", stats.state_speed[Altos.ao_flight_main]),
+ String.format("%5.0f ft/s", AltosConvert.meters_to_feet(stats.state_speed[Altos.ao_flight_main])));
new FlightStat(layout, y++, "Ascent time",
String.format("%6.1f s %s", stats.state_end[AltosLib.ao_flight_boost] - stats.state_start[AltosLib.ao_flight_boost],
AltosLib.state_name(Altos.ao_flight_boost)),
import java.awt.*;
import javax.swing.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
public class AltosFlightStatus extends JComponent implements AltosFlightDisplay {
GridBagLayout layout;
class Call extends FlightValue {
void show(AltosState state, AltosListenerState listener_state) {
- value.setText(state.data.callsign);
+ value.setText(state.callsign);
}
public Call (GridBagLayout layout, int x) {
super (layout, x, "Callsign");
class Serial extends FlightValue {
void show(AltosState state, AltosListenerState listener_state) {
- if (state.data.serial == AltosRecord.MISSING)
+ if (state.serial == AltosLib.MISSING)
value.setText("none");
else
- value.setText(String.format("%d", state.data.serial));
+ value.setText(String.format("%d", state.serial));
}
public Serial (GridBagLayout layout, int x) {
super (layout, x, "Serial");
class Flight extends FlightValue {
void show(AltosState state, AltosListenerState listener_state) {
- if (state.data.flight == AltosRecord.MISSING)
+ if (state.flight == AltosLib.MISSING)
value.setText("none");
else
- value.setText(String.format("%d", state.data.flight));
+ value.setText(String.format("%d", state.flight));
}
public Flight (GridBagLayout layout, int x) {
super (layout, x, "Flight");
class FlightState extends FlightValue {
void show(AltosState state, AltosListenerState listener_state) {
- value.setText(state.data.state());
+ value.setText(state.state_name());
}
public FlightState (GridBagLayout layout, int x) {
super (layout, x, "State");
class RSSI extends FlightValue {
void show(AltosState state, AltosListenerState listener_state) {
- value.setText(String.format("%d", state.data.rssi));
+ value.setText(String.format("%d", state.rssi()));
}
public RSSI (GridBagLayout layout, int x) {
super (layout, x, "RSSI");
class LastPacket extends FlightValue {
void show(AltosState state, AltosListenerState listener_state) {
- long secs = (System.currentTimeMillis() - state.report_time + 500) / 1000;
+ long secs = (System.currentTimeMillis() - state.received_time + 500) / 1000;
value.setText(String.format("%d", secs));
}
public LastPacket(GridBagLayout layout, int x) {
import java.text.*;
import java.util.prefs.*;
import java.util.concurrent.LinkedBlockingQueue;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
public class AltosFlightStatusTableModel extends AbstractTableModel {
private String[] columnNames = {
package altosui;
import java.awt.event.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
public class AltosFlightStatusUpdate implements ActionListener {
import java.awt.event.*;
import javax.swing.*;
import java.util.concurrent.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
import org.altusmetrum.altosuilib_1.*;
public class AltosFlightUI extends AltosUIFrame implements AltosFlightDisplay, AltosFontListener {
status_update.saved_state = state;
if (state == null)
- state = new AltosState(new AltosRecord());
+ state = new AltosState();
pad.show(state, listener_state);
flightStatus.show(state, listener_state);
flightInfo.show(state, listener_state);
- if (state.data.companion != null) {
+ if (state.companion != null) {
if (!has_companion) {
pane.add("Companion", companion);
has_companion= true;
package altosui;
import javax.swing.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
import org.altusmetrum.altosuilib_1.*;
public class AltosFreqList extends JComboBox {
public void set_frequency(double new_frequency) {
int i;
+
+ if (new_frequency < 0) {
+ setVisible(false);
+ return;
+ }
+
for (i = 0; i < getItemCount(); i++) {
AltosFrequency f = (AltosFrequency) getItemAt(i);
import java.awt.*;
import javax.swing.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
import org.altusmetrum.altosuilib_1.*;
import org.jfree.ui.*;
class AltosVoltage extends AltosUnits {
- public double value(double v) {
+ public double value(double v, boolean imperial_units) {
return v;
}
- public String show_units() {
+ public double inverse(double v, boolean imperial_units) {
+ return v;
+ }
+
+ public String show_units(boolean imperial_units) {
return "V";
}
- public String say_units() {
+ public String say_units(boolean imperial_units) {
return "volts";
}
- public int show_fraction(int width) {
+ public int show_fraction(int width, boolean imperial_units) {
return width / 2;
}
}
class AltosNsat extends AltosUnits {
- public double value(double v) {
+ public double value(double v, boolean imperial_units) {
+ return v;
+ }
+
+ public double inverse(double v, boolean imperial_units) {
return v;
}
- public String show_units() {
+ public String show_units(boolean imperial_units) {
return "Sats";
}
- public String say_units() {
+ public String say_units(boolean imperial_units) {
return "Satellites";
}
- public int show_fraction(int width) {
+ public int show_fraction(int width, boolean imperial_units) {
+ return 0;
+ }
+}
+
+class AltosPressure extends AltosUnits {
+
+ public double value(double p, boolean imperial_units) {
+ return p;
+ }
+
+ public double inverse(double p, boolean imperial_units) {
+ return p;
+ }
+
+ public String show_units(boolean imperial_units) {
+ return "Pa";
+ }
+
+ public String say_units(boolean imperial_units) {
+ return "pascals";
+ }
+
+ public int show_fraction(int width, boolean imperial_units) {
return 0;
}
}
class AltosDbm extends AltosUnits {
- public double value(double v) {
- return v;
+ public double value(double d, boolean imperial_units) {
+ return d;
+ }
+
+ public double inverse(double d, boolean imperial_units) {
+ return d;
}
- public String show_units() {
+ public String show_units(boolean imperial_units) {
return "dBm";
}
- public String say_units() {
- return "d b m";
+ public String say_units(boolean imperial_units) {
+ return "D B M";
}
- public int show_fraction(int width) {
+ public int show_fraction(int width, boolean imperial_units) {
return 0;
}
}
static final private Color height_color = new Color(194,31,31);
static final private Color gps_height_color = new Color(150,31,31);
+ static final private Color pressure_color = new Color (225,31,31);
static final private Color range_color = new Color(100, 31, 31);
static final private Color distance_color = new Color(100, 31, 194);
static final private Color speed_color = new Color(31,194,31);
static final private Color state_color = new Color(0,0,0);
static AltosVoltage voltage_units = new AltosVoltage();
+ static AltosPressure pressure_units = new AltosPressure();
static AltosNsat nsat_units = new AltosNsat();
static AltosDbm dbm_units = new AltosDbm();
AltosUIAxis height_axis, speed_axis, accel_axis, voltage_axis, temperature_axis, nsat_axis, dbm_axis;
- AltosUIAxis distance_axis;
+ AltosUIAxis distance_axis, pressure_axis;
public AltosGraph(AltosUIEnable enable, AltosFlightStats stats, AltosGraphDataSet dataSet) {
super(enable);
height_axis = newAxis("Height", AltosConvert.height, height_color);
+ pressure_axis = newAxis("Pressure", pressure_units, pressure_color, 0);
speed_axis = newAxis("Speed", AltosConvert.speed, speed_color);
accel_axis = newAxis("Acceleration", AltosConvert.accel, accel_color);
voltage_axis = newAxis("Voltage", voltage_units, voltage_color);
height_color,
true,
height_axis);
+ addSeries("Pressure",
+ AltosGraphDataPoint.data_pressure,
+ pressure_units,
+ pressure_color,
+ false,
+ pressure_axis);
addSeries("Speed",
AltosGraphDataPoint.data_speed,
AltosConvert.speed,
package altosui;
import org.altusmetrum.altosuilib_1.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
public class AltosGraphDataPoint implements AltosUIDataPoint {
public static final int data_temperature = 12;
public static final int data_range = 13;
public static final int data_distance = 14;
+ public static final int data_pressure = 15;
public double x() throws AltosUIDataMissing {
- if (state.data.time < -2)
+ double time = state.time_since_boost();
+ if (time < -2)
throw new AltosUIDataMissing(-1);
- return state.data.time;
+ return time;
}
public double y(int index) throws AltosUIDataMissing {
- double y = AltosRecord.MISSING;
+ double y = AltosLib.MISSING;
switch (index) {
case data_height:
- y = state.height;
+ y = state.height();
break;
case data_speed:
y = state.speed();
break;
case data_accel:
- y = state.acceleration;
+ y = state.acceleration();
break;
case data_temp:
y = state.temperature;
break;
case data_battery_voltage:
- y = state.battery;
+ y = state.battery_voltage;
break;
case data_drogue_voltage:
- y = state.drogue_sense;
+ y = state.apogee_voltage;
break;
case data_main_voltage:
- y = state.main_sense;
+ y = state.main_voltage;
break;
case data_rssi:
- y = state.data.rssi;
+ y = state.rssi;
break;
case data_gps_height:
y = state.gps_height;
if (state.from_pad != null)
y = state.from_pad.distance;
break;
+ case data_pressure:
+ y = state.pressure();
+ break;
}
- if (y == AltosRecord.MISSING)
+ if (y == AltosLib.MISSING)
throw new AltosUIDataMissing(index);
return y;
}
public int id(int index) {
if (index == data_state) {
- int s = state.data.state;
+ int s = state.state;
if (s < Altos.ao_flight_boost || s > Altos.ao_flight_landed)
return -1;
return s;
public String id_name(int index) {
if (index == data_state)
- return state.data.state();
+ return state.state_name();
return "";
}
import java.lang.*;
import java.io.*;
import java.util.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
import org.altusmetrum.altosuilib_1.*;
class AltosGraphIterator implements Iterator<AltosUIDataPoint> {
AltosGraphDataSet dataSet;
- Iterator<AltosRecord> iterator;
-
- AltosState state;
+ Iterator<AltosState> iterator;
public boolean hasNext() {
return iterator.hasNext();
}
public AltosUIDataPoint next() {
- state = new AltosState(iterator.next(), state);
+ AltosState state = iterator.next();
- if ((state.data.seen & AltosRecord.seen_flight) != 0) {
- if (dataSet.callsign == null && state.data.callsign != null)
- dataSet.callsign = state.data.callsign;
+ if (state.flight != AltosLib.MISSING) {
+ if (dataSet.callsign == null && state.callsign != null)
+ dataSet.callsign = state.callsign;
- if (dataSet.serial == 0 && state.data.serial != 0)
- dataSet.serial = state.data.serial;
+ if (dataSet.serial == 0 && state.serial != 0)
+ dataSet.serial = state.serial;
- if (dataSet.flight == 0 && state.data.flight != 0)
- dataSet.flight = state.data.flight;
+ if (dataSet.flight == 0 && state.flight != 0)
+ dataSet.flight = state.flight;
}
return new AltosGraphDataPoint(state);
}
- public AltosGraphIterator (Iterator<AltosRecord> iterator, AltosGraphDataSet dataSet) {
+ public AltosGraphIterator (Iterator<AltosState> iterator, AltosGraphDataSet dataSet) {
this.iterator = iterator;
- this.state = null;
this.dataSet = dataSet;
}
AltosGraphDataSet dataSet;
public Iterator<AltosUIDataPoint> iterator() {
- return new AltosGraphIterator(dataSet.records.iterator(), dataSet);
+ return new AltosGraphIterator(dataSet.states.iterator(), dataSet);
}
public AltosGraphIterable(AltosGraphDataSet dataSet) {
String callsign;
int serial;
int flight;
- AltosRecordIterable records;
+ AltosStateIterable states;
public String name() {
if (callsign != null)
return new AltosGraphIterable(this);
}
- public AltosGraphDataSet (AltosRecordIterable records) {
- this.records = records;
+ public AltosGraphDataSet (AltosStateIterable states) {
+ this.states = states;
this.callsign = null;
this.serial = 0;
this.flight = 0;
import java.awt.*;
import javax.swing.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
import org.altusmetrum.altosuilib_1.*;
import org.jfree.chart.ChartPanel;
AltosFlightStatsTable statsTable;
boolean has_gps;
- void fill_map(AltosRecordIterable records) {
+ void fill_map(AltosStateIterable states) {
boolean any_gps = false;
- for (AltosRecord record : records) {
- state = new AltosState(record, state);
+ for (AltosState state : states) {
if (state.gps != null && state.gps.locked && state.gps.nsat >= 4) {
if (map == null)
map = new AltosSiteMap();
}
}
- AltosGraphUI(AltosRecordIterable records, File file) throws InterruptedException, IOException {
+ AltosGraphUI(AltosStateIterable states, File file) throws InterruptedException, IOException {
super(file.getName());
state = null;
enable = new AltosUIEnable();
- stats = new AltosFlightStats(records);
- graphDataSet = new AltosGraphDataSet(records);
+ stats = new AltosFlightStats(states);
+ graphDataSet = new AltosGraphDataSet(states);
graph = new AltosGraph(enable, stats, graphDataSet);
pane.add("Flight Statistics", statsTable);
has_gps = false;
- fill_map(records);
+ fill_map(states);
if (has_gps)
pane.add("Map", map);
import javax.swing.event.*;
import java.io.*;
import java.util.concurrent.*;
-import org.altusmetrum.altoslib_1.*;
+import java.util.Arrays;
+import org.altusmetrum.altoslib_2.*;
import org.altusmetrum.altosuilib_1.*;
public class AltosIdleMonitorUI extends AltosUIFrame implements AltosFlightDisplay, AltosFontListener, AltosIdleMonitorListener, DocumentListener {
void stop_display() {
if (thread != null) {
- thread.abort();
+ try {
+ thread.abort();
+ } catch (InterruptedException ie) {
+ }
}
thread = null;
}
public void show(AltosState state, AltosListenerState listener_state) {
status_update.saved_state = state;
- try {
+// try {
pad.show(state, listener_state);
flightStatus.show(state, listener_state);
flightInfo.show(state, listener_state);
- } catch (Exception e) {
- System.out.print("Show exception" + e);
- }
+// } catch (Exception e) {
+// System.out.print("Show exception " + e);
+// }
}
public void update(final AltosState state, final AltosListenerState listener_state) {
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
- disconnect();
+ try {
+ disconnect();
+ } catch (Exception ex) {
+ System.out.println(Arrays.toString(ex.getStackTrace()));
+ }
setVisible(false);
dispose();
AltosUIPreferences.unregister_font_listener(AltosIdleMonitorUI.this);
import java.io.*;
import java.text.*;
import java.util.concurrent.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
import org.altusmetrum.altosuilib_1.*;
public class AltosIgniteUI
import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
public class AltosInfoTable extends JTable {
private AltosFlightInfoTableModel model;
public void show(AltosState state, AltosListenerState listener_state) {
info_reset();
if (state != null) {
- if (state.altitude != AltosRecord.MISSING)
- info_add_row(0, "Altitude", "%6.0f m", state.altitude);
- if (state.ground_altitude != AltosRecord.MISSING)
- info_add_row(0, "Pad altitude", "%6.0f m", state.ground_altitude);
- if (state.height != AltosRecord.MISSING)
- info_add_row(0, "Height", "%6.0f m", state.height);
- if (state.height != AltosRecord.MISSING)
- info_add_row(0, "Max height", "%6.0f m", state.max_height);
- if (state.acceleration != AltosRecord.MISSING)
- info_add_row(0, "Acceleration", "%8.1f m/s²", state.acceleration);
- if (state.acceleration != AltosRecord.MISSING)
- info_add_row(0, "Max acceleration", "%8.1f m/s²", state.max_acceleration);
- if (state.speed() != AltosRecord.MISSING)
+ if (state.device_type != AltosLib.MISSING)
+ info_add_row(0, "Device", "%s", AltosLib.product_name(state.device_type));
+ if (state.altitude() != AltosLib.MISSING)
+ info_add_row(0, "Altitude", "%6.0f m", state.altitude());
+ if (state.ground_altitude() != AltosLib.MISSING)
+ info_add_row(0, "Pad altitude", "%6.0f m", state.ground_altitude());
+ if (state.height() != AltosLib.MISSING)
+ info_add_row(0, "Height", "%6.0f m", state.height());
+ if (state.max_height() != AltosLib.MISSING)
+ info_add_row(0, "Max height", "%6.0f m", state.max_height());
+ if (state.acceleration() != AltosLib.MISSING)
+ info_add_row(0, "Acceleration", "%8.1f m/s²", state.acceleration());
+ if (state.max_acceleration() != AltosLib.MISSING)
+ info_add_row(0, "Max acceleration", "%8.1f m/s²", state.max_acceleration());
+ if (state.speed() != AltosLib.MISSING)
info_add_row(0, "Speed", "%8.1f m/s", state.speed());
- if (state.speed() != AltosRecord.MISSING)
- info_add_row(0, "Max Speed", "%8.1f m/s", state.max_accel_speed);
- if (state.temperature != AltosRecord.MISSING)
+ if (state.max_speed() != AltosLib.MISSING)
+ info_add_row(0, "Max Speed", "%8.1f m/s", state.max_speed());
+ if (state.temperature != AltosLib.MISSING)
info_add_row(0, "Temperature", "%9.2f °C", state.temperature);
- if (state.battery != AltosRecord.MISSING)
- info_add_row(0, "Battery", "%9.2f V", state.battery);
- if (state.drogue_sense != AltosRecord.MISSING)
- info_add_row(0, "Drogue", "%9.2f V", state.drogue_sense);
- if (state.main_sense != AltosRecord.MISSING)
- info_add_row(0, "Main", "%9.2f V", state.main_sense);
+ if (state.battery_voltage != AltosLib.MISSING)
+ info_add_row(0, "Battery", "%9.2f V", state.battery_voltage);
+ if (state.apogee_voltage != AltosLib.MISSING)
+ info_add_row(0, "Drogue", "%9.2f V", state.apogee_voltage);
+ if (state.main_voltage != AltosLib.MISSING)
+ info_add_row(0, "Main", "%9.2f V", state.main_voltage);
}
if (listener_state != null) {
info_add_row(0, "CRC Errors", "%6d", listener_state.crc_errors);
- if (listener_state.battery != AltosRecord.MISSING)
+ if (listener_state.battery != AltosLib.MISSING)
info_add_row(0, "Receiver Battery", "%9.2f", listener_state.battery);
}
else
info_add_row(1, "GPS state", "wait (%d)",
state.gps_waiting);
- if (state.data.gps.locked)
+ if (state.gps.locked)
info_add_row(1, "GPS", " locked");
- else if (state.data.gps.connected)
+ else if (state.gps.connected)
info_add_row(1, "GPS", " unlocked");
else
info_add_row(1, "GPS", " missing");
- info_add_row(1, "Satellites", "%6d", state.data.gps.nsat);
- info_add_deg(1, "Latitude", state.gps.lat, 'N', 'S');
- info_add_deg(1, "Longitude", state.gps.lon, 'E', 'W');
- info_add_row(1, "GPS altitude", "%6d", state.gps.alt);
- info_add_row(1, "GPS height", "%6.0f", state.gps_height);
+ info_add_row(1, "Satellites", "%6d", state.gps.nsat);
+ if (state.gps.lat != AltosLib.MISSING)
+ info_add_deg(1, "Latitude", state.gps.lat, 'N', 'S');
+ if (state.gps.lon != AltosLib.MISSING)
+ info_add_deg(1, "Longitude", state.gps.lon, 'E', 'W');
+ if (state.gps.alt != AltosLib.MISSING)
+ info_add_row(1, "GPS altitude", "%8.1f", state.gps.alt);
+ if (state.gps_height != AltosLib.MISSING)
+ info_add_row(1, "GPS height", "%8.1f", state.gps_height);
/* The SkyTraq GPS doesn't report these values */
/*
info_add_deg(1, "Pad longitude", state.pad_lon, 'E', 'W');
info_add_row(1, "Pad GPS alt", "%6.0f m", state.pad_alt);
}
- info_add_row(1, "GPS date", "%04d-%02d-%02d",
- state.gps.year,
- state.gps.month,
- state.gps.day);
- info_add_row(1, "GPS time", " %02d:%02d:%02d",
- state.gps.hour,
- state.gps.minute,
- state.gps.second);
+ if (state.gps.year != AltosLib.MISSING)
+ info_add_row(1, "GPS date", "%04d-%02d-%02d",
+ state.gps.year,
+ state.gps.month,
+ state.gps.day);
+ if (state.gps.hour != AltosLib.MISSING)
+ info_add_row(1, "GPS time", " %02d:%02d:%02d",
+ state.gps.hour,
+ state.gps.minute,
+ state.gps.second);
//int nsat_vis = 0;
int c;
package altosui;
import java.io.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
public class AltosKML implements AltosWriter {
File name;
PrintStream out;
- int state = -1;
- AltosRecord prev = null;
+ int flight_state = -1;
+ AltosState prev = null;
double gps_start_altitude;
static final String[] kml_state_colors = {
"</Document>\n" +
"</kml>\n";
- void start (AltosRecord record) {
+ void start (AltosState record) {
out.printf(kml_header_start, record.flight, record.serial);
out.printf("Date: %04d-%02d-%02d\n",
record.gps.year, record.gps.month, record.gps.day);
boolean started = false;
- void state_start(AltosRecord record) {
- String state_name = Altos.state_name(record.state);
- out.printf(kml_style_start, state_name, kml_state_colors[record.state]);
+ void state_start(AltosState state) {
+ String state_name = Altos.state_name(state.state);
+ out.printf(kml_style_start, state_name, kml_state_colors[state.state]);
out.printf("\tState: %s\n", state_name);
out.printf("%s", kml_style_end);
out.printf(kml_placemark_start, state_name, state_name);
}
- void state_end(AltosRecord record) {
+ void state_end(AltosState state) {
out.printf("%s", kml_placemark_end);
}
- void coord(AltosRecord record) {
- AltosGPS gps = record.gps;
+ void coord(AltosState state) {
+ AltosGPS gps = state.gps;
double altitude;
- if (record.height() != AltosRecord.MISSING)
- altitude = record.height() + gps_start_altitude;
+ if (state.height() != AltosLib.MISSING)
+ altitude = state.height() + gps_start_altitude;
else
altitude = gps.alt;
out.printf(kml_coord_fmt,
gps.lon, gps.lat,
altitude, (double) gps.alt,
- record.time, gps.nsat);
+ state.time, gps.nsat);
}
void end() {
}
}
- public void write(AltosRecord record) {
- AltosGPS gps = record.gps;
+ public void write(AltosState state) {
+ AltosGPS gps = state.gps;
if (gps == null)
return;
- if ((record.seen & (AltosRecord.seen_gps_lat)) == 0)
+ if (gps.lat == AltosLib.MISSING)
return;
- if ((record.seen & (AltosRecord.seen_gps_lon)) == 0)
+ if (gps.lon == AltosLib.MISSING)
return;
if (!started) {
- start(record);
+ start(state);
started = true;
gps_start_altitude = gps.alt;
}
- if (prev != null && prev.gps_sequence == record.gps_sequence)
+ if (prev != null && prev.gps_sequence == state.gps_sequence)
return;
- if (record.state != state) {
- state = record.state;
+ if (state.state != flight_state) {
+ flight_state = state.state;
if (prev != null) {
- coord(record);
+ coord(state);
state_end(prev);
}
- state_start(record);
+ state_start(state);
}
- coord(record);
- prev = record;
+ coord(state);
+ prev = state;
}
- public void write(AltosRecordIterable iterable) {
- for (AltosRecord record : iterable)
- write(record);
+ public void write(AltosStateIterable states) {
+ for (AltosState state : states) {
+ if ((state.set & AltosState.set_gps) != 0)
+ write(state);
+ }
}
public AltosKML(File in_name) throws FileNotFoundException {
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
public class AltosLanded extends JComponent implements AltosFlightDisplay, ActionListener {
GridBagLayout layout;
class Lat extends LandedValue {
void show (AltosState state, AltosListenerState listener_state) {
- if (state.gps != null && state.gps.connected)
+ show();
+ if (state.gps != null && state.gps.connected && state.gps.lat != AltosLib.MISSING)
show(pos(state.gps.lat,"N", "S"));
else
show("???");
class Lon extends LandedValue {
void show (AltosState state, AltosListenerState listener_state) {
show();
- if (state.gps != null && state.gps.connected)
+ if (state.gps != null && state.gps.connected && state.gps.lon != AltosLib.MISSING)
show(pos(state.gps.lon,"E", "W"));
else
show("???");
class Height extends LandedValue {
void show (AltosState state, AltosListenerState listener_state) {
- show(AltosConvert.height, state.max_height);
+ show(AltosConvert.height, state.max_height());
}
public Height (GridBagLayout layout, int y) {
super (layout, y, "Maximum Height");
class Accel extends LandedValue {
void show (AltosState state, AltosListenerState listener_state) {
- show(AltosConvert.accel, state.max_acceleration);
+ show(AltosConvert.accel, state.max_acceleration());
}
public Accel (GridBagLayout layout, int y) {
super (layout, y, "Maximum Acceleration");
if (file != null) {
String filename = file.getName();
try {
- AltosRecordIterable records = null;
+ AltosStateIterable states = null;
if (filename.endsWith("eeprom")) {
FileInputStream in = new FileInputStream(file);
- records = new AltosEepromIterable(in);
+ states = new AltosEepromFile(in);
} else if (filename.endsWith("telem")) {
FileInputStream in = new FileInputStream(file);
- records = new AltosTelemetryIterable(in);
- } else if (filename.endsWith("mega")) {
- FileInputStream in = new FileInputStream(file);
- records = new AltosEepromMegaIterable(in);
+ states = new AltosTelemetryFile(in);
} else {
throw new FileNotFoundException(filename);
}
try {
- new AltosGraphUI(records, file);
+ new AltosGraphUI(states, file);
} catch (InterruptedException ie) {
} catch (IOException ie) {
}
import java.awt.*;
import javax.swing.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
public class AltosPad extends JComponent implements AltosFlightDisplay {
GridBagLayout layout;
class Battery extends LaunchStatus {
void show (AltosState state, AltosListenerState listener_state) {
- if (state == null || state.battery == AltosRecord.MISSING)
+ if (state == null || state.battery_voltage == AltosLib.MISSING)
hide();
else {
- show("%4.2f V", state.battery);
- lights.set(state.battery > 3.7);
+ show("%4.2f V", state.battery_voltage);
+ lights.set(state.battery_voltage >= AltosLib.ao_battery_good);
}
}
public Battery (GridBagLayout layout, int y) {
class Apogee extends LaunchStatus {
void show (AltosState state, AltosListenerState listener_state) {
- if (state == null || state.drogue_sense == AltosRecord.MISSING)
+ if (state == null || state.apogee_voltage == AltosLib.MISSING)
hide();
else {
- show("%4.2f V", state.drogue_sense);
- lights.set(state.drogue_sense > 3.2);
+ show("%4.2f V", state.apogee_voltage);
+ lights.set(state.apogee_voltage >= AltosLib.ao_igniter_good);
}
}
public Apogee (GridBagLayout layout, int y) {
class Main extends LaunchStatus {
void show (AltosState state, AltosListenerState listener_state) {
- if (state == null || state.main_sense == AltosRecord.MISSING)
+ if (state == null || state.main_voltage == AltosLib.MISSING)
hide();
else {
- show("%4.2f V", state.main_sense);
- lights.set(state.main_sense > 3.2);
+ show("%4.2f V", state.main_voltage);
+ lights.set(state.main_voltage >= AltosLib.ao_igniter_good);
}
}
public Main (GridBagLayout layout, int y) {
class LoggingReady extends LaunchStatus {
void show (AltosState state, AltosListenerState listener_state) {
- if (state == null || state.data.flight == AltosRecord.MISSING) {
+ if (state == null || state.flight == AltosLib.MISSING) {
hide();
} else {
- if (state.data.flight != 0) {
- if (state.data.state <= Altos.ao_flight_pad)
+ if (state.flight != 0) {
+ if (state.state <= Altos.ao_flight_pad)
show("Ready to record");
- else if (state.data.state < Altos.ao_flight_landed)
+ else if (state.state < Altos.ao_flight_landed)
show("Recording data");
else
show("Recorded data");
} else
show("Storage full");
- lights.set(state.data.flight != 0);
+ lights.set(state.flight != 0);
}
}
public LoggingReady (GridBagLayout layout, int y) {
class ReceiverBattery extends LaunchStatus {
void show (AltosState state, AltosListenerState listener_state) {
- if (listener_state == null || listener_state.battery == AltosRecord.MISSING)
+ if (listener_state == null || listener_state.battery == AltosLib.MISSING)
hide();
else {
show("%4.2f V", listener_state.battery);
- lights.set(listener_state.battery > 3.7);
+ lights.set(listener_state.battery > AltosLib.ao_battery_good);
}
}
public ReceiverBattery (GridBagLayout layout, int y) {
class PadLat extends LaunchValue {
void show (AltosState state, AltosListenerState listener_state) {
- if (state == null || state.gps == null) {
- hide();
- } else {
- if (state.state < AltosLib.ao_flight_pad) {
- show(pos(state.gps.lat,"N", "S"));
- set_label("Latitude");
- } else {
- show(pos(state.pad_lat,"N", "S"));
- set_label("Pad Latitude");
+ double lat = AltosLib.MISSING;
+ String label = null;
+
+ if (state != null) {
+ if (state.state < AltosLib.ao_flight_pad && state.gps != null && state.gps.lat != AltosLib.MISSING) {
+ lat = state.gps.lat;
+ label = "Latitude";
+ } else {
+ lat = state.pad_lat;
+ label = "Pad Latitude";
}
}
+ if (lat != AltosLib.MISSING) {
+ show(pos(lat,"N", "S"));
+ set_label(label);
+ } else
+ hide();
}
public PadLat (GridBagLayout layout, int y) {
super (layout, y, "Pad Latitude");
class PadLon extends LaunchValue {
void show (AltosState state, AltosListenerState listener_state) {
- if (state == null || state.gps == null) {
- hide();
- } else {
- if (state.state < AltosLib.ao_flight_pad) {
- show(pos(state.gps.lon,"E", "W"));
- set_label("Longitude");
- } else {
- show(pos(state.pad_lon,"E", "W"));
- set_label("Pad Longitude");
+ double lon = AltosLib.MISSING;
+ String label = null;
+
+ if (state != null) {
+ if (state.state < AltosLib.ao_flight_pad && state.gps != null && state.gps.lon != AltosLib.MISSING) {
+ lon = state.gps.lon;
+ label = "Longitude";
+ } else {
+ lon = state.pad_lon;
+ label = "Pad Longitude";
}
}
+ if (lon != AltosLib.MISSING) {
+ show(pos(lon,"E", "W"));
+ set_label(label);
+ } else
+ hide();
}
public PadLon (GridBagLayout layout, int y) {
super (layout, y, "Pad Longitude");
class PadAlt extends LaunchValue {
void show (AltosState state, AltosListenerState listener_state) {
- if (state == null)
- hide();
- else {
- if (state.state < AltosLib.ao_flight_pad && state.gps != null) {
- show("%4.0f m", state.gps.alt);
- set_label("Altitude");
+ double alt = AltosLib.MISSING;
+ String label = null;
+
+ if (state != null) {
+ if (state.state < AltosLib.ao_flight_pad && state.gps != null && state.gps.alt != AltosLib.MISSING) {
+ alt = state.gps.alt;
+ label = "Altitude";
} else {
- if (state.pad_alt == AltosRecord.MISSING)
- hide();
- else {
- show("%4.0f m", state.pad_alt);
- set_label("Pad Altitude");
- }
+ alt = state.pad_alt;
+ label = "Pad Altitude";
}
}
+ if (alt != AltosLib.MISSING) {
+ show("%4.0f m", state.gps.alt);
+ set_label(label);
+ } else
+ hide();
}
public PadAlt (GridBagLayout layout, int y) {
super (layout, y, "Pad Altitude");
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
import org.altusmetrum.altosuilib_1.*;
public class AltosRomconfigUI
c.anchor = GridBagConstraints.LINE_START;
c.insets = ir;
c.ipady = 5;
- radio_calibration_value = new JTextField("1186611");
+ radio_calibration_value = new JTextField("0");
pane.add(radio_calibration_value, c);
/* Buttons */
import java.util.*;
import java.text.*;
import java.util.concurrent.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
import org.altusmetrum.altosuilib_1.*;
class AltosScanResult {
try {
for (;;) {
try {
- AltosRecord record = reader.read();
- if (record == null)
+ AltosState state = reader.read();
+ if (state == null)
continue;
- if ((record.seen & AltosRecord.seen_flight) != 0) {
- final AltosScanResult result = new AltosScanResult(record.callsign,
- record.serial,
- record.flight,
+ if (state.flight != AltosLib.MISSING) {
+ final AltosScanResult result = new AltosScanResult(state.callsign,
+ state.serial,
+ state.flight,
frequencies[frequency_index],
telemetry);
Runnable r = new Runnable() {
import java.util.*;
import java.awt.*;
import javax.swing.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
import org.altusmetrum.altosuilib_1.*;
import libaltosJNI.*;
public void flush_output() {
super.flush_output();
if (altos != null) {
- if (libaltos.altos_flush(altos) != 0) {
- libaltos.altos_close(altos);
- altos = null;
- abort_reply();
- }
+ if (libaltos.altos_flush(altos) != 0)
+ close_serial();
}
}
SwingUtilities.invokeLater(r);
}
+ private void close_serial() {
+ synchronized (devices_opened) {
+ devices_opened.remove(device.getPath());
+ }
+ if (altos != null) {
+ libaltos.altos_free(altos);
+ altos = null;
+ }
+ abort_reply();
+ }
+
public void close() {
if (remote) {
try {
if (in_reply != 0)
System.out.printf("Uh-oh. Closing active serial device\n");
- if (altos != null) {
- libaltos.altos_close(altos);
- }
+ close_serial();
+
if (input_thread != null) {
try {
input_thread.interrupt();
input_thread.join();
- } catch (InterruptedException e) {
+ } catch (InterruptedException ie) {
}
input_thread = null;
}
- if (altos != null) {
- libaltos.altos_free(altos);
- altos = null;
- }
- synchronized (devices_opened) {
- devices_opened.remove(device.getPath());
- }
if (debug)
System.out.printf("Closing %s\n", device.getPath());
}
private void putc(char c) {
if (altos != null)
- if (libaltos.altos_putchar(altos, c) != 0) {
- libaltos.altos_close(altos);
- altos = null;
- abort_reply();
- }
+ if (libaltos.altos_putchar(altos, c) != 0)
+ close_serial();
+ }
+
+ public void putchar(byte c) {
+ if (altos != null) {
+ if (debug)
+ System.out.printf(" %02x", (int) c & 0xff);
+ if (libaltos.altos_putchar(altos, (char) c) != 0)
+ close_serial();
+ }
}
public void print(String data) {
import java.lang.Math;
import java.awt.geom.Point2D;
import java.util.concurrent.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
import org.altusmetrum.altosuilib_1.*;
public class AltosSiteMap extends JScrollPane implements AltosFlightDisplay {
int last_state = -1;
public void show(double lat, double lon) {
- initMaps(lat, lon);
- scrollRocketToVisible(pt(lat, lon));
+ System.out.printf ("show %g %g\n", lat, lon);
+ return;
+// initMaps(lat, lon);
+// scrollRocketToVisible(pt(lat, lon));
}
public void show(final AltosState state, final AltosListenerState listener_state) {
// if insufficient gps data, nothing to update
- if (!state.gps.locked && state.gps.nsat < 4)
+ AltosGPS gps = state.gps;
+
+ if (gps == null)
+ return;
+
+ if (!gps.locked && gps.nsat < 4)
return;
if (!initialised) {
- if (state.pad_lat != 0 || state.pad_lon != 0) {
+ if (state.pad_lat != AltosLib.MISSING && state.pad_lon != AltosLib.MISSING) {
initMaps(state.pad_lat, state.pad_lon);
initialised = true;
- } else if (state.gps.lat != 0 || state.gps.lon != 0) {
- initMaps(state.gps.lat, state.gps.lon);
+ } else if (gps.lat != AltosLib.MISSING && gps.lon != AltosLib.MISSING) {
+ initMaps(gps.lat, gps.lon);
initialised = true;
} else {
return;
}
}
- final Point2D.Double pt = pt(state.gps.lat, state.gps.lon);
+ final Point2D.Double pt = pt(gps.lat, gps.lon);
if (last_pt == pt && last_state == state.state)
return;
import javax.swing.*;
import java.awt.geom.Point2D;
import java.awt.geom.Line2D;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
public class AltosSiteMapTile extends JLayeredPane {
JLabel mapLabel;
import javax.swing.*;
import java.io.*;
import java.util.concurrent.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
import org.altusmetrum.altosuilib_1.*;
public class AltosUI extends AltosUIFrame {
AltosDataChooser chooser = new AltosDataChooser(
AltosUI.this);
- AltosRecordIterable iterable = chooser.runDialog();
- if (iterable != null) {
- AltosFlightReader reader = new AltosReplayReader(iterable.iterator(),
+ Iterable<AltosState> states = chooser.runDialog();
+ if (states != null) {
+ AltosFlightReader reader = new AltosReplayReader(states.iterator(),
chooser.file());
new AltosFlightUI(voice, reader);
}
private void ExportData() {
AltosDataChooser chooser;
chooser = new AltosDataChooser(this);
- AltosRecordIterable record_reader = chooser.runDialog();
- if (record_reader == null)
+ AltosStateIterable states = chooser.runDialog();
+ if (states == null)
return;
- new AltosCSVUI(AltosUI.this, record_reader, chooser.file());
+ new AltosCSVUI(AltosUI.this, states, chooser.file());
}
/* Load a flight log CSV file and display a pretty graph.
private void GraphData() {
AltosDataChooser chooser;
chooser = new AltosDataChooser(this);
- AltosRecordIterable record_reader = chooser.runDialog();
- if (record_reader == null)
+ AltosStateIterable states = chooser.runDialog();
+ if (states == null)
return;
try {
- new AltosGraphUI(record_reader, chooser.file());
+ new AltosGraphUI(states, chooser.file());
} catch (InterruptedException ie) {
} catch (IOException ie) {
}
}
}
- static AltosRecordIterable open_logfile(File file) {
+ static AltosStateIterable open_logfile(File file) {
try {
FileInputStream in;
in = new FileInputStream(file);
- if (file.getName().endsWith("eeprom"))
- return new AltosEepromIterable(in);
- else if (file.getName().endsWith("mega"))
- return new AltosEepromMegaIterable(in);
+ if (file.getName().endsWith("telem"))
+ return new AltosTelemetryFile(in);
else
- return new AltosTelemetryIterable(in);
+ return new AltosEepromFile(in);
} catch (FileNotFoundException fe) {
System.out.printf("%s\n", fe.getMessage());
return null;
static final int process_graph = 3;
static final int process_replay = 4;
static final int process_summary = 5;
+ static final int process_cat = 6;
static boolean process_csv(File input) {
- AltosRecordIterable iterable = open_logfile(input);
- if (iterable == null)
+ AltosStateIterable states = open_logfile(input);
+ if (states == null)
return false;
File output = Altos.replace_extension(input,".csv");
AltosWriter writer = open_csv(output);
if (writer == null)
return false;
- writer.write(iterable);
+ writer.write(states);
writer.close();
}
return true;
}
static boolean process_kml(File input) {
- AltosRecordIterable iterable = open_logfile(input);
- if (iterable == null)
+ AltosStateIterable states = open_logfile(input);
+ if (states == null)
return false;
File output = Altos.replace_extension(input,".kml");
AltosWriter writer = open_kml(output);
if (writer == null)
return false;
- writer.write(iterable);
+ writer.write(states);
writer.close();
return true;
}
}
- static AltosRecordIterable record_iterable(File file) {
+ static AltosStateIterable record_iterable(File file) {
FileInputStream in;
try {
in = new FileInputStream(file);
System.out.printf("Failed to open file '%s'\n", file);
return null;
}
- AltosRecordIterable recs;
- //AltosReplayReader reader;
- if (file.getName().endsWith("eeprom")) {
- recs = new AltosEepromIterable(in);
- } else if (file.getName().endsWith("mega")) {
- recs = new AltosEepromMegaIterable(in);
- } else {
- recs = new AltosTelemetryIterable(in);
- }
- return recs;
+ if (file.getName().endsWith("telem"))
+ return new AltosTelemetryFile(in);
+ else
+ return new AltosEepromFile(in);
}
static AltosReplayReader replay_file(File file) {
- AltosRecordIterable recs = record_iterable(file);
- if (recs == null)
+ AltosStateIterable states = record_iterable(file);
+ if (states == null)
return null;
- return new AltosReplayReader(recs.iterator(), file);
+ return new AltosReplayReader(states.iterator(), file);
}
static boolean process_replay(File file) {
}
static boolean process_graph(File file) {
- AltosRecordIterable recs = record_iterable(file);
- if (recs == null)
+ AltosStateIterable states = record_iterable(file);
+ if (states == null)
return false;
try {
- new AltosGraphUI(recs, file);
+ new AltosGraphUI(states, file);
return true;
} catch (InterruptedException ie) {
} catch (IOException ie) {
}
static boolean process_summary(File file) {
- AltosRecordIterable iterable = record_iterable(file);
- if (iterable == null)
+ AltosStateIterable states = record_iterable(file);
+ if (states == null)
return false;
try {
- AltosFlightStats stats = new AltosFlightStats(iterable);
+ AltosFlightStats stats = new AltosFlightStats(states);
if (stats.serial > 0)
System.out.printf("Serial: %5d\n", stats.serial);
if (stats.flight > 0)
stats.max_speed,
AltosConvert.meters_to_feet(stats.max_speed),
AltosConvert.meters_to_mach(stats.max_speed));
- if (stats.max_acceleration != AltosRecord.MISSING) {
+ if (stats.max_acceleration != AltosLib.MISSING) {
System.out.printf("Max accel: %6.0f m/s² %6.0f ft/s² %6.2f g\n",
stats.max_acceleration,
AltosConvert.meters_to_feet(stats.max_acceleration),
AltosConvert.meters_to_g(stats.max_acceleration));
}
System.out.printf("Drogue rate: %6.0f m/s %6.0f ft/s\n",
- stats.state_baro_speed[Altos.ao_flight_drogue],
- AltosConvert.meters_to_feet(stats.state_baro_speed[Altos.ao_flight_drogue]));
+ stats.state_speed[Altos.ao_flight_drogue],
+ AltosConvert.meters_to_feet(stats.state_speed[Altos.ao_flight_drogue]));
System.out.printf("Main rate: %6.0f m/s %6.0f ft/s\n",
- stats.state_baro_speed[Altos.ao_flight_main],
- AltosConvert.meters_to_feet(stats.state_baro_speed[Altos.ao_flight_main]));
+ stats.state_speed[Altos.ao_flight_main],
+ AltosConvert.meters_to_feet(stats.state_speed[Altos.ao_flight_main]));
System.out.printf("Flight time: %6.0f s\n",
stats.state_end[Altos.ao_flight_main] -
stats.state_start[Altos.ao_flight_boost]);
return false;
}
+ static boolean process_cat(File file) {
+ try {
+ AltosStateIterable eef = record_iterable(file);
+
+ System.out.printf ("process cat\n");
+ for (AltosState state : eef) {
+ System.out.printf ("tick %d state %d height %g\n",
+ state.tick, state.state, state.height());
+ if ((state.set & AltosState.set_gps) != 0)
+ System.out.printf ("time %g lat %g lon %g alt %g\n",
+ state.time_since_boost(),
+ state.gps.lat,
+ state.gps.lon,
+ state.gps.alt);
+ }
+
+ } catch (Exception e) {
+ System.out.printf("Failed to open file '%s'\n", file);
+ return false;
+ }
+ return true;
+ }
+
public static void help(int code) {
System.out.printf("Usage: altosui [OPTION]... [FILE]...\n");
System.out.printf(" Options:\n");
process = process_graph;
else if (args[i].equals("--summary"))
process = process_summary;
+ else if (args[i].equals("--cat"))
+ process = process_cat;
else if (args[i].startsWith("--"))
help(1);
else {
if (!process_summary(file))
++errors;
break;
+ case process_cat:
+ if (!process_cat(file))
+ ++errors;
}
}
}
import java.io.File;
import java.util.prefs.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
import javax.swing.filechooser.FileSystemView;
public class AltosUIPreferencesBackend implements AltosPreferencesBackend {
package altosui;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
public interface AltosWriter {
- public void write(AltosRecord record);
+ public void write(AltosState state);
- public void write(AltosRecordIterable iterable);
+ public void write(AltosStateIterable states);
public void close();
}
JAVAROOT=classes
-AM_JAVACFLAGS=-encoding UTF-8 -Xlint:deprecation
+AM_JAVACFLAGS=-target 1.6 -encoding UTF-8 -Xlint:deprecation -source 6
man_MANS=altosui.1
AltosDeviceUIDialog.java \
AltosDisplayThread.java \
AltosEepromDelete.java \
- AltosEepromDownload.java \
- AltosEepromList.java \
AltosEepromManage.java \
- AltosEepromMonitor.java \
+ AltosEepromMonitorUI.java \
AltosEepromSelect.java \
AltosFlashUI.java \
AltosFlightDisplay.java \
WINDOWS_ICON=$(ICONDIR)/altus-metrum.ico
# Firmware
-FIRMWARE_TD_0_2=$(top_srcdir)/src/teledongle-v0.2-$(VERSION).ihx
+FIRMWARE_TD_0_2=$(top_srcdir)/src/teledongle-v0.2/teledongle-v0.2-$(VERSION).ihx
FIRMWARE_TD=$(FIRMWARE_TD_0_2)
-FIRMWARE_TM_1_0=$(top_srcdir)/src/telemetrum-v1.0-$(VERSION).ihx
-FIRMWARE_TM_1_1=$(top_srcdir)/src/telemetrum-v1.1-$(VERSION).ihx
-FIRMWARE_TM_1_2=$(top_srcdir)/src/telemetrum-v1.2-$(VERSION).ihx
+FIRMWARE_TM_1_0=$(top_srcdir)/src/telemetrum-v1.0/telemetrum-v1.0-$(VERSION).ihx
+FIRMWARE_TM_1_1=$(top_srcdir)/src/telemetrum-v1.1/telemetrum-v1.1-$(VERSION).ihx
+FIRMWARE_TM_1_2=$(top_srcdir)/src/telemetrum-v1.2/telemetrum-v1.2-$(VERSION).ihx
FIRMWARE_TM=$(FIRMWARE_TM_1_0) $(FIRMWARE_TM_1_1) $(FIRMWARE_TM_1_2)
-FIRMWARE_TELEMINI_1_0=$(top_srcdir)/src/telemini-v1.0-$(VERSION).ihx
+FIRMWARE_TELEMINI_1_0=$(top_srcdir)/src/telemini-v1.0/telemini-v1.0-$(VERSION).ihx
FIRMWARE_TELEMINI=$(FIRMWARE_TELEMINI_1_0)
-FIRMWARE_TBT_1_0=$(top_srcdir)/src/telebt-v1.0-$(VERSION).ihx
+FIRMWARE_TBT_1_0=$(top_srcdir)/src/telebt-v1.0/telebt-v1.0-$(VERSION).ihx
FIRMWARE_TBT=$(FIRMWARE_TBT_1_0)
-FIRMWARE=$(FIRMWARE_TM) $(FIRMWARE_TELEMINI) $(FIRMWARE_TD) $(FIRMWARE_TBT)
+FIRMWARE_TMEGA_1_0=$(top_srcdir)/src/telemega-v1.0/telemega-v1.0-$(VERSION).ihx
+FIRMWARE_TMEGA=$(FIRMWARE_TMEGA_1_0)
+
+FIRMWARE_EMINI_1_0=$(top_srcdir)/src/easymini-v1.0/easymini-v1.0-$(VERSION).ihx
+
+FIRMWARE=$(FIRMWARE_TM) $(FIRMWARE_TELEMINI) $(FIRMWARE_TD) $(FIRMWARE_TBT) $(FIRMWARE_TMEGA) $(FIRMWARE_EMINI)
ALTUSMETRUM_DOC=$(top_srcdir)/doc/altusmetrum.pdf
ALTOS_DOC=$(top_srcdir)/doc/altos.pdf
TELEMETRY_DOC=$(top_srcdir)/doc/telemetry.pdf
-TEMPLATE_DOC=$(top_srcdir)/doc/telemetrum-outline.pdf $(top_srcdir)/doc/telemega-outline.pdf
+TEMPLATE_DOC=\
+ $(top_srcdir)/doc/telemetrum-outline.pdf \
+ $(top_srcdir)/doc/easymini-outline.pdf \
+ $(top_srcdir)/doc/telemega-outline.pdf \
+ $(top_srcdir)/doc/easymini-outline.pdf
DOC=$(ALTUSMETRUM_DOC) $(ALTOS_DOC) $(TELEMETRY_DOC) $(TEMPLATE_DOC)
LINUX_EXTRA=altosui-fat
MACOSX_INFO_PLIST=Info.plist
-MACOSX_FILES=$(FAT_FILES) libaltos.dylib $(MACOSX_INFO_PLIST) ReadMe-Mac.rtf
+MACOSX_FILES=$(FAT_FILES) libaltos.dylib $(MACOSX_INFO_PLIST) $(DOC) ReadMe-Mac.rtf
MACOSX_EXTRA=$(FIRMWARE)
WINDOWS_FILES=$(FAT_FILES) altos.dll altos64.dll $(top_srcdir)/telemetrum.inf $(WINDOWS_ICON)
mkdir macosx
cp -a AltosUI.app macosx/
cp -a ReadMe-Mac.rtf macosx/ReadMe.rtf
+ mkdir -p macosx/Doc
+ cp -a $(DOC) macosx/Doc
cp -p Info.plist macosx/AltosUI.app/Contents
mkdir -p macosx/AltOS-$(VERSION) macosx/AltosUI.app/Contents/Resources/Java
cp -p $(FATJAR) macosx/AltosUI.app/Contents/Resources/Java/altosui.jar
File "../src/telemini-v1.0/telemini-v1.0-${VERSION}.ihx"
File "../src/teledongle-v0.2/teledongle-v0.2-${VERSION}.ihx"
File "../src/telebt-v1.0/telebt-v1.0-${VERSION}.ihx"
+ File "../src/telemega-v1.0/telemega-v1.0-${VERSION}.ihx"
+ File "../src/easymini-v1.0/easymini-v1.0-${VERSION}.ihx"
SectionEnd
File "../doc/telemetry.pdf"
File "../doc/telemetrum-outline.pdf"
File "../doc/telemega-outline.pdf"
+ File "../doc/easymini-outline.pdf"
SectionEnd
Section "Uninstaller"
import java.awt.*;
import javax.swing.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
import org.jfree.ui.*;
import org.jfree.chart.*;
import java.io.*;
import java.util.concurrent.*;
import java.util.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
import org.jfree.ui.*;
import org.jfree.chart.*;
import java.awt.*;
import javax.swing.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
import org.jfree.ui.*;
import org.jfree.chart.*;
import java.awt.*;
import javax.swing.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
import org.jfree.ui.*;
import org.jfree.chart.*;
import java.awt.*;
import libaltosJNI.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
public class AltosUILib extends AltosLib {
import java.awt.*;
import javax.swing.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
import org.jfree.ui.*;
import org.jfree.chart.*;
import java.util.*;
import java.awt.Component;
import javax.swing.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
public class AltosUIPreferences extends AltosPreferences {
import java.io.File;
import java.util.prefs.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
import javax.swing.filechooser.FileSystemView;
public class AltosUIPreferencesBackend implements AltosPreferencesBackend {
import java.awt.*;
import javax.swing.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
import org.jfree.ui.*;
import org.jfree.chart.*;
import org.jfree.data.xy.*;
import org.jfree.data.*;
+class AltosUITime extends AltosUnits {
+ public double value(double v, boolean imperial_units) { return v; }
+
+ public double inverse(double v, boolean imperial_unis) { return v; }
+
+ public String show_units(boolean imperial_units) { return "s"; }
+
+ public String say_units(boolean imperial_units) { return "seconds"; }
+
+ public int show_fraction(int width, boolean imperial_units) {
+ if (width < 5)
+ return 0;
+ return width - 5;
+ }
+
+ public int say_fraction(boolean imperial_units) { return 0; }
+}
+
public class AltosUISeries extends XYSeries implements AltosUIGrapher {
AltosUIAxis axis;
String label;
axis.set_units();
StandardXYToolTipGenerator ttg;
- String example = units.graph_format(4);
+ String time_example = (new AltosUITime()).graph_format(7);
+ String example = units.graph_format(7);
ttg = new StandardXYToolTipGenerator(String.format("{1}s: {2}%s ({0})",
units.show_units()),
- new java.text.DecimalFormat(example),
+ new java.text.DecimalFormat(time_example),
new java.text.DecimalFormat(example));
renderer.setBaseToolTipGenerator(ttg);
}
if (want_product == AltosUILib.product_any)
return true;
+ int have_product = getProduct();
+
if (want_product == AltosUILib.product_basestation)
- return matchProduct(AltosUILib.product_teledongle) ||
- matchProduct(AltosUILib.product_teleterra) ||
- matchProduct(AltosUILib.product_telebt) ||
- matchProduct(AltosUILib.product_megadongle);
+ return have_product == AltosUILib.product_teledongle ||
+ have_product == AltosUILib.product_teleterra ||
+ have_product == AltosUILib.product_telebt ||
+ have_product == AltosUILib.product_megadongle;
if (want_product == AltosUILib.product_altimeter)
- return matchProduct(AltosUILib.product_telemetrum) ||
- matchProduct(AltosUILib.product_telemega) ||
- matchProduct(AltosUILib.product_telegps);
-
- int have_product = getProduct();
+ return have_product == AltosUILib.product_telemetrum ||
+ have_product == AltosUILib.product_telemega ||
+ have_product == AltosUILib.product_telegps ||
+ have_product == AltosUILib.product_easymini ||
+ have_product == AltosUILib.product_telemini;
if (have_product == AltosUILib.product_altusmetrum) /* old devices match any request */
return true;
-AM_JAVACFLAGS=-encoding UTF-8 -Xlint:deprecation
+AM_JAVACFLAGS=-target 1.6 -encoding UTF-8 -Xlint:deprecation -source 6
JAVAROOT=bin
--- /dev/null
+#!/usr/bin/nickle
+
+import File;
+
+string timed_read(file f, int timeout) {
+ thread reader = fork func() {
+ try {
+ return fgets(f);
+ } catch Thread::signal(int i) {
+ return "";
+ }
+ }();
+
+ thread killer = fork func() {
+ try {
+ sleep (timeout);
+ Thread::send_signal(reader, 1);
+ } catch Thread::signal(int i) {
+ return;
+ }
+ }();
+
+ poly v = Thread::join(reader);
+ Thread::send_signal(killer, 1);
+ Thread::join(killer);
+ if (is_string(v))
+ return v;
+ return "";
+}
+
+void flush_input(file f) {
+ for (;;) {
+ string s = timed_read(f, 200);
+ if (s == "")
+ break;
+ }
+}
+
+string[*] settings(file f) {
+ string[...] x = {};
+
+ flush_input(f);
+ fprintf (f, "c s\nv\n");
+ flush(f);
+ for (;;) {
+ string l = File::fgets(f);
+ x[dim(x)] = l;
+ if (String::index(l, "software-version") == 0)
+ break;
+ }
+ return x;
+}
+
+string[*] find_setting(string[*] s, string match) {
+ for (int i = 0; i < dim(s); i++)
+ if (String::index(s[i], match) == 0)
+ return String::split(s[i], " ");
+ return (string[*]) {};
+}
+
+bool
+do_cal(file f) {
+ flush_input(f);
+ fprintf(f, "E 1\nc a 0\n");
+ flush(f);
+ string s = "";
+ bool worked = true;
+ bool running = false;
+
+ thread put = fork func() {
+ try {
+ for (;;) {
+ putc(getchar(), f);
+ flush(f);
+ }
+ } catch Thread::signal(int i) {
+ return;
+ }
+ }();
+
+ for (;;) {
+ int c = getc(f);
+ if (c == '\n')
+ s = "";
+ else
+ s = s + String::new(c);
+ putchar(c); flush(stdout);
+ if (String::index(s, "press a key...") >= 0)
+ running = true;
+ if (String::index(s, "Invalid") >= 0)
+ worked = false;
+ if (running && String::index(s, ">") >= 0)
+ break;
+ }
+ fprintf (f, "E 0\n");
+ if (worked)
+ fprintf (f, "c w\n");
+ sleep(200);
+ Thread::send_signal(put, 1);
+ Thread::join(put);
+
+ return worked;
+}
+
+void main () {
+ string name = argv[1];
+ file f = open(name, "r+");
+
+ if (do_cal(f)) {
+ string[*] s = settings(f);
+ string[*] ac = find_setting(s, "Accel cal");
+ printf ("Calibration value +1g %s -1g %s saved\n", ac[3], ac[5]);
+ exit (0);
+ } else {
+ printf ("Calibration failed\n");
+ exit (1);
+ }
+}
+
+main();
--- /dev/null
+#!/bin/sh
+
+case $# in
+1)
+ dev="$1"
+ ;;
+*)
+ echo "Usage: $0 <device>"
+ exit 1;
+ ;;
+esac
+
+while true; do
+ echo 'C 1' > $dev
+
+ echo -n "Generating RF carrier. Please enter measured frequency [enter for done]: "
+
+ read FREQ
+
+ echo 'C 0' > $dev
+
+ case "$FREQ" in
+ "")
+ exit 0
+ ;;
+ *)
+ calline=`./get-radio-cal $dev`
+ CURRENT_CAL=`echo $calline | awk '{print $2}'`
+ CURRENT_FREQ=`echo $calline | awk '{print $4}'`
+
+ echo "Current radio calibration "$CURRENT_CAL
+ echo "Current radio frequency "$CURRENT_FREQ
+
+ CAL_VALUE=`nickle -e "floor($CURRENT_FREQ / $FREQ * $CURRENT_CAL + 0.5)"`
+
+ echo "Programming flash with cal value " $CAL_VALUE
+
+ cat << EOF > $dev
+c f $CAL_VALUE
+c w
+EOF
+
+ echo "Serial number "$SERIAL" programmed with RF cal value "$CAL_VALUE
+ ;;
+ esac
+done
--- /dev/null
+#!/usr/bin/nickle
+
+import File;
+
+string timed_read(file f, int timeout) {
+ thread reader = fork func() { try { return fgets(f); } catch Thread::signal(int i) { return ""; } }();
+ thread killer = fork func() { sleep (timeout); Thread::send_signal(reader, 1); }();
+ poly v = Thread::join(reader);
+ if (is_string(v))
+ return v;
+ return "";
+}
+
+void flush_input(file f) {
+ for (;;) {
+ string s = timed_read(f, 100);
+ if (s == "")
+ break;
+ }
+}
+
+string[*] settings(file f) {
+ string[...] x = {};
+
+ flush_input(f);
+ fprintf (f, "c s\nv\n");
+ flush(f);
+ for (;;) {
+ string l = File::fgets(f);
+ x[dim(x)] = l;
+ if (String::index(l, "software-version") == 0)
+ break;
+ }
+ return x;
+}
+
+string[*] find_setting(string[*] s, string match) {
+ for (int i = 0; i < dim(s); i++)
+ if (String::index(s[i], match) == 0)
+ return String::split(s[i], " ");
+ return (string[*]) {};
+}
+
+int[*]
+get_radio (file f) {
+ string[*] s = settings(f);
+
+ string[*] cal = find_setting(s, "Radio cal:");
+ string[*] freq = find_setting(s, "Frequency:");
+ if (dim(cal) == 0 || dim(freq) == 0)
+ return (int[2]) { 0, 0 };
+
+ int cal_val = string_to_integer(cal[2]);
+ int freq_val = string_to_integer(freq[1]);
+ return (int[2]) { cal_val, freq_val };
+}
+
+void main () {
+ string name = argv[1];
+ file f = open(name, "r+");
+
+ int[*] vals = get_radio(f);
+ printf ("cal %d freq %f\n", vals[0], vals[1] / 1000);
+}
+
+main();
#!/bin/sh
+# serial number of the TeleDongle being used as the flash programmer
+DONGLE=612
+
if [ -x ../ao-tools/ao-load/ao-load ]; then
AOLOAD=../ao-tools/ao-load/ao-load
elif [ -x /usr/bin/ao-load ]; then
exit 1
fi
-echo "TeleBT v0.1 Turn-On and Calibration Program"
-echo "Copyright 2011 by Bdale Garbee. Released under GPL v2"
+echo "TeleBT v1.1 Turn-On and Calibration Program"
+echo "Copyright 2013 by Bdale Garbee. Released under GPL v2"
echo
echo "Expectations:"
-echo "\tTeleBT v0.1 powered from USB"
-echo "\t\twith TeleDonle (on /dev/ttyACM0) cabled to debug header"
+echo "\tTeleBT v1.1 powered from USB"
+echo "\t\twith TeleDonlge (on /dev/ttyACM0) cabled to debug header"
echo "\t\twith coax from SMA to frequency counter"
echo
echo -n "TeleBT serial number: "
echo $RAWLOAD
-$RAWLOAD -D 100 -r ao_led_blink.ihx
+$RAWLOAD -D $DONGLE -r ao_led_blink.ihx
echo "LEDs should be blinking"
sleep 5
-$RAWLOAD -D 100 -r ao_radio_xmit.ihx
+$RAWLOAD -D $DONGLE -r ao_radio_xmit.ihx
echo -n "Generating RF carrier. Please enter measured frequency: "
read FREQ
CAL_VALUE=`nickle -e "floor(434.55 / $FREQ * 1186611 + 0.5)"`
echo "Programming flash with cal value " $CAL_VALUE
-$AOLOAD -D 100 --cal $CAL_VALUE /usr/share/altos/telebt-v0.1*.ihx $SERIAL
+$AOLOAD -D $DONGLE --cal $CAL_VALUE /usr/share/altos/stable/telebt-v1.0*.ihx $SERIAL
echo "Serial number "$SERIAL" programmed with RF cal value "$CAL_VALUE
echo "Unplug debug cable, power cycle, cu to the board, confirm freq and record power"
--- /dev/null
+#!/bin/sh
+
+if [ -x ../ao-tools/ao-stmload/ao-stmload ]; then
+ STMLOAD=../ao-tools/ao-stmload/ao-stmload
+elif [ -x /usr/bin/ao-stmload ]; then
+ STMLOAD=/usr/bin/ao-stmload
+else
+ echo "Can't find ao-stmload! Aborting."
+ exit 1
+fi
+
+if [ -x ../ao-tools/ao-usbload/ao-usbload ]; then
+ USBLOAD=../ao-tools/ao-usbload/ao-usbload
+elif [ -x /usr/bin/ao-usbload ]; then
+ USBLOAD=/usr/bin/ao-usbload
+else
+ echo "Can't find ao-usbload! Aborting."
+ exit 1
+fi
+
+VERSION=1.0
+#VERSION=0.1
+
+echo "TeleMega v$VERSION Turn-On and Calibration Program"
+echo "Copyright 2010 by Bdale Garbee. Released under GPL v2"
+echo
+echo "Expectations:"
+echo "\tTeleMega v$VERSIOn powered from USB"
+echo "\t\twith ST-Link-V2 cabled to debug header"
+echo "\t\twith coax from UHF to frequency counter"
+echo
+echo -n "TeleMega-$VERSION serial number: "
+read SERIAL
+
+echo $STMLOAD
+
+$STMLOAD --raw ../src/telemega-v$VERSION/flash-loader/*.elf || exit 1
+
+sleep 2
+
+$USBLOAD --serial=$SERIAL ../src/telemega-v$VERSION/*.ihx || exit 1
+
+sleep 2
+
+dev=`ao-list | awk '/TeleMega-v'"$VERSION"'/ { print $3; exit(0); }'`
+
+case "$dev" in
+/dev/tty*)
+ echo "TeleMega found on $dev"
+ ;;
+*)
+ echo 'No TeleMega-v'"$VERSION"' found'
+ exit 1
+ ;;
+esac
+
+echo 'E 0' > $dev
+
+SERIAL=$SERIAL ./cal-freq $dev
+
+./cal-accel $dev
--- /dev/null
+#!/bin/sh
+
+if [ -x ../ao-tools/ao-load/ao-load ]; then
+ AOLOAD=../ao-tools/ao-load/ao-load
+elif [ -x /usr/bin/ao-load ]; then
+ AOLOAD=/usr/bin/ao-load
+else
+ echo "Can't find ao-load! Aborting."
+ exit 1
+fi
+
+if [ -x ../ao-tools/ao-rawload/ao-rawload ]; then
+ RAWLOAD=../ao-tools/ao-rawload/ao-rawload
+elif [ -x /usr/bin/ao-rawload ]; then
+ RAWLOAD=/usr/bin/ao-rawload
+else
+ echo "Can't find ao-rawload! Aborting."
+ exit 1
+fi
+
+echo "TeleMini v2.0 Turn-On and Calibration Program"
+echo "Copyright 2011 by Bdale Garbee. Released under GPL v2"
+echo "Copyright 2013 by Keith Packard. Released under GPL v2"
+echo
+echo "Expectations:"
+echo "\tTeleMini v2.0 powered from LiPo"
+echo "\t\twith TeleDongle (on /dev/ttyACM0) cabled to debug header"
+echo "\t\twith frequency counter able to sample RF output"
+echo
+echo -n "TeleMini serial number: "
+read SERIAL
+
+echo $RAWLOAD
+
+#TTY=/dev/ttyACM0
+PROGRAMMER="-D 186"
+BIN=../src/telemini-v2.0*.ihx
+
+$RAWLOAD $PROGRAMMER -r ao_led_blink.ihx
+echo "LEDs should be blinking"
+sleep 5
+
+$RAWLOAD $PROGRAMMER -r ao_radio_xmit.ihx
+echo -n "Generating RF carrier. Please enter measured frequency: "
+read FREQ
+
+CAL_VALUE=`nickle -e "floor(434.55 / $FREQ * 1186611 + 0.5)"`
+
+echo "Programming flash with cal value " $CAL_VALUE
+$AOLOAD $PROGRAMMER --cal=$CAL_VALUE $BIN $SERIAL
+
+echo "Serial number "$SERIAL" programmed with RF cal value "$CAL_VALUE
+echo "Unplug and replug USB, cu to the board, confirm freq and record power"
SUBDIRS=lib ao-rawload ao-dbg ao-bitbang ao-eeprom ao-list \
- ao-load ao-telem ao-stmload ao-send-telem ao-sky-flash \
- ao-dumpflash ao-edit-telem ao-dump-up
+ ao-load ao-telem ao-send-telem ao-sky-flash \
+ ao-dumpflash ao-edit-telem ao-dump-up ao-elftohex \
+ ao-flash ao-usbload
+if LIBSTLINK
+SUBDIRS += ao-stmload
+endif
ao_dbg_DEPENDENCIES = $(AO_DBG_LIBS)
-ao_dbg_LDADD=$(AO_DBG_LIBS) $(LIBUSB_LIBS) -lreadline
+ao_dbg_LDADD=$(AO_DBG_LIBS) $(LIBUSB_LIBS) $(LIBREADLINE)
ao_dbg_SOURCES = ao-dbg-parse.c ao-dbg-command.c ao-dbg-main.c
enum command_result
command_file (int argc, char **argv)
{
- struct hex_file *hex;
- struct hex_image *image;
+ struct ao_hex_file *hex;
+ struct ao_hex_image *image;
FILE *file;
if (argc != 2)
file = fopen (argv[1], "r");
if (!file)
return command_error;
- hex = ccdbg_hex_file_read(file, argv[1]);
+ hex = ao_hex_file_read(file, argv[1]);
fclose(file);
if (!hex)
return command_error;
if (hex->nrecord == 0) {
- ccdbg_hex_file_free(hex);
+ ao_hex_file_free(hex);
return command_error;
}
- image = ccdbg_hex_image_create(hex);
- ccdbg_hex_file_free(hex);
+ image = ao_hex_image_create(hex);
+ ao_hex_file_free(hex);
start_address = image->address;
ccdbg_set_rom(s51_dbg, image);
return command_success;
{
char *filename = argv[1];
FILE *file;
- struct hex_file *hex;
- struct hex_image *image;
+ struct ao_hex_file *hex;
+ struct ao_hex_image *image;
if (!filename)
return command_error;
perror(filename);
return command_error;
}
- hex = ccdbg_hex_file_read(file, filename);
+ hex = ao_hex_file_read(file, filename);
fclose(file);
if (!hex) {
return command_error;
}
- image = ccdbg_hex_image_create(hex);
- ccdbg_hex_file_free(hex);
+ image = ao_hex_image_create(hex);
+ ao_hex_file_free(hex);
if (!image) {
fprintf(stderr, "image create failed\n");
return command_error;
} else {
fprintf(stderr, "Can only load to RAM\n");
}
- ccdbg_hex_image_free(image);
+ ao_hex_image_free(image);
return command_success;
}
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include "ao-dbg.h"
#include <unistd.h>
#include <sys/types.h>
putc(c, s51_output);
}
+#if HAVE_LIBREADLINE
#include <readline/readline.h>
#include <readline/history.h>
+#endif
int
s51_read_line(char *line, int len)
{
int ret;
+#if HAVE_LIBREADLINE
if (s51_output == stdout && s51_input == stdin && s51_prompt) {
char *r;
line[len-1] = '\0';
add_history(r);
return 1;
- } else {
+ } else
+#endif
+ {
if (s51_prompt)
s51_printf("%s", s51_prompt);
else
if (!s51_tty) {
if (!s51_device)
s51_device = getenv("AO_DBG_DEVICE");
- s51_tty = cc_usbdevs_find_by_arg(s51_device, "TIDongle");
+ s51_tty = cc_usbdevs_find_by_arg(s51_device, "TeleDongle");
}
s51_dbg = ccdbg_open (s51_tty);
if (!s51_dbg)
--- /dev/null
+bin_PROGRAMS=ao-elftohex
+
+AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
+AO_ELFTOHEX_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a
+
+ao_elftohex_DEPENDENCIES = $(AO_ELFTOHEX_LIBS)
+
+ao_elftohex_LDADD=$(AO_ELFTOHEX_LIBS) -lelf
+
+ao_elftohex_SOURCES=ao-elftohex.c
+
+man_MANS = ao-elftohex.1
--- /dev/null
+.\"
+.\" Copyright © 2013 Keith Packard <keithp@keithp.com>
+.\"
+.\" This program is free software; you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation; either version 2 of the License, or
+.\" (at your option) any later version.
+.\"
+.\" This program is distributed in the hope that it will be useful, but
+.\" WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+.\" General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License along
+.\" with this program; if not, write to the Free Software Foundation, Inc.,
+.\" 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+.\"
+.\"
+.TH AO-LOAD 1 "ao-elftohex" ""
+.SH NAME
+ao-elftohex \- convert a program to IHX format
+.SH SYNOPSIS
+.B "ao-elftohex"
+[\--output-\fIoutput.ihx\fP]
+[\--verbose]
+\fIinput.elf\fP
+.SH DESCRIPTION
+.I ao-elftohex
+reads the specified .elf file and writes out a .ihx version.
+.SH OPTIONS
+.TP
+\--output=\fIoutput.ihx\fP
+This specifies the output file (default is stdout)
+.TP
+\--verbose
+Dumps some debug information.
+.SH AUTHOR
+Keith Packard
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <getopt.h>
+#include <stdlib.h>
+#include <string.h>
+#include "ao-hex.h"
+#include "ao-elf.h"
+#include "ao-verbose.h"
+
+static const struct option options[] = {
+ { .name = "verbose", .has_arg = 1, .val = 'v' },
+ { .name = "output", .has_arg = 1, .val = 'o' },
+ { 0, 0, 0, 0},
+};
+
+static void usage(char *program)
+{
+ fprintf(stderr, "usage: %s [--verbose=<level>] [--output=<output.ihx>] <input.elf>\n", program);
+ exit(1);
+}
+
+static int
+ends_with(char *whole, char *suffix)
+{
+ int whole_len = strlen(whole);
+ int suffix_len = strlen(suffix);
+
+ if (suffix_len > whole_len)
+ return 0;
+ return strcmp(whole + whole_len - suffix_len, suffix) == 0;
+}
+
+int
+main (int argc, char **argv)
+{
+ char *input = NULL;
+ char *output = NULL;
+ struct ao_hex_image *image;
+ struct ao_sym *file_symbols;
+ int num_file_symbols;
+ FILE *file;
+ int c;
+
+ while ((c = getopt_long(argc, argv, "v:o:", options, NULL)) != -1) {
+ switch (c) {
+ case 'o':
+ output = optarg;
+ break;
+ case 'v':
+ ao_verbose = (int) strtol(optarg, NULL, 0);
+ break;
+ default:
+ usage(argv[0]);
+ break;
+ }
+ }
+
+ input = argv[optind];
+ if (input == NULL)
+ usage(argv[0]);
+
+ if (ends_with (input, ".ihx"))
+ image = ao_hex_load(input, &file_symbols, &num_file_symbols);
+ else
+ image = ao_load_elf(input, &file_symbols, &num_file_symbols);
+
+ if (!image)
+ usage(argv[0]);
+
+ if (!output)
+ file = stdout;
+ else {
+ file = fopen(output, "w");
+ if (!file) {
+ perror(output);
+ exit(1);
+ }
+ }
+
+ if (!ao_hex_save(file, image, file_symbols, num_file_symbols)) {
+ fprintf(stderr, "%s: failed to write hex file\n", output ? output : "<stdout>");
+ if (output)
+ unlink(output);
+ exit(1);
+ }
+ exit(0);
+}
--- /dev/null
+bin_SCRIPTS=ao-flash-stm ao-flash-lpc
+
+man_MANS = ao-flash-stm.1 ao-flash-lpc.1
\ No newline at end of file
--- /dev/null
+#!/bin/sh
+case "$#" in
+0)
+ echo "usage: $0 <filename> ..."
+ exit 1
+ ;;
+esac
+cmds=/tmp/flash$$
+trap "rm $cmds" 0 1 15
+for file in "$@"; do
+ echo "flash write_image $file"
+done > $cmds
+openocd \
+ -f interface/stlink-v2.cfg \
+ -f target/lpc11u14.cfg \
+ -c init \
+ -c 'reset halt' \
+ -f $cmds \
+ -c 'reset init' \
+ -c 'reset run' \
+ -c shutdown
--- /dev/null
+.\"
+.\" Copyright © 2013 Keith Packard <keithp@keithp.com>
+.\"
+.\" This program is free software; you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation; either version 2 of the License, or
+.\" (at your option) any later version.
+.\"
+.\" This program is distributed in the hope that it will be useful, but
+.\" WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+.\" General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License along
+.\" with this program; if not, write to the Free Software Foundation, Inc.,
+.\" 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+.\"
+.\"
+.TH AO-FLASH-LPC 1 "ao-flash-lpc" ""
+.SH NAME
+ao-flash-lpc \- flash a program to an LPC11U14-based AltOS device using openocd
+.SH SYNOPSIS
+.B "ao-flash-lpc"
+\fIfile.elf\fP
+.SH DESCRIPTION
+.I ao-flash-lpc
+loads the specified .elf file into the target device flash memory.
+.SH USAGE
+.I ao-flash-lpc
+is a simple script that passes the correct arguments to openocd to
+load a file into the target device via a connected STlink
+debugging dongle.
+.SH "SEE ALSO"
+openocd(1)
+.SH AUTHOR
+Keith Packard
--- /dev/null
+#!/bin/sh
+case "$#" in
+0)
+ echo "usage: $0 <filename> ..."
+ exit 1
+ ;;
+esac
+
+ST_FLASH=st-flash
+
+if which $ST_FLASH > /dev/null; then
+ :
+else
+ echo "$0: $ST_FLASH not found. Check to see if the stlink package is installed"
+ exit 1
+fi
+
+file=$1
+
+bin=/tmp/flash$$.bin
+trap "rm $bin" 0 1 15
+
+base=`arm-none-eabi-nm $file | awk '/interrupt_vector/ { print $1 }'`
+case x"$base" in
+x)
+ echo "$file: No interrupt vector address found"
+ exit 1
+ ;;
+esac
+
+arm-none-eabi-objcopy -O binary $file $bin
+
+$ST_FLASH --reset write $bin $base
--- /dev/null
+.\"
+.\" Copyright © 2013 Keith Packard <keithp@keithp.com>
+.\"
+.\" This program is free software; you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation; either version 2 of the License, or
+.\" (at your option) any later version.
+.\"
+.\" This program is distributed in the hope that it will be useful, but
+.\" WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+.\" General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License along
+.\" with this program; if not, write to the Free Software Foundation, Inc.,
+.\" 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+.\"
+.\"
+.TH AO-FLASH-STM 1 "ao-flash-stm" ""
+.SH NAME
+ao-flash-stm \- flash a program to an STM32-based AltOS device using st-flash
+.SH SYNOPSIS
+.B "ao-flash-stm"
+\fIfile.elf\fP
+.SH DESCRIPTION
+.I ao-flash-stm
+loads the specified .elf file into the target device flash memory.
+.SH USAGE
+.I ao-flash-stm
+converts the specified .elf file into a raw binary file and then uses
+st-flash to load it into the target device via a connected STlink
+debugging dongle. If st-flash is not available,
+.I ao-flash-stm
+will emit an error message and terminate.
+.SH "SEE ALSO"
+st-flash(1)
+.SH AUTHOR
+Keith Packard
}
static int
-rewrite(struct hex_image *image, unsigned addr, char *data, int len)
+rewrite(struct ao_hex_image *image, unsigned addr, char *data, int len)
{
int i;
if (addr < image->address || image->address + image->length < addr + len)
struct ccdbg *dbg;
uint8_t status;
uint16_t pc;
- struct hex_file *hex;
- struct hex_image *image;
+ struct ao_hex_file *hex;
+ struct ao_hex_image *image;
char *filename;
FILE *file;
FILE *map;
}
fclose(map);
- hex = ccdbg_hex_file_read(file, filename);
+ hex = ao_hex_file_read(file, filename);
fclose(file);
if (!hex) {
perror(filename);
exit (1);
}
- image = ccdbg_hex_image_create(hex);
+ image = ao_hex_image_create(hex);
if (!image) {
fprintf(stderr, "image create failed\n");
exit (1);
}
- ccdbg_hex_file_free(hex);
+ ao_hex_file_free(hex);
serial = strtoul(serial_string, NULL, 0);
if (!serial)
} else {
printf("Cannot load code to 0x%04x\n",
image->address);
- ccdbg_hex_image_free(image);
+ ao_hex_image_free(image);
ccdbg_close(dbg);
exit(1);
}
--- /dev/null
+bin_PROGRAMS=ao-mega
+
+AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
+AO_POSTFLIGHT_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a
+
+ao_mega_DEPENDENCIES = $(AO_POSTFLIGHT_LIBS)
+
+ao_mega_LDADD=$(AO_POSTFLIGHT_LIBS) $(LIBUSB_LIBS)
+
+ao_mega_SOURCES = ao-mega.c
+
+man_MANS = ao-mega.1
--- /dev/null
+.\"
+.\" Copyright © 2009 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; either version 2 of the License, or
+.\" (at your option) any later version.
+.\"
+.\" This program is distributed in the hope that it will be useful, but
+.\" WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+.\" General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License along
+.\" with this program; if not, write to the Free Software Foundation, Inc.,
+.\" 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+.\"
+.\"
+.TH AO-TELEM 1 "ao-mega" ""
+.SH NAME
+ao-mega \- Dump a mega flight log (eeprom only)
+.SH SYNOPSIS
+.B "ao-mega"
+{flight.mega}
+.SH DESCRIPTION
+.I ao-mega
+reads the specified flight log and dumps it in human readable format.
+output.
+.SH AUTHOR
+Keith Packard
--- /dev/null
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#define _GNU_SOURCE
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <getopt.h>
+#include "cc.h"
+
+static const struct option options[] = {
+ { 0, 0, 0, 0},
+};
+
+static void usage(char *program)
+{
+ fprintf(stderr, "usage: %s\n"
+ "\t{flight.mega} ...\n", program);
+ exit(1);
+}
+
+#define bool(b) ((b) ? "true" : "false")
+
+static const char *state_names[] = {
+ "startup",
+ "idle",
+ "pad",
+ "boost",
+ "fast",
+ "coast",
+ "drogue",
+ "main",
+ "landed",
+ "invalid"
+};
+
+
+#define NUM_STATE (sizeof state_names/sizeof state_names[0])
+
+int
+main (int argc, char **argv)
+{
+ char line[256];
+ int c, i, ret, j;
+ char *s;
+ FILE *file;
+ int serial;
+ const char *state;
+ while ((c = getopt_long(argc, argv, "", options, NULL)) != -1) {
+ switch (c) {
+ default:
+ usage(argv[0]);
+ break;
+ }
+ }
+ for (i = optind; i < argc; i++) {
+ file = fopen(argv[i], "r");
+ if (!file) {
+ perror(argv[i]);
+ ret++;
+ continue;
+ }
+ s = strstr(argv[i], "-serial-");
+ if (s)
+ serial = atoi(s + 8);
+ else
+ serial = 0;
+ while (fgets(line, sizeof (line), file)) {
+ struct ao_log_mega log;
+
+ if (cc_mega_parse(line, &log)) {
+ if (log.is_config) {
+ printf ("kind %d\n", log.u.config_int.kind);
+ } else {
+ printf ("tick %5d ", log.tick);
+ switch (log.type) {
+ case AO_LOG_FLIGHT:
+ printf ("flight %5u ground_accel %d ground_pres %u\n",
+ log.u.flight.flight,
+ log.u.flight.ground_accel,
+ log.u.flight.ground_pres);
+ break;
+ case AO_LOG_STATE:
+ if (log.u.state.state < NUM_STATE)
+ state = state_names[log.u.state.state];
+ else
+ state = "invalid";
+ printf ("state %d (%s)\n", log.u.state.state, state);
+ break;
+ case AO_LOG_SENSOR:
+ printf ("p %9u t %9u ax %6d ay %6d az %6d gx %6d gy %6d gz %6d mx %6d my %6d mz %6d a %6d\n",
+ log.u.sensor.pres,
+ log.u.sensor.temp,
+ log.u.sensor.accel_x,
+ log.u.sensor.accel_y,
+ log.u.sensor.accel_z,
+ log.u.sensor.gyro_x,
+ log.u.sensor.gyro_y,
+ log.u.sensor.gyro_z,
+ log.u.sensor.mag_x,
+ log.u.sensor.mag_y,
+ log.u.sensor.mag_z,
+ log.u.sensor.accel);
+ break;
+ case AO_LOG_TEMP_VOLT:
+ printf ("batt %6d pbatt %6d n_sense %d",
+ log.u.volt.v_batt,
+ log.u.volt.v_pbatt,
+ log.u.volt.n_sense);
+ for (j = 0; j < log.u.volt.n_sense; j++) {
+ printf (" s%d %6d",
+ j, log.u.volt.sense[j]);
+ }
+ printf ("pyro %04x\n", log.u.volt.pyro);
+ printf ("\n");
+ break;
+ default:
+ printf ("type %c\n", log.type, log.tick);
+ break;
+ }
+ }
+ }
+ }
+ fclose (file);
+
+ }
+ return ret;
+}
struct ccdbg *dbg;
uint8_t status;
uint16_t pc;
- struct hex_file *hex;
- struct hex_image *image;
+ struct ao_hex_file *hex;
+ struct ao_hex_image *image;
char *filename;
FILE *file;
char *tty = NULL;
perror(filename);
exit(1);
}
- hex = ccdbg_hex_file_read(file, filename);
+ hex = ao_hex_file_read(file, filename);
fclose(file);
if (!hex)
exit (1);
- image = ccdbg_hex_image_create(hex);
+ image = ao_hex_image_create(hex);
if (!image) {
fprintf(stderr, "image create failed\n");
exit (1);
}
- ccdbg_hex_file_free(hex);
+ ao_hex_file_free(hex);
if (!tty)
tty = cc_usbdevs_find_by_arg(device, "TIDongle");
dbg = ccdbg_open(tty);
} else {
printf("Cannot load code to 0x%04x\n",
image->address);
- ccdbg_hex_image_free(image);
+ ao_hex_image_free(image);
ccdbg_close(dbg);
exit(1);
}
bin_PROGRAMS=ao-stmload
-LIBSTLINKDIR=/local/src/stlink
-
-AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBSTLINK_CFLAGS) $(LIBUSB_CFLAGS)
+AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(STLINK_CFLAGS) $(LIBUSB_CFLAGS)
AO_STMLOAD_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a
ao_stmload_DEPENDENCIES = $(AO_STMLOAD_LIBS)
-ao_stmload_LDADD=$(AO_STMLOAD_LIBS) $(LIBSTLINK_LIBS) $(LIBUSB_LIBS) -lelf
+ao_stmload_LDADD=$(AO_STMLOAD_LIBS) $(STLINK_LIBS) $(LIBUSB_LIBS) -lelf
-ao_stmload_SOURCES=ao-stmload.c ao-elf.c ao-stmload.h ao-selfload.c
+ao_stmload_SOURCES=ao-stmload.c ao-stmload.h
man_MANS = ao-stmload.1
+++ /dev/null
-/*
- * Copyright © 2013 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-#include "ao-elf.h"
-#include <err.h>
-#include <gelf.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include "ccdbg.h"
-#include "ao-stmload.h"
-
-/*
- * Look through the Elf file for the AltOS symbols
- * that can be adjusted before the image is written
- * to the device
- */
-static int
-find_symbols (Elf *e)
-{
- Elf_Scn *scn;
- Elf_Data *symbol_data = NULL;
- GElf_Shdr shdr;
- GElf_Sym sym;
- int i, symbol_count, s;
- int required = 0;
- char *symbol_name;
- char *section_name;
- size_t shstrndx;
-
- if (elf_getshdrstrndx(e, &shstrndx) < 0)
- return 0;
-
- /*
- * Find the symbols
- */
-
- scn = NULL;
- while ((scn = elf_nextscn(e, scn)) != NULL) {
-
- if (gelf_getshdr(scn, &shdr) != &shdr)
- return 0;
-
- if (shdr.sh_type == SHT_SYMTAB) {
- symbol_data = elf_getdata(scn, NULL);
- symbol_count = shdr.sh_size / shdr.sh_entsize;
- break;
- }
- }
-
- if (!symbol_data)
- return 0;
-
- for (i = 0; i < symbol_count; i++) {
- gelf_getsym(symbol_data, i, &sym);
-
- symbol_name = elf_strptr(e, shdr.sh_link, sym.st_name);
-
- for (s = 0; s < ao_num_symbols; s++)
- if (!strcmp (ao_symbols[s].name, symbol_name)) {
- int t;
- ao_symbols[s].addr = sym.st_value;
- if (ao_symbols[s].required)
- ++required;
- }
- }
-
- return required >= ao_num_required_symbols;
-}
-
-uint32_t round4(uint32_t a) {
- return (a + 3) & ~3;
-}
-
-struct hex_image *
-new_load (uint32_t addr, uint32_t len)
-{
- struct hex_image *new;
-
- len = round4(len);
- new = calloc (1, sizeof (struct hex_image) + len);
- if (!new)
- abort();
-
- new->address = addr;
- new->length = len;
- return new;
-}
-
-void
-load_paste(struct hex_image *into, struct hex_image *from)
-{
- if (from->address < into->address || into->address + into->length < from->address + from->length)
- abort();
-
- memcpy(into->data + from->address - into->address, from->data, from->length);
-}
-
-/*
- * Make a new load structure large enough to hold the old one and
- * the new data
- */
-struct hex_image *
-expand_load(struct hex_image *from, uint32_t address, uint32_t length)
-{
- struct hex_image *new;
-
- if (from) {
- uint32_t from_last = from->address + from->length;
- uint32_t last = address + length;
-
- if (address > from->address)
- address = from->address;
- if (last < from_last)
- last = from_last;
-
- length = last - address;
-
- if (address == from->address && length == from->length)
- return from;
- }
- new = new_load(address, length);
- if (from) {
- load_paste(new, from);
- free (from);
- }
- return new;
-}
-
-/*
- * Create a new load structure with data from the existing one
- * and the new data
- */
-struct hex_image *
-load_write(struct hex_image *from, uint32_t address, uint32_t length, void *data)
-{
- struct hex_image *new;
-
- new = expand_load(from, address, length);
- memcpy(new->data + address - new->address, data, length);
- return new;
-}
-
-/*
- * Construct a large in-memory block for all
- * of the loaded sections of the program
- */
-static struct hex_image *
-get_load(Elf *e)
-{
- Elf_Scn *scn;
- size_t shstrndx;
- GElf_Shdr shdr;
- Elf_Data *data;
- char *got_name;
- size_t nphdr;
- size_t p;
- GElf_Phdr phdr;
- GElf_Addr p_paddr;
- GElf_Off p_offset;
- GElf_Addr sh_paddr;
- struct hex_image *load = NULL;
- char *section_name;
- size_t nshdr;
- size_t s;
-
- if (elf_getshdrstrndx(e, &shstrndx) < 0)
- return 0;
-
- if (elf_getphdrnum(e, &nphdr) < 0)
- return 0;
-
- if (elf_getshdrnum(e, &nshdr) < 0)
- return 0;
-
- /*
- * As far as I can tell, all of the phdr sections should
- * be flashed to memory
- */
- for (p = 0; p < nphdr; p++) {
-
- /* Find this phdr */
- gelf_getphdr(e, p, &phdr);
-
- if (phdr.p_type != PT_LOAD)
- continue;
-
- p_offset = phdr.p_offset;
- /* Get the associated file section */
-
-#if 0
- printf ("offset %08x vaddr %08x paddr %08x filesz %08x memsz %08x\n",
- (uint32_t) phdr.p_offset,
- (uint32_t) phdr.p_vaddr,
- (uint32_t) phdr.p_paddr,
- (uint32_t) phdr.p_filesz,
- (uint32_t) phdr.p_memsz);
-#endif
-
- for (s = 0; s < nshdr; s++) {
- scn = elf_getscn(e, s);
-
- if (!scn) {
- printf ("getscn failed\n");
- abort();
- }
- if (gelf_getshdr(scn, &shdr) != &shdr) {
- printf ("gelf_getshdr failed\n");
- abort();
- }
-
- section_name = elf_strptr(e, shstrndx, shdr.sh_name);
-
- if (phdr.p_offset <= shdr.sh_offset && shdr.sh_offset < phdr.p_offset + phdr.p_filesz) {
-
- if (shdr.sh_size == 0)
- continue;
-
- sh_paddr = phdr.p_paddr + shdr.sh_offset - phdr.p_offset;
-
- printf ("\tsize %08x rom %08x exec %08x %s\n",
- (uint32_t) shdr.sh_size,
- (uint32_t) sh_paddr,
- (uint32_t) shdr.sh_addr,
- section_name);
-
- data = elf_getdata(scn, NULL);
-
- /* Write the section data into the memory block */
- load = load_write(load, sh_paddr, shdr.sh_size, data->d_buf);
- }
- }
- }
- return load;
-}
-
-/*
- * Open the specified ELF file and
- * check for the symbols we need
- */
-
-struct hex_image *
-ao_load_elf(char *name)
-{
- int fd;
- Elf *e;
- Elf_Scn *scn;
- Elf_Data *symbol_data = NULL;
- GElf_Shdr shdr;
- GElf_Sym sym;
- size_t n, shstrndx, sz;
- int i, symbol_count, s;
- int required = 0;
- struct hex_image *image;
-
- if (elf_version(EV_CURRENT) == EV_NONE)
- return NULL;
-
- fd = open(name, O_RDONLY, 0);
-
- if (fd < 0)
- return NULL;
-
- e = elf_begin(fd, ELF_C_READ, NULL);
-
- if (!e)
- return NULL;
-
- if (elf_kind(e) != ELF_K_ELF)
- return NULL;
-
- if (elf_getshdrstrndx(e, &shstrndx) != 0)
- return NULL;
-
- if (!find_symbols(e)) {
- fprintf (stderr, "Cannot find required symbols\n");
- return NULL;
- }
-
- image = get_load(e);
- if (!image) {
- fprintf (stderr, "Cannot create memory image from file\n");
- return NULL;
- }
-
- return image;
-}
+++ /dev/null
-/*
- * Copyright © 2013 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-#ifndef _AO_ELF_H_
-#define _AO_ELF_H_
-
-struct hex_image *
-ao_load_elf(char *name);
-
-#endif
+++ /dev/null
-/*
- * Copyright © 2013 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <sysexits.h>
-#include <unistd.h>
-#include <string.h>
-#include "cc.h"
-#include "cc-usb.h"
-#include "ccdbg.h"
-#include "ao-stmload.h"
-
-int ao_self_verbose;
-
-#define TRACE(...) if (ao_self_verbose) printf (__VA_ARGS__)
-
-void
-ao_self_block_read(struct cc_usb *cc, uint32_t address, uint8_t block[256])
-{
- int byte;
- cc_usb_sync(cc);
- cc_usb_printf(cc, "R %x\n", address);
- for (byte = 0; byte < 0x100; byte++) {
- block[byte] = cc_usb_getchar(cc);
- }
- TRACE ("\nread %08x\n", address);
- for (byte = 0; byte < 0x100; byte++) {
- TRACE (" %02x", block[byte]);
- if ((byte & 0xf) == 0xf)
- TRACE ("\n");
- }
-}
-
-void
-ao_self_block_write(struct cc_usb *cc, uint32_t address, uint8_t block[256])
-{
- int byte;
- cc_usb_sync(cc);
- cc_usb_printf(cc, "W %x\n", address);
- TRACE ("write %08x\n", address);
- for (byte = 0; byte < 0x100; byte++) {
- TRACE (" %02x", block[byte]);
- if ((byte & 0xf) == 0xf)
- TRACE ("\n");
- }
- for (byte = 0; byte < 0x100; byte++) {
- cc_usb_printf(cc, "%c", block[byte]);
- }
-}
-
-struct hex_image *
-ao_self_read(struct cc_usb *cc, uint32_t address, uint32_t length)
-{
- struct hex_image *image;
- int pages;
- int page;
- uint32_t base = address & ~0xff;
- uint32_t bound = (address + length + 0xff) & ~0xff;
-
- image = calloc(sizeof (struct hex_image) + (bound - base), 1);
- image->address = base;
- image->length = bound - base;
- pages = image->length / 0x100;
- for (page = 0; page < pages; page++)
- ao_self_block_read(cc, image->address + page * 0x100, image->data + page * 0x100);
- return image;
-}
-
-int
-ao_self_write(struct cc_usb *cc, struct hex_image *image)
-{
- uint8_t block[256];
- uint8_t check[256];
- uint32_t base, bound, length, address;
- uint32_t pages;
- uint32_t page;
-
- base = image->address & ~0xff;
- bound = (image->address + image->length + 0xff) & ~0xff;
-
- address = base;
- length = bound - base;
-
- pages = length / 0x100;
- printf ("Write %08x %d pages: ", address, length/0x100); fflush(stdout);
- for (page = 0; page < pages; page++) {
- uint32_t start, stop;
- address = base + page * 0x100;
-
- if (address < image->address || address + 0x100 > image->address + image->length) {
- ao_self_block_read(cc, address, block);
- }
- start = address;
- stop = address + 0x100;
- if (start < image->address)
- start = image->address;
- if (stop > image->address + image->length)
- stop = image->address + image->length;
- memcpy(block + start - address, image->data + start - image->address, stop - start);
- ao_self_block_write(cc, address, block);
- ao_self_block_read(cc, address, check);
- if (memcmp(block, check, 0x100) != 0) {
- fprintf(stderr, "Block at 0x%08x doesn't match\n", address);
- return 0;
- }
- putchar('.'); fflush(stdout);
- }
- printf("done\n");
- cc_usb_printf(cc,"a\n");
- return 1;
-}
#include <unistd.h>
#include <getopt.h>
#include <string.h>
+#include <stdbool.h>
#include "stlink-common.h"
#include "ao-elf.h"
#include "ccdbg.h"
-#include "cc-usb.h"
#include "cc.h"
#include "ao-stmload.h"
+#include "ao-selfload.h"
+#include "ao-verbose.h"
+#include "ao-editaltos.h"
-#define AO_USB_DESC_STRING 3
-
-struct sym ao_symbols[] = {
-
- { 0, AO_BOOT_APPLICATION_BASE + 0x100, "ao_romconfig_version", 1 },
-#define AO_ROMCONFIG_VERSION (ao_symbols[0].addr)
-
- { 0, AO_BOOT_APPLICATION_BASE + 0x102, "ao_romconfig_check", 1 },
-#define AO_ROMCONFIG_CHECK (ao_symbols[1].addr)
-
- { 0, AO_BOOT_APPLICATION_BASE + 0x104, "ao_serial_number", 1 },
-#define AO_SERIAL_NUMBER (ao_symbols[2].addr)
-
- { 0, AO_BOOT_APPLICATION_BASE + 0x108, "ao_radio_cal", 0 },
-#define AO_RADIO_CAL (ao_symbols[3].addr)
-
- { 0, AO_BOOT_APPLICATION_BASE + 0x10c, "ao_usb_descriptors", 0 },
-#define AO_USB_DESCRIPTORS (ao_symbols[4].addr)
-};
-
-#define NUM_SYMBOLS 5
-#define NUM_REQUIRED_SYMBOLS 3
-
-int ao_num_symbols = NUM_SYMBOLS;
-int ao_num_required_symbols = NUM_REQUIRED_SYMBOLS;
-
-/*
- * Edit the to-be-written memory block
- */
-static int
-rewrite(struct hex_image *load, unsigned address, uint8_t *data, int length)
-{
- int i;
-
- if (address < load->address || load->address + load->length < address + length)
- return 0;
-
- printf("rewrite %04x:", address);
- for (i = 0; i < length; i++)
- printf (" %02x", load->data[address - load->address + i]);
- printf(" ->");
- for (i = 0; i < length; i++)
- printf (" %02x", data[i]);
- printf("\n");
- memcpy(load->data + address - load->address, data, length);
-}
-
-/*
- * Read a 16-bit value from the USB target
- */
-
-static uint16_t
-get_uint16_cc(struct cc_usb *cc, uint32_t addr)
-{
- struct hex_image *hex = ao_self_read(cc, addr, 2);
- uint16_t v;
- uint8_t *data;
-
- if (!hex)
- return 0;
- data = hex->data + addr - hex->address;
- v = data[0] | (data[1] << 8);
- free(hex);
- return v;
-}
-
-static uint32_t
-get_uint32_cc(struct cc_usb *cc, uint32_t addr)
-{
- struct hex_image *hex = ao_self_read(cc, addr, 4);
- uint32_t v;
- uint8_t *data;
-
- if (!hex)
- return 0;
- data = hex->data + addr - hex->address;
- v = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
- free(hex);
- return v;
-}
/*
* Read a 16-bit value from the target device with arbitrary
}
static uint16_t
-get_uint16(stlink_t *sl, struct cc_usb *cc, uint32_t addr)
+get_uint16(stlink_t *sl, uint32_t addr)
{
uint16_t result;
- if (cc)
- result = get_uint16_cc(cc, addr);
- else
- result = get_uint16_sl(sl, addr);
+ result = get_uint16_sl(sl, addr);
printf ("read 0x%08x = 0x%04x\n", addr, result);
return result;
}
* alignment
*/
static uint32_t
-get_uint32(stlink_t *sl, struct cc_usb *cc, uint32_t addr)
+get_uint32(stlink_t *sl, uint32_t addr)
{
uint32_t result;
- if (cc)
- result = get_uint32_cc(cc, addr);
- else
- result = get_uint32_sl(sl, addr);
+ result = get_uint32_sl(sl, addr);
printf ("read 0x%08x = 0x%08x\n", addr, result);
return result;
}
* places this at 0x100 from the start of the rom section
*/
static int
-check_flashed(stlink_t *sl, struct cc_usb *cc)
+check_flashed(stlink_t *sl)
{
- uint16_t romconfig_version = get_uint16(sl, cc, AO_ROMCONFIG_VERSION);
- uint16_t romconfig_check = get_uint16(sl, cc, AO_ROMCONFIG_CHECK);
+ uint16_t romconfig_version = get_uint16(sl, AO_ROMCONFIG_VERSION);
+ uint16_t romconfig_check = get_uint16(sl, AO_ROMCONFIG_CHECK);
if (romconfig_version != (uint16_t) ~romconfig_check) {
fprintf (stderr, "Device has not been flashed before\n");
}
static const struct option options[] = {
- { .name = "stlink", .has_arg = 0, .val = 'S' },
- { .name = "tty", .has_arg = 1, .val = 'T' },
- { .name = "device", .has_arg = 1, .val = 'D' },
+ { .name = "v1", .has_arg = 0, .val = '1' },
+ { .name = "raw", .has_arg = 0, .val = 'r' },
{ .name = "cal", .has_arg = 1, .val = 'c' },
{ .name = "serial", .has_arg = 1, .val = 's' },
- { .name = "verbose", .has_arg = 0, .val = 'v' },
+ { .name = "verbose", .has_arg = 1, .val = 'v' },
{ 0, 0, 0, 0},
};
static void usage(char *program)
{
- fprintf(stderr, "usage: %s [--stlink] [--verbose] [--device=<device>] [-tty=<tty>] [--cal=<radio-cal>] [--serial=<serial>] file.{elf,ihx}\n", program);
+ fprintf(stderr, "usage: %s [--v1] [--raw] [--verbose=<verbose>] [--cal=<radio-cal>] [--serial=<serial>] file.{elf,ihx}\n", program);
exit(1);
}
void
-done(stlink_t *sl, struct cc_usb *cc, int code)
+done(stlink_t *sl, int code)
{
- if (cc) {
-/* cc_usb_printf(cc, "a\n"); */
- cc_usb_close(cc);
- }
- if (sl) {
- stlink_reset(sl);
- stlink_run(sl);
- stlink_exit_debug_mode(sl);
- stlink_close(sl);
- }
+ stlink_reset(sl);
+ stlink_run(sl);
+ stlink_exit_debug_mode(sl);
+ stlink_close(sl);
exit (code);
}
int
main (int argc, char **argv)
{
- char *device = NULL;
+ int stlink_v1 = 0;
+ int raw = 0;
char *filename;
Elf *e;
char *serial_end;
int c;
stlink_t *sl = NULL;
int was_flashed = 0;
- struct hex_image *load;
+ struct ao_hex_image *load;
int tries;
- struct cc_usb *cc = NULL;
- int use_stlink = 0;
- char *tty = NULL;
int success;
int verbose = 0;
+ struct ao_sym *file_symbols;
+ int num_file_symbols;
- while ((c = getopt_long(argc, argv, "T:D:c:s:Sv", options, NULL)) != -1) {
+ while ((c = getopt_long(argc, argv, "1rc:s:v:", options, NULL)) != -1) {
switch (c) {
- case 'T':
- tty = optarg;
+ case '1':
+ stlink_v1 = 1;
break;
- case 'D':
- device = optarg;
+ case 'r':
+ raw = 1;
break;
case 'c':
cal = strtoul(optarg, &cal_end, 10);
if (serial_end == optarg || *serial_end != '\0')
usage(argv[0]);
break;
- case 'S':
- use_stlink = 1;
- break;
case 'v':
verbose++;
break;
}
}
- ao_self_verbose = verbose;
+ ao_verbose = verbose;
if (verbose > 1)
ccdbg_add_debug(CC_DEBUG_BITBANG);
usage(argv[0]);
if (ends_with (filename, ".elf")) {
- load = ao_load_elf(filename);
+ load = ao_load_elf(filename, &file_symbols, &num_file_symbols);
} else if (ends_with (filename, ".ihx")) {
- int i;
- load = ccdbg_hex_load(filename);
- for (i = 0; i < ao_num_symbols; i++)
- ao_symbols[i].addr = ao_symbols[i].default_addr;
+ load = ao_hex_load(filename, &file_symbols, &num_file_symbols);
} else
usage(argv[0]);
- if (use_stlink) {
- /* Connect to the programming dongle
- */
+ if (!raw) {
+ if (!ao_editaltos_find_symbols(file_symbols, num_file_symbols, ao_symbols, ao_num_symbols)) {
+ fprintf(stderr, "Cannot find required symbols\n");
+ usage(argv[0]);
+ }
+ }
+
+ /* Connect to the programming dongle
+ */
- for (tries = 0; tries < 3; tries++) {
- if (device) {
- sl = stlink_v1_open(50);
- } else {
- sl = stlink_open_usb(50);
+ for (tries = 0; tries < 3; tries++) {
+ if (stlink_v1) {
+ sl = stlink_v1_open(50);
+ } else {
+ sl = stlink_open_usb(50);
- }
- if (!sl) {
- fprintf (stderr, "No STLink devices present\n");
- done (sl, NULL, 1);
- }
-
- if (sl->chip_id != 0)
- break;
- stlink_reset(sl);
- stlink_close(sl);
- sl = NULL;
}
if (!sl) {
- fprintf (stderr, "Debugger connection failed\n");
- exit(1);
+ fprintf (stderr, "No STLink devices present\n");
+ done (sl, 1);
}
- /* Verify that the loaded image fits entirely within device flash
- */
- if (load->address < sl->flash_base ||
- sl->flash_base + sl->flash_size < load->address + load->length) {
- fprintf (stderr, "\%s\": Invalid memory range 0x%08x - 0x%08x\n", filename,
- load->address, load->address + load->length);
- done(sl, NULL, 1);
- }
-
- /* Enter debugging mode
- */
- if (stlink_current_mode(sl) == STLINK_DEV_DFU_MODE)
- stlink_exit_dfu_mode(sl);
-
- if (stlink_current_mode(sl) != STLINK_DEV_DEBUG_MODE)
- stlink_enter_swd_mode(sl);
- } else {
- int is_loader;
- int tries;
-
- for (tries = 0; tries < 3; tries++) {
- char *this_tty = tty;
- if (!this_tty)
- this_tty = cc_usbdevs_find_by_arg(device, "AltosFlash");
- if (!this_tty)
- this_tty = cc_usbdevs_find_by_arg(device, "MegaMetrum");
- if (!this_tty)
- this_tty = getenv("ALTOS_TTY");
- if (!this_tty)
- this_tty="/dev/ttyACM0";
-
- cc = cc_usb_open(this_tty);
-
- if (!cc)
- exit(1);
- cc_usb_printf(cc, "v\n");
- is_loader = 0;
- for (;;) {
- char line[256];
- cc_usb_getline(cc, line, sizeof(line));
- if (!strncmp(line, "altos-loader", 12))
- is_loader = 1;
- if (!strncmp(line, "software-version", 16))
- break;
- }
- if (is_loader)
- break;
- printf ("rebooting to loader\n");
- cc_usb_printf(cc, "X\n");
- cc_usb_close(cc);
- sleep(1);
- cc = NULL;
- }
- if (!is_loader) {
- fprintf(stderr, "Cannot switch to boot loader\n");
- exit(1);
- }
-#if 0
- {
- uint8_t check[256];
- int i = 0;
-
- ao_self_block_read(cc, AO_BOOT_APPLICATION_BASE, check);
- for (;;) {
- uint8_t block[256];
- putchar ('.');
- if (++i == 40) {
- putchar('\n');
- i = 0;
- }
- fflush(stdout);
- ao_self_block_write(cc, AO_BOOT_APPLICATION_BASE, block);
- ao_self_block_read(cc, AO_BOOT_APPLICATION_BASE, block);
- if (memcmp(block, check, 256) != 0) {
- fprintf (stderr, "read differed\n");
- exit(1);
- }
- }
- }
-#endif
+ if (sl->chip_id != 0)
+ break;
+ stlink_reset(sl);
+ stlink_close(sl);
+ sl = NULL;
}
-
- /* Go fetch existing config values
- * if available
- */
- was_flashed = check_flashed(sl, cc);
-
- if (!serial) {
- if (!was_flashed) {
- fprintf (stderr, "Must provide serial number\n");
- done(sl, cc, 1);
- }
- serial = get_uint16(sl, cc, AO_SERIAL_NUMBER);
- if (!serial || serial == 0xffff) {
- fprintf (stderr, "Invalid existing serial %d\n", serial);
- done(sl, cc, 1);
- }
+ if (!sl) {
+ fprintf (stderr, "Debugger connection failed\n");
+ exit(1);
}
- if (!cal && AO_RADIO_CAL && was_flashed) {
- cal = get_uint32(sl, cc, AO_RADIO_CAL);
- if (!cal || cal == 0xffffffff) {
- fprintf (stderr, "Invalid existing rf cal %d\n", cal);
- done(sl, cc, 1);
- }
+ /* Verify that the loaded image fits entirely within device flash
+ */
+ if (load->address < sl->flash_base ||
+ sl->flash_base + sl->flash_size < load->address + load->length) {
+ fprintf (stderr, "\%s\": Invalid memory range 0x%08x - 0x%08x\n", filename,
+ load->address, load->address + load->length);
+ done(sl, 1);
}
- /* Write the config values into the flash image
+ /* Enter debugging mode
*/
+ if (stlink_current_mode(sl) == STLINK_DEV_DFU_MODE)
+ stlink_exit_dfu_mode(sl);
- serial_int[0] = serial & 0xff;
- serial_int[1] = (serial >> 8) & 0xff;
+ if (stlink_current_mode(sl) != STLINK_DEV_DEBUG_MODE)
+ stlink_enter_swd_mode(sl);
- if (!rewrite(load, AO_SERIAL_NUMBER, serial_int, sizeof (serial_int))) {
- fprintf(stderr, "Cannot rewrite serial integer at %08x\n",
- AO_SERIAL_NUMBER);
- done(sl, cc, 1);
- }
- if (AO_USB_DESCRIPTORS) {
- uint32_t usb_descriptors = AO_USB_DESCRIPTORS - load->address;
- string_num = 0;
+ if (!raw) {
+ /* Go fetch existing config values
+ * if available
+ */
+ was_flashed = check_flashed(sl);
- while (load->data[usb_descriptors] != 0 && usb_descriptors < load->length) {
- if (load->data[usb_descriptors+1] == AO_USB_DESC_STRING) {
- ++string_num;
- if (string_num == 4)
- break;
+ if (!serial) {
+ if (!was_flashed) {
+ fprintf (stderr, "Must provide serial number\n");
+ done(sl, 1);
+ }
+ serial = get_uint16(sl, AO_SERIAL_NUMBER);
+ if (!serial || serial == 0xffff) {
+ fprintf (stderr, "Invalid existing serial %d\n", serial);
+ done(sl, 1);
}
- usb_descriptors += load->data[usb_descriptors];
- }
- if (usb_descriptors >= load->length || load->data[usb_descriptors] == 0 ) {
- fprintf(stderr, "Cannot rewrite serial string at %08x\n", AO_USB_DESCRIPTORS);
- done(sl, cc, 1);
}
- serial_ucs2_len = load->data[usb_descriptors] - 2;
- serial_ucs2 = malloc(serial_ucs2_len);
- if (!serial_ucs2) {
- fprintf(stderr, "Malloc(%d) failed\n", serial_ucs2_len);
- done(sl, cc, 1);
- }
- s = serial;
- for (i = serial_ucs2_len / 2; i; i--) {
- serial_ucs2[i * 2 - 1] = 0;
- serial_ucs2[i * 2 - 2] = (s % 10) + '0';
- s /= 10;
- }
- if (!rewrite(load, usb_descriptors + 2 + load->address, serial_ucs2, serial_ucs2_len)) {
- fprintf (stderr, "Cannot rewrite USB descriptor at %08x\n", AO_USB_DESCRIPTORS);
- done(sl, cc, 1);
+ if (!cal && AO_RADIO_CAL && was_flashed) {
+ cal = get_uint32(sl, AO_RADIO_CAL);
+ if (!cal || cal == 0xffffffff) {
+ fprintf (stderr, "Invalid existing rf cal %d\n", cal);
+ done(sl, 1);
+ }
}
- }
-
- if (cal && AO_RADIO_CAL) {
- cal_int[0] = cal & 0xff;
- cal_int[1] = (cal >> 8) & 0xff;
- cal_int[2] = (cal >> 16) & 0xff;
- cal_int[3] = (cal >> 24) & 0xff;
- if (!rewrite(load, AO_RADIO_CAL, cal_int, sizeof (cal_int))) {
- fprintf(stderr, "Cannot rewrite radio calibration at %08x\n", AO_RADIO_CAL);
- exit(1);
- }
+ if (!ao_editaltos(load, serial, cal))
+ done(sl, 1);
}
/* And flash the resulting image to the device
*/
- if (cc)
- success = ao_self_write(cc, load);
- else
- success = (stlink_write_flash(sl, load->address, load->data, load->length) >= 0);
+
+ success = (stlink_write_flash(sl, load->address, load->data, load->length) >= 0);
if (!success) {
fprintf (stderr, "\"%s\": Write failed\n", filename);
- done(sl, cc, 1);
+ done(sl, 1);
}
- done(sl, cc, 0);
+ done(sl, 0);
}
#ifndef _AO_STMLOAD_H_
#define _AO_STMLOAD_H_
-struct sym {
- unsigned addr;
- unsigned default_addr;
- char *name;
- int required;
-};
+#include "ao-elf.h"
#define AO_BOOT_APPLICATION_BASE 0x08001000
-extern struct sym ao_symbols[];
+extern struct ao_sym ao_symbols[];
extern int ao_num_symbols;
extern int ao_num_required_symbols;
void
ao_self_block_write(struct cc_usb *cc, uint32_t address, uint8_t block[256]);
-struct hex_image *
-ao_self_read(struct cc_usb *cc, uint32_t address, uint32_t length);
-
-int
-ao_self_write(struct cc_usb *cc, struct hex_image *image);
-
-extern int ao_self_verbose;
-
#endif /* _AO_STMLOAD_H_ */
telem.mega_data.height);
break;
+ case AO_TELEMETRY_METRUM_SENSOR:
+ printf ("state %1d accel %5d pres %9d temp %6.2f acceleration %6.2f speed %6.2f height %5d v_batt %5d sense_a %5d sense_m %5d\n",
+ telem.metrum_sensor.state,
+ telem.metrum_sensor.accel,
+ telem.metrum_sensor.pres,
+ telem.metrum_sensor.temp / 100.0,
+ telem.metrum_sensor.acceleration / 16.0,
+ telem.metrum_sensor.speed / 16.0,
+ telem.metrum_sensor.height,
+ telem.metrum_sensor.v_batt,
+ telem.metrum_sensor.sense_a,
+ telem.metrum_sensor.sense_m);
+ break;
+ case AO_TELEMETRY_METRUM_DATA:
+ printf ("ground_pres %9d ground_accel %5d accel_plus %5d accel_minus %5d\n",
+ telem.metrum_data.ground_pres,
+ telem.metrum_data.ground_accel,
+ telem.metrum_data.accel_plus_g,
+ telem.metrum_data.accel_minus_g);
+ break;
+ case AO_TELEMETRY_MINI:
+ printf ("state %1d v_batt %5d sense_a %5d sense_m %5d pres %9d temp %6.2f acceleration %6.2f speed %6.2f height %5d ground_pres %9d\n",
+ telem.mini.state,
+ telem.mini.v_batt,
+ telem.mini.sense_a,
+ telem.mini.sense_m,
+ telem.mini.pres,
+ telem.mini.temp / 100.0,
+ telem.mini.acceleration / 16.0,
+ telem.mini.speed / 16.0,
+ telem.mini.height,
+ telem.mini.ground_pres);
+ break;
default:
printf("\n");
}
--- /dev/null
+bin_PROGRAMS=ao-usbload
+
+AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
+AO_STMLOAD_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a
+
+ao_usbload_DEPENDENCIES = $(AO_STMLOAD_LIBS)
+
+ao_usbload_LDADD=$(AO_STMLOAD_LIBS) $(LIBUSB_LIBS) -lelf
+
+ao_usbload_SOURCES=ao-usbload.c ao-usbload.h
+
+man_MANS = ao-usbload.1
--- /dev/null
+.\"
+.\" Copyright © 2009 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; either version 2 of the License, or
+.\" (at your option) any later version.
+.\"
+.\" This program is distributed in the hope that it will be useful, but
+.\" WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+.\" General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License along
+.\" with this program; if not, write to the Free Software Foundation, Inc.,
+.\" 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+.\"
+.\"
+.TH AO-LOAD 1 "ao-usbload" ""
+.SH NAME
+ao-usbload \- flash a program to an ARM-based AltOS device
+.SH SYNOPSIS
+.B "ao-usbload"
+[\-T \fItty-device\fP]
+[\--tty \fItty-device\fP]
+[\-D \fIaltos-device\fP]
+[\--device \fIaltos-device\fP]
+[\--cal \fIradio-calibration\fP]
+[\--serial \fserial-number\fP]
+\fIfile.elf\fP or \fIfile.ihx\fP
+.SH DESCRIPTION
+.I ao-usbload
+loads the specified .elf or .ihx file into the target device flash
+memory via the AltOS boot loader, using either existing serial number
+and radio calibration values or taking either of those from the
+command line.
+.SH OPTIONS
+.TP
+\-T tty-device | --tty tty-device
+This selects which tty device the debugger uses to communicate with
+the target device. The special name 'BITBANG' directs ao-dbg to use
+the cp2103 connection, otherwise this should be a usb serial port
+connected to a suitable cc1111 debug node.
+.TP
+\-D AltOS-device | --device AltOS-device
+Search for a connected device. This requires an argument of one of the
+following forms:
+.IP
+TeleMega:2
+.br
+TeleMega
+.br
+2
+.IP
+Leaving out the product name will cause the tool to select a suitable
+product, leaving out the serial number will cause the tool to match
+one of the available devices.
+.TP
+\-s serial-number | --serial serial-number
+This programs the device serial number into the image. If no serial
+number is specified, then the existing serial number, if any, will be
+read from the device.
+.TP
+\-c radio-calibration | --cal radio-calibration This programs the
+radio calibration value into the image for hardware which doesn't have
+any eeprom storage for this value. If no calibration value is
+specified, an existing calibration value will be used. The value here
+can be computed given the current radio calibration value, the
+measured frequency and the desired frequency:
+.IP
+ cal' = cal * (desired/measured)
+.IP
+The default calibration value is 7119667.
+.SH USAGE
+.I ao-usbload
+reads the specified .elf file into memory, edits the image to
+customize it using the specified serial number and radio calibration
+values. It then connects to the debug dongle and writes the program to
+the target device flash memory.
+.SH AUTHOR
+Keith Packard
--- /dev/null
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <err.h>
+#include <fcntl.h>
+#include <gelf.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sysexits.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <string.h>
+#include <stdbool.h>
+#include "ao-elf.h"
+#include "ccdbg.h"
+#include "cc-usb.h"
+#include "cc.h"
+#include "ao-usbload.h"
+#include "ao-selfload.h"
+#include "ao-verbose.h"
+#include "ao-editaltos.h"
+
+static uint16_t
+get_uint16(struct cc_usb *cc, uint32_t addr)
+{
+ uint16_t result;
+ result = ao_self_get_uint16(cc, addr);
+ printf ("read 0x%08x = 0x%04x\n", addr, result);
+ return result;
+}
+
+/*
+ * Read a 32-bit value from the target device with arbitrary
+ * alignment
+ */
+static uint32_t
+get_uint32(struct cc_usb *cc, uint32_t addr)
+{
+ uint32_t result;
+
+ result = ao_self_get_uint32(cc, addr);
+ printf ("read 0x%08x = 0x%08x\n", addr, result);
+ return result;
+}
+
+/*
+ * Check to see if the target device has been
+ * flashed with a similar firmware image before
+ *
+ * This is done by looking for the same romconfig version,
+ * which should be at the same location as the linker script
+ * places this at 0x100 from the start of the rom section
+ */
+static int
+check_flashed(struct cc_usb *cc)
+{
+ uint16_t romconfig_version = get_uint16(cc, AO_ROMCONFIG_VERSION);
+ uint16_t romconfig_check = get_uint16(cc, AO_ROMCONFIG_CHECK);
+
+ if (romconfig_version != (uint16_t) ~romconfig_check) {
+ fprintf (stderr, "Device has not been flashed before\n");
+ return 0;
+ }
+ return 1;
+}
+
+static const struct option options[] = {
+ { .name = "tty", .has_arg = 1, .val = 'T' },
+ { .name = "device", .has_arg = 1, .val = 'D' },
+ { .name = "raw", .has_arg = 0, .val = 'r' },
+ { .name = "cal", .has_arg = 1, .val = 'c' },
+ { .name = "serial", .has_arg = 1, .val = 's' },
+ { .name = "verbose", .has_arg = 1, .val = 'v' },
+ { 0, 0, 0, 0},
+};
+
+static void usage(char *program)
+{
+ fprintf(stderr, "usage: %s [--raw] [--verbose=<verbose>] [--device=<device>] [-tty=<tty>] [--cal=<radio-cal>] [--serial=<serial>] file.{elf,ihx}\n", program);
+ exit(1);
+}
+
+void
+done(struct cc_usb *cc, int code)
+{
+/* cc_usb_printf(cc, "a\n"); */
+ cc_usb_close(cc);
+ exit (code);
+}
+
+static int
+ends_with(char *whole, char *suffix)
+{
+ int whole_len = strlen(whole);
+ int suffix_len = strlen(suffix);
+
+ if (suffix_len > whole_len)
+ return 0;
+ return strcmp(whole + whole_len - suffix_len, suffix) == 0;
+}
+
+int
+main (int argc, char **argv)
+{
+ char *device = NULL;
+ char *filename;
+ Elf *e;
+ int raw = 0;
+ char *serial_end;
+ unsigned int serial = 0;
+ char *serial_ucs2;
+ int serial_ucs2_len;
+ char serial_int[2];
+ unsigned int s;
+ int i;
+ int string_num;
+ uint32_t cal = 0;
+ char cal_int[4];
+ char *cal_end;
+ int c;
+ int was_flashed = 0;
+ struct ao_hex_image *load;
+ int tries;
+ struct cc_usb *cc = NULL;
+ char *tty = NULL;
+ int success;
+ int verbose = 0;
+ struct ao_sym *file_symbols;
+ int num_file_symbols;
+
+ while ((c = getopt_long(argc, argv, "rT:D:c:s:v:", options, NULL)) != -1) {
+ switch (c) {
+ case 'T':
+ tty = optarg;
+ break;
+ case 'D':
+ device = optarg;
+ break;
+ case 'r':
+ raw = 1;
+ break;
+ case 'c':
+ cal = strtoul(optarg, &cal_end, 10);
+ if (cal_end == optarg || *cal_end != '\0')
+ usage(argv[0]);
+ break;
+ case 's':
+ serial = strtoul(optarg, &serial_end, 10);
+ if (serial_end == optarg || *serial_end != '\0')
+ usage(argv[0]);
+ break;
+ case 'v':
+ verbose++;
+ break;
+ default:
+ usage(argv[0]);
+ break;
+ }
+ }
+
+ ao_verbose = verbose;
+
+ if (verbose > 1)
+ ccdbg_add_debug(CC_DEBUG_BITBANG);
+
+ filename = argv[optind];
+ if (filename == NULL)
+ usage(argv[0]);
+
+ if (ends_with (filename, ".elf")) {
+ load = ao_load_elf(filename, &file_symbols, &num_file_symbols);
+ } else if (ends_with (filename, ".ihx")) {
+ load = ao_hex_load(filename, &file_symbols, &num_file_symbols);
+ } else
+ usage(argv[0]);
+
+ if (!raw) {
+ if (!ao_editaltos_find_symbols(file_symbols, num_file_symbols, ao_symbols, ao_num_symbols)) {
+ fprintf(stderr, "Cannot find required symbols\n");
+ usage(argv[0]);
+ }
+ }
+
+ {
+ int is_loader;
+ int tries;
+
+ for (tries = 0; tries < 3; tries++) {
+ char *this_tty = tty;
+ if (!this_tty)
+ this_tty = cc_usbdevs_find_by_arg(device, "AltosFlash");
+ if (!this_tty)
+ this_tty = cc_usbdevs_find_by_arg(device, "TeleMega");
+ if (!this_tty)
+ this_tty = getenv("ALTOS_TTY");
+ if (!this_tty)
+ this_tty="/dev/ttyACM0";
+
+ cc = cc_usb_open(this_tty);
+
+ if (!cc)
+ exit(1);
+ cc_usb_printf(cc, "v\n");
+ is_loader = 0;
+ for (;;) {
+ char line[256];
+ cc_usb_getline(cc, line, sizeof(line));
+ if (!strncmp(line, "altos-loader", 12))
+ is_loader = 1;
+ if (!strncmp(line, "software-version", 16))
+ break;
+ }
+ if (is_loader)
+ break;
+ printf ("rebooting to loader\n");
+ cc_usb_printf(cc, "X\n");
+ cc_usb_close(cc);
+ sleep(1);
+ cc = NULL;
+ }
+ if (!is_loader) {
+ fprintf(stderr, "Cannot switch to boot loader\n");
+ exit(1);
+ }
+#if 0
+ {
+ uint8_t check[256];
+ int i = 0;
+
+ ao_self_block_read(cc, AO_BOOT_APPLICATION_BASE, check);
+ for (;;) {
+ uint8_t block[256];
+ putchar ('.');
+ if (++i == 40) {
+ putchar('\n');
+ i = 0;
+ }
+ fflush(stdout);
+ ao_self_block_write(cc, AO_BOOT_APPLICATION_BASE, block);
+ ao_self_block_read(cc, AO_BOOT_APPLICATION_BASE, block);
+ if (memcmp(block, check, 256) != 0) {
+ fprintf (stderr, "read differed\n");
+ exit(1);
+ }
+ }
+ }
+#endif
+ }
+
+ if (!raw) {
+ /* Go fetch existing config values
+ * if available
+ */
+ was_flashed = check_flashed(cc);
+
+ if (!serial) {
+ if (!was_flashed) {
+ fprintf (stderr, "Must provide serial number\n");
+ done(cc, 1);
+ }
+ serial = get_uint16(cc, AO_SERIAL_NUMBER);
+ if (!serial || serial == 0xffff) {
+ fprintf (stderr, "Invalid existing serial %d\n", serial);
+ done(cc, 1);
+ }
+ }
+
+ if (!cal && AO_RADIO_CAL && was_flashed) {
+ cal = get_uint32(cc, AO_RADIO_CAL);
+ if (!cal || cal == 0xffffffff) {
+ fprintf (stderr, "Invalid existing rf cal %d\n", cal);
+ done(cc, 1);
+ }
+ }
+
+ if (!ao_editaltos(load, serial, cal))
+ done(cc, 1);
+ }
+
+ /* And flash the resulting image to the device
+ */
+ success = ao_self_write(cc, load);
+
+ if (!success) {
+ fprintf (stderr, "\"%s\": Write failed\n", filename);
+ done(cc, 1);
+ }
+
+ done(cc, 0);
+}
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_STMLOAD_H_
+#define _AO_STMLOAD_H_
+
+#include "ao-elf.h"
+
+#define AO_BOOT_APPLICATION_BASE 0x08001000
+
+extern struct ao_sym ao_symbols[];
+
+extern int ao_num_symbols;
+extern int ao_num_required_symbols;
+
+void
+ao_self_block_read(struct cc_usb *cc, uint32_t address, uint8_t block[256]);
+
+void
+ao_self_block_write(struct cc_usb *cc, uint32_t address, uint8_t block[256]);
+
+#endif /* _AO_STMLOAD_H_ */
ccdbg-debug.h \
ccdbg-flash.c \
ccdbg.h \
- ccdbg-hex.c \
ccdbg-io.c \
ccdbg-manual.c \
ccdbg-memory.c \
cc-convert.c \
cc-dsp.c \
cc-integrate.c \
+ cc-mega.c \
cc-period.c \
cc-process.c \
cc-usb.c \
i0.c \
chbevl.c \
mconf.h \
- cephes.h
+ cephes.h \
+ ao-hex.c \
+ ao-hex.h \
+ ao-editaltos.c \
+ ao-editaltos.h \
+ ao-elf.c \
+ ao-elf.h \
+ ao-selfload.c \
+ ao-selfload.h \
+ ao-verbose.c \
+ ao-verbose.h
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include "ao-editaltos.h"
+
+struct ao_sym ao_symbols[] = {
+
+ { 0, 0, "ao_romconfig_version", 1 },
+ { 0, 0, "ao_romconfig_check", 1 },
+ { 0, 0, "ao_serial_number", 1 },
+ { 0, 0, "ao_radio_cal", 0 },
+ { 0, 0, "ao_usb_descriptors", 0 },
+};
+
+#define NUM_SYMBOLS 5
+
+int ao_num_symbols = NUM_SYMBOLS;
+
+/*
+ * Edit the to-be-written memory block
+ */
+static bool
+rewrite(struct ao_hex_image *load, unsigned address, uint8_t *data, int length)
+{
+ int i;
+
+ if (address < load->address || load->address + load->length < address + length)
+ return false;
+
+ printf("rewrite %04x:", address);
+ for (i = 0; i < length; i++)
+ printf (" %02x", load->data[address - load->address + i]);
+ printf(" ->");
+ for (i = 0; i < length; i++)
+ printf (" %02x", data[i]);
+ printf("\n");
+ memcpy(load->data + address - load->address, data, length);
+ return true;
+}
+
+/*
+ * Find the symbols needed to correctly load the program
+ */
+
+bool
+ao_editaltos_find_symbols(struct ao_sym *file_symbols, int num_file_symbols,
+ struct ao_sym *symbols, int num_symbols)
+{
+ int f, s;
+
+ for (f = 0; f < num_file_symbols; f++) {
+ for (s = 0; s < num_symbols; s++) {
+ if (strcmp(symbols[s].name, file_symbols[f].name) == 0) {
+ symbols[s].addr = file_symbols[f].addr;
+ symbols[s].found = true;
+ }
+ }
+ }
+ for (s = 0; s < num_symbols; s++)
+ if (!symbols[s].found && symbols[s].required)
+ return false;
+ return true;
+}
+
+bool
+ao_editaltos(struct ao_hex_image *image,
+ uint16_t serial,
+ uint32_t cal)
+{
+ uint8_t *serial_ucs2;
+ int serial_ucs2_len;
+ uint8_t serial_int[2];
+ unsigned int s;
+ int i;
+ int string_num;
+ uint8_t cal_int[4];
+
+ /* Write the config values into the flash image
+ */
+
+ serial_int[0] = serial & 0xff;
+ serial_int[1] = (serial >> 8) & 0xff;
+
+ if (!rewrite(image, AO_SERIAL_NUMBER, serial_int, sizeof (serial_int))) {
+ fprintf(stderr, "Cannot rewrite serial integer at %08x\n",
+ AO_SERIAL_NUMBER);
+ return false;
+ }
+
+ if (AO_USB_DESCRIPTORS) {
+ uint32_t usb_descriptors = AO_USB_DESCRIPTORS - image->address;
+ string_num = 0;
+
+ while (image->data[usb_descriptors] != 0 && usb_descriptors < image->length) {
+ if (image->data[usb_descriptors+1] == AO_USB_DESC_STRING) {
+ ++string_num;
+ if (string_num == 4)
+ break;
+ }
+ usb_descriptors += image->data[usb_descriptors];
+ }
+ if (usb_descriptors >= image->length || image->data[usb_descriptors] == 0 ) {
+ fprintf(stderr, "Cannot rewrite serial string at %08x\n", AO_USB_DESCRIPTORS);
+ return false;
+ }
+
+ serial_ucs2_len = image->data[usb_descriptors] - 2;
+ serial_ucs2 = malloc(serial_ucs2_len);
+ if (!serial_ucs2) {
+ fprintf(stderr, "Malloc(%d) failed\n", serial_ucs2_len);
+ return false;
+ }
+ s = serial;
+ for (i = serial_ucs2_len / 2; i; i--) {
+ serial_ucs2[i * 2 - 1] = 0;
+ serial_ucs2[i * 2 - 2] = (s % 10) + '0';
+ s /= 10;
+ }
+ if (!rewrite(image, usb_descriptors + 2 + image->address, serial_ucs2, serial_ucs2_len)) {
+ fprintf (stderr, "Cannot rewrite USB descriptor at %08x\n", AO_USB_DESCRIPTORS);
+ return false;
+ }
+ }
+
+ if (cal && AO_RADIO_CAL) {
+ cal_int[0] = cal & 0xff;
+ cal_int[1] = (cal >> 8) & 0xff;
+ cal_int[2] = (cal >> 16) & 0xff;
+ cal_int[3] = (cal >> 24) & 0xff;
+
+ if (!rewrite(image, AO_RADIO_CAL, cal_int, sizeof (cal_int))) {
+ fprintf(stderr, "Cannot rewrite radio calibration at %08x\n", AO_RADIO_CAL);
+ return false;
+ }
+ }
+ return true;
+}
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_EDITALTOS_H_
+#define _AO_EDITALTOS_H_
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "ao-hex.h"
+
+extern struct ao_sym ao_symbols[];
+extern int ao_num_symbols;
+
+#define AO_USB_DESC_STRING 3
+
+#define AO_ROMCONFIG_VERSION (ao_symbols[0].addr)
+#define AO_ROMCONFIG_CHECK (ao_symbols[1].addr)
+#define AO_SERIAL_NUMBER (ao_symbols[2].addr)
+#define AO_RADIO_CAL (ao_symbols[3].addr)
+#define AO_USB_DESCRIPTORS (ao_symbols[4].addr)
+
+struct ao_editaltos_funcs {
+ uint16_t (*get_uint16)(void *closure, uint32_t addr);
+ uint32_t (*get_uint32)(void *closure, uint32_t addr);
+};
+
+bool
+ao_editaltos_find_symbols(struct ao_sym *file_symbols, int num_file_symbols,
+ struct ao_sym *symbols, int num_symbols);
+
+bool
+ao_editaltos(struct ao_hex_image *image,
+ uint16_t serial,
+ uint32_t radio_cal);
+
+#endif /* _AO_EDITALTOS_H_ */
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <err.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "ao-elf.h"
+#include "ao-hex.h"
+#include "ao-verbose.h"
+
+/*
+ * Look through the Elf file for symbols that can be adjusted before
+ * the image is written to the device
+ */
+static struct ao_sym *
+load_symbols (Elf *e, int *num_symbolsp)
+{
+ Elf_Scn *scn;
+ Elf_Data *symbol_data = NULL;
+ GElf_Shdr shdr;
+ GElf_Sym sym;
+ int i, symbol_count;
+ char *symbol_name;
+ size_t shstrndx;
+ struct ao_sym *symbols = NULL;
+ struct ao_sym *symbol;
+ int num_symbols = 0;
+ int size_symbols = 0;
+
+ if (elf_getshdrstrndx(e, &shstrndx) < 0)
+ return false;
+
+ /*
+ * Find the symbols
+ */
+
+ scn = NULL;
+ while ((scn = elf_nextscn(e, scn)) != NULL) {
+
+ if (gelf_getshdr(scn, &shdr) != &shdr)
+ return false;
+
+ if (shdr.sh_type == SHT_SYMTAB) {
+ symbol_data = elf_getdata(scn, NULL);
+ symbol_count = shdr.sh_size / shdr.sh_entsize;
+ break;
+ }
+ }
+
+ if (!symbol_data)
+ return NULL;
+
+ for (i = 0; i < symbol_count; i++) {
+ gelf_getsym(symbol_data, i, &sym);
+
+ symbol_name = elf_strptr(e, shdr.sh_link, sym.st_name);
+ if (!symbol_name[0])
+ continue;
+
+ if (num_symbols == size_symbols) {
+ struct ao_sym *new_symbols;
+ int new_size;
+
+ if (!size_symbols)
+ new_size = 16;
+ else
+ new_size = size_symbols * 2;
+ new_symbols = realloc(symbols, new_size * sizeof (struct ao_sym));
+ if (!new_symbols)
+ goto bail;
+
+ symbols = new_symbols;
+ size_symbols = new_size;
+ }
+ symbol = &symbols[num_symbols];
+ memset(symbol, 0, sizeof (struct ao_sym));
+ symbol->name = strdup(symbol_name);
+ if (!symbol->name)
+ goto bail;
+ symbol->addr = sym.st_value;
+ ao_printf(AO_VERBOSE_EXE, "Add symbol %s: %08x\n", symbol->name, symbol->addr);
+ num_symbols++;
+ }
+ *num_symbolsp = num_symbols;
+ return symbols;
+bail:
+ for (i = 0; i < num_symbols; i++)
+ free(symbols[i].name);
+ free(symbols);
+ return NULL;
+}
+
+static uint32_t
+round4(uint32_t a) {
+ return (a + 3) & ~3;
+}
+
+static struct ao_hex_image *
+new_load (uint32_t addr, uint32_t len)
+{
+ struct ao_hex_image *new;
+
+ len = round4(len);
+ new = calloc (1, sizeof (struct ao_hex_image) + len);
+ if (!new)
+ abort();
+
+ new->address = addr;
+ new->length = len;
+ return new;
+}
+
+static void
+load_paste(struct ao_hex_image *into, struct ao_hex_image *from)
+{
+ if (from->address < into->address || into->address + into->length < from->address + from->length)
+ abort();
+
+ memcpy(into->data + from->address - into->address, from->data, from->length);
+}
+
+/*
+ * Make a new load structure large enough to hold the old one and
+ * the new data
+ */
+static struct ao_hex_image *
+expand_load(struct ao_hex_image *from, uint32_t address, uint32_t length)
+{
+ struct ao_hex_image *new;
+
+ if (from) {
+ uint32_t from_last = from->address + from->length;
+ uint32_t last = address + length;
+
+ if (address > from->address)
+ address = from->address;
+ if (last < from_last)
+ last = from_last;
+
+ length = last - address;
+
+ if (address == from->address && length == from->length)
+ return from;
+ }
+ new = new_load(address, length);
+ if (from) {
+ load_paste(new, from);
+ free (from);
+ }
+ return new;
+}
+
+/*
+ * Create a new load structure with data from the existing one
+ * and the new data
+ */
+static struct ao_hex_image *
+load_write(struct ao_hex_image *from, uint32_t address, uint32_t length, void *data)
+{
+ struct ao_hex_image *new;
+
+ new = expand_load(from, address, length);
+ memcpy(new->data + address - new->address, data, length);
+ return new;
+}
+
+/*
+ * Construct a large in-memory block for all
+ * of the loaded sections of the program
+ */
+static struct ao_hex_image *
+get_load(Elf *e)
+{
+ Elf_Scn *scn;
+ size_t shstrndx;
+ GElf_Shdr shdr;
+ Elf_Data *data;
+ size_t nphdr;
+ size_t p;
+ GElf_Phdr phdr;
+ GElf_Addr sh_paddr;
+ struct ao_hex_image *load = NULL;
+#if 0
+ char *section_name;
+#endif
+ size_t nshdr;
+ size_t s;
+
+ if (elf_getshdrstrndx(e, &shstrndx) < 0)
+ return 0;
+
+ if (elf_getphdrnum(e, &nphdr) < 0)
+ return 0;
+
+ if (elf_getshdrnum(e, &nshdr) < 0)
+ return 0;
+
+ /*
+ * As far as I can tell, all of the phdr sections should
+ * be flashed to memory
+ */
+ for (p = 0; p < nphdr; p++) {
+
+ /* Find this phdr */
+ gelf_getphdr(e, p, &phdr);
+
+ if (phdr.p_type != PT_LOAD)
+ continue;
+
+ /* Get the associated file section */
+
+#if 0
+ fprintf (stderr, "offset %08x vaddr %08x paddr %08x filesz %08x memsz %08x\n",
+ (uint32_t) phdr.p_offset,
+ (uint32_t) phdr.p_vaddr,
+ (uint32_t) phdr.p_paddr,
+ (uint32_t) phdr.p_filesz,
+ (uint32_t) phdr.p_memsz);
+#endif
+
+ for (s = 0; s < nshdr; s++) {
+ scn = elf_getscn(e, s);
+
+ if (!scn) {
+ fprintf (stderr, "getscn failed\n");
+ abort();
+ }
+ if (gelf_getshdr(scn, &shdr) != &shdr) {
+ fprintf (stderr, "gelf_getshdr failed\n");
+ abort();
+ }
+
+#if 0
+ section_name = elf_strptr(e, shstrndx, shdr.sh_name);
+#endif
+
+ if (phdr.p_offset <= shdr.sh_offset && shdr.sh_offset < phdr.p_offset + phdr.p_filesz) {
+
+ if (shdr.sh_size == 0)
+ continue;
+
+ sh_paddr = phdr.p_paddr + shdr.sh_offset - phdr.p_offset;
+
+#if 0
+ fprintf (stderr, "\tsize %08x rom %08x exec %08x %s\n",
+ (uint32_t) shdr.sh_size,
+ (uint32_t) sh_paddr,
+ (uint32_t) shdr.sh_addr,
+ section_name);
+#endif
+
+ data = elf_getdata(scn, NULL);
+
+ /* Write the section data into the memory block */
+ load = load_write(load, sh_paddr, shdr.sh_size, data->d_buf);
+ }
+ }
+ }
+ return load;
+}
+
+/*
+ * Open the specified ELF file and
+ * check for the symbols we need
+ */
+
+struct ao_hex_image *
+ao_load_elf(char *name, struct ao_sym **symbols, int *num_symbols)
+{
+ int fd;
+ Elf *e;
+ size_t shstrndx;
+ struct ao_hex_image *image;
+
+ if (elf_version(EV_CURRENT) == EV_NONE)
+ return NULL;
+
+ fd = open(name, O_RDONLY, 0);
+
+ if (fd < 0)
+ return NULL;
+
+ e = elf_begin(fd, ELF_C_READ, NULL);
+
+ if (!e)
+ return NULL;
+
+ if (elf_kind(e) != ELF_K_ELF)
+ return NULL;
+
+ if (elf_getshdrstrndx(e, &shstrndx) != 0)
+ return NULL;
+
+ if (symbols)
+ *symbols = load_symbols(e, num_symbols);
+
+ image = get_load(e);
+ if (!image) {
+ fprintf (stderr, "Cannot create memory image from file\n");
+ return NULL;
+ }
+
+ return image;
+}
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_ELF_H_
+#define _AO_ELF_H_
+
+#include <stdbool.h>
+#include <gelf.h>
+#include "ao-hex.h"
+
+struct ao_hex_image *
+ao_load_elf(char *name, struct ao_sym **symbols, int *num_symbols);
+
+#endif /* _AO_ELF_H_ */
--- /dev/null
+/*
+ * Copyright © 2008 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <stdarg.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include "ao-hex.h"
+#include "ao-verbose.h"
+
+struct ao_hex_input {
+ FILE *file;
+ int line;
+ char *name;
+};
+
+enum ao_hex_read_state {
+ read_marker,
+ read_length,
+ read_address,
+ read_type,
+ read_data,
+ read_checksum,
+ read_newline,
+ read_white,
+ read_done,
+};
+
+
+static void
+ao_hex_error(struct ao_hex_input *input, char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ fprintf(stderr, "Hex error %s:%d: ", input->name, input->line);
+ vfprintf(stderr, format, ap);
+ fprintf(stderr, "\n");
+ va_end(ap);
+}
+
+static void
+ao_hex_free(struct ao_hex_record *record)
+{
+ if (!record) return;
+ free(record);
+}
+
+static struct ao_hex_record *
+ao_hex_alloc(uint8_t length)
+{
+ struct ao_hex_record *record;
+
+ record = calloc(1, sizeof(struct ao_hex_record) + length);
+ record->length = length;
+ return record;
+}
+
+static int
+ishex(char c)
+{
+ return isdigit(c) || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F');
+}
+
+static int
+fromhex(char c)
+{
+ if (isdigit(c))
+ return c - '0';
+ if ('a' <= c && c <= 'f')
+ return c - 'a' + 10;
+ if ('A' <= c && c <= 'F')
+ return c - 'A' + 10;
+ abort();
+ return 0;
+}
+
+static uint8_t
+ao_hex_checksum(struct ao_hex_record *record)
+{
+ uint8_t checksum = 0;
+ int i;
+
+ checksum += record->length;
+ checksum += record->address >> 8;
+ checksum += record->address & 0xff;
+ checksum += record->type;
+ for (i = 0; i < record->length; i++)
+ checksum += record->data[i];
+ return -checksum;
+}
+
+static struct ao_hex_record *
+ao_hex_read_record(struct ao_hex_input *input)
+{
+ struct ao_hex_record *record = NULL;
+ enum ao_hex_read_state state = read_marker;
+ char c;
+ int nhexbytes;
+ uint32_t hex;
+ uint32_t ndata;
+ uint8_t checksum;
+
+ while (state != read_done) {
+ c = getc(input->file);
+ if (c == EOF && state != read_white && state != read_marker) {
+ ao_hex_error(input, "Unexpected EOF");
+ goto bail;
+ }
+ if (c == ' ')
+ continue;
+ if (c == '\n')
+ input->line++;
+ switch (state) {
+ case read_marker:
+ if (c == EOF)
+ return NULL;
+ if (c != ':') {
+ ao_hex_error(input, "Missing ':'");
+ goto bail;
+ }
+ state = read_length;
+ nhexbytes = 2;
+ hex = 0;
+ break;
+ case read_length:
+ case read_address:
+ case read_type:
+ case read_data:
+ case read_checksum:
+ if (!ishex(c)) {
+ ao_hex_error(input, "Non-hex char '%c'",
+ c);
+ goto bail;
+ }
+ hex = hex << 4 | fromhex(c);
+ --nhexbytes;
+ if (nhexbytes != 0)
+ break;
+
+ switch (state) {
+ case read_length:
+ record = ao_hex_alloc(hex);
+ if (!record) {
+ ao_hex_error(input, "Out of memory");
+ goto bail;
+ }
+ state = read_address;
+ nhexbytes = 4;
+ break;
+ case read_address:
+ record->address = hex;
+ state = read_type;
+ nhexbytes = 2;
+ break;
+ case read_type:
+ record->type = hex;
+ state = read_data;
+ nhexbytes = 2;
+ ndata = 0;
+ break;
+ case read_data:
+ record->data[ndata] = hex;
+ ndata++;
+ nhexbytes = 2;
+ break;
+ case read_checksum:
+ record->checksum = hex;
+ state = read_newline;
+ break;
+ default:
+ break;
+ }
+ if (state == read_data)
+ if (ndata == record->length) {
+ nhexbytes = 2;
+ state = read_checksum;
+ }
+ hex = 0;
+ break;
+ case read_newline:
+ if (c != '\n' && c != '\r') {
+ ao_hex_error(input, "Missing newline");
+ goto bail;
+ }
+ state = read_white;
+ break;
+ case read_white:
+ if (!isspace(c)) {
+ if (c == '\n')
+ input->line--;
+ if (c != EOF)
+ ungetc(c, input->file);
+ state = read_done;
+ }
+ break;
+ case read_done:
+ break;
+ }
+ }
+ checksum = ao_hex_checksum(record);
+ if (checksum != record->checksum) {
+ ao_hex_error(input, "Invalid checksum (read 0x%02x computed 0x%02x)\n",
+ record->checksum, checksum);
+ goto bail;
+ }
+ return record;
+
+bail:
+ ao_hex_free(record);
+ return NULL;
+}
+
+void
+ao_hex_file_free(struct ao_hex_file *hex)
+{
+ int i;
+
+ if (!hex)
+ return;
+ for (i = 0; i < hex->nrecord; i++)
+ ao_hex_free(hex->records[i]);
+ free(hex);
+}
+
+struct ao_hex_file *
+ao_hex_file_read(FILE *file, char *name)
+{
+ struct ao_hex_input input;
+ struct ao_hex_file *hex = NULL, *newhex;
+ struct ao_hex_record *record;
+ int srecord = 1;
+ int done = 0;
+
+ hex = calloc(sizeof (struct ao_hex_file) + sizeof (struct ao_hex_record *), 1);
+ if (!hex)
+ return NULL;
+ input.name = name;
+ input.line = 1;
+ input.file = file;
+ while (!done) {
+ record = ao_hex_read_record(&input);
+ if (!record) {
+ if (feof(input.file)) {
+ done = 1;
+ break;
+ } else
+ goto bail;
+ }
+ if (hex->nrecord == srecord) {
+ srecord *= 2;
+ newhex = realloc(hex,
+ sizeof (struct ao_hex_file) +
+ srecord * sizeof (struct ao_hex_record *));
+ if (!newhex)
+ goto bail;
+ hex = newhex;
+ }
+ hex->records[hex->nrecord++] = record;
+ }
+ return hex;
+
+bail:
+ ao_hex_file_free(hex);
+ return NULL;
+}
+
+static struct ao_sym *
+load_symbols(struct ao_hex_file *hex,
+ int *num_symbolsp)
+{
+ uint32_t extended_addr;
+ uint32_t addr;
+ int i;
+ struct ao_hex_record *record;
+ struct ao_sym *symbols = NULL;
+ struct ao_sym *symbol;
+ int num_symbols = 0;
+ int size_symbols = 0;
+
+ extended_addr = 0;
+ for (i = 0; i < hex->nrecord; i++) {
+ record = hex->records[i];
+ switch (record->type) {
+ case AO_HEX_RECORD_NORMAL:
+ addr = extended_addr + record->address;
+ break;
+ case AO_HEX_RECORD_EOF:
+ break;
+ case AO_HEX_RECORD_EXTENDED_ADDRESS_4:
+ if (record->length != 2)
+ goto bail;
+ extended_addr = ((record->data[0] << 8) | record->data[1]) << 4;
+ break;
+ case AO_HEX_RECORD_EXTENDED_ADDRESS_8:
+ if (record->length != 2)
+ goto bail;
+ extended_addr = (record->data[0] << 24) | (record->data[1] << 16);
+ break;
+ case AO_HEX_RECORD_SYMBOL:
+ addr = extended_addr + record->address;
+ if (num_symbols == size_symbols) {
+ struct ao_sym *new_symbols;
+ int new_size;
+
+ if (!size_symbols)
+ new_size = 16;
+ else
+ new_size = size_symbols * 2;
+ new_symbols = realloc(symbols, new_size * sizeof (struct ao_sym));
+ if (!new_symbols)
+ goto bail;
+
+ symbols = new_symbols;
+ size_symbols = new_size;
+ }
+ symbol = &symbols[num_symbols];
+ memset(symbol, 0, sizeof (struct ao_sym));
+ symbol->name = calloc(record->length + 1, 1);
+ if (!symbol->name)
+ goto bail;
+ memcpy(symbol->name, record->data, record->length);
+ symbol->addr = addr;
+ ao_printf(AO_VERBOSE_EXE, "Add symbol %s: %08x\n", symbol->name, symbol->addr);
+ num_symbols++;
+ break;
+ }
+ }
+ *num_symbolsp = num_symbols;
+ return symbols;
+bail:
+ for (i = 0; i < num_symbols; i++)
+ free(symbols[i].name);
+ free(symbols);
+ return NULL;
+}
+
+static void
+ao_hex_record_set_checksum(struct ao_hex_record *record)
+{
+ uint8_t cksum = 0;
+ int i;
+
+ cksum += record->length;
+ cksum += record->address >> 8;
+ cksum += record->address;
+ cksum += record->type;
+ for (i = 0; i < record->length; i++)
+ cksum += record->data[i];
+
+ record->checksum = -cksum;
+}
+
+struct ao_hex_image *
+ao_hex_image_create(struct ao_hex_file *hex)
+{
+ struct ao_hex_image *image;
+ struct ao_hex_record *record;
+ int i;
+ uint32_t addr;
+ uint32_t base, bound;
+ uint32_t offset;
+ uint32_t extended_addr;
+
+ int length;
+
+ /* Find the address bounds of the file
+ */
+ base = 0xffffffff;
+ bound = 0x0;
+ extended_addr = 0;
+ for (i = 0; i < hex->nrecord; i++) {
+ uint32_t r_bound;
+ record = hex->records[i];
+ switch (record->type) {
+ case AO_HEX_RECORD_NORMAL:
+ addr = extended_addr + record->address;
+ r_bound = addr + record->length;
+ if (addr < base)
+ base = addr;
+ if (r_bound > bound)
+ bound = r_bound;
+ break;
+ case AO_HEX_RECORD_EOF:
+ break;
+ case AO_HEX_RECORD_EXTENDED_ADDRESS_4:
+ if (record->length != 2)
+ return NULL;
+ extended_addr = ((record->data[0] << 8) | record->data[1]) << 4;
+ break;
+ case AO_HEX_RECORD_EXTENDED_ADDRESS_8:
+ if (record->length != 2)
+ return NULL;
+ extended_addr = (record->data[0] << 24) | (record->data[1] << 16);
+ break;
+ case AO_HEX_RECORD_SYMBOL:
+ break;
+ }
+ }
+ length = bound - base;
+ image = calloc(sizeof(struct ao_hex_image) + length, 1);
+ if (!image)
+ return NULL;
+ image->address = base;
+ image->length = length;
+ memset(image->data, 0xff, length);
+ extended_addr = 0;
+ for (i = 0; i < hex->nrecord; i++) {
+ record = hex->records[i];
+ switch (record->type) {
+ case AO_HEX_RECORD_NORMAL:
+ addr = extended_addr + record->address;
+ offset = addr - base;
+ memcpy(image->data + offset, record->data, record->length);
+ break;
+ case AO_HEX_RECORD_EOF:
+ break;
+ case AO_HEX_RECORD_EXTENDED_ADDRESS_4:
+ extended_addr = ((record->data[0] << 8) | record->data[1]) << 4;
+ break;
+ case AO_HEX_RECORD_EXTENDED_ADDRESS_8:
+ extended_addr = (record->data[0] << 24) | (record->data[1] << 16);
+ break;
+ case AO_HEX_RECORD_SYMBOL:
+ break;
+ }
+ }
+ return image;
+}
+
+void
+ao_hex_image_free(struct ao_hex_image *image)
+{
+ free(image);
+}
+
+int
+ao_hex_image_equal(struct ao_hex_image *a, struct ao_hex_image *b)
+{
+ if (a->length != b->length)
+ return 0;
+ if (memcmp(a->data, b->data, a->length) != 0)
+ return 0;
+ return 1;
+}
+
+struct ao_hex_image *
+ao_hex_load(char *filename, struct ao_sym **symbols, int *num_symbolsp)
+{
+ FILE *file;
+ struct ao_hex_file *hex_file;
+ struct ao_hex_image *hex_image;
+
+ file = fopen (filename, "r");
+ if (!file)
+ return NULL;
+
+ hex_file = ao_hex_file_read(file, filename);
+ fclose(file);
+ if (!hex_file)
+ return NULL;
+ hex_image = ao_hex_image_create(hex_file);
+ if (!hex_image)
+ return NULL;
+
+ if (symbols)
+ *symbols = load_symbols(hex_file, num_symbolsp);
+
+ ao_hex_file_free(hex_file);
+ return hex_image;
+}
+
+#define BYTES_PER_RECORD 32
+
+static struct ao_hex_file *
+ao_hex_file_create(struct ao_hex_image *image, struct ao_sym *symbols, int num_symbols)
+{
+ /* split data into n-byte-sized chunks */
+ uint32_t data_records = (image->length + BYTES_PER_RECORD-1) / BYTES_PER_RECORD;
+ /* extended address and data for each block, EOF, address and data for each symbol */
+ uint32_t total_records = data_records * 2 + 1 + num_symbols * 2;
+ uint32_t offset;
+ uint32_t address;
+ uint32_t length;
+ char *name;
+ struct ao_hex_file *hex_file;
+ int nrecord = 0;
+ int s;
+ struct ao_hex_record *record;
+
+ hex_file = calloc(sizeof (struct ao_hex_file) + sizeof (struct ao_hex_record *) * total_records, 1);
+ if (!hex_file)
+ return NULL;
+
+ /* Add the data
+ */
+ for (offset = 0; offset < image->length; offset += BYTES_PER_RECORD) {
+ uint32_t address = image->address + offset;
+ uint32_t length = image->length - offset;
+
+ if (length > BYTES_PER_RECORD)
+ length = BYTES_PER_RECORD;
+
+ record = calloc(sizeof (struct ao_hex_record) + 2, 1);
+ record->type = AO_HEX_RECORD_EXTENDED_ADDRESS_8;
+ record->address = 0;
+ record->length = 2;
+ record->data[0] = address >> 24;
+ record->data[1] = address >> 16;
+ ao_hex_record_set_checksum(record);
+
+ hex_file->records[nrecord++] = record;
+
+ record = calloc(sizeof (struct ao_hex_record) + length, 1);
+ record->type = AO_HEX_RECORD_NORMAL;
+ record->address = address;
+ record->length = length;
+ memcpy(record->data, image->data + offset, length);
+ ao_hex_record_set_checksum(record);
+
+ hex_file->records[nrecord++] = record;
+ }
+
+ /* Stick an EOF after the data
+ */
+ record = calloc(sizeof (struct ao_hex_record), 1);
+ record->type = AO_HEX_RECORD_EOF;
+ record->address = 0;
+ record->length = 0;
+ record->data[0] = 0;
+ record->data[1] = 0;
+ ao_hex_record_set_checksum(record);
+
+ hex_file->records[nrecord++] = record;
+
+ /* Add the symbols
+ */
+
+ for (s = 0; s < num_symbols; s++) {
+
+ name = symbols[s].name;
+ address = symbols[s].addr;
+ length = strlen (name);
+
+ record = calloc(sizeof (struct ao_hex_record) + 2, 1);
+ record->type = AO_HEX_RECORD_EXTENDED_ADDRESS_8;
+ record->address = 0;
+ record->length = 2;
+ record->data[0] = address >> 24;
+ record->data[1] = address >> 16;
+ ao_hex_record_set_checksum(record);
+
+ hex_file->records[nrecord++] = record;
+
+ record = calloc(sizeof (struct ao_hex_record) + length, 1);
+ record->type = AO_HEX_RECORD_SYMBOL;
+ record->address = address;
+ record->length = length;
+ memcpy(record->data, name, length);
+ ao_hex_record_set_checksum(record);
+
+ hex_file->records[nrecord++] = record;
+ }
+
+ hex_file->nrecord = nrecord;
+ return hex_file;
+}
+
+static bool
+ao_hex_write_record(FILE *file, struct ao_hex_record *record)
+{
+ int i;
+
+ fputc(':', file);
+ fprintf(file, "%02x", record->length);
+ fprintf(file, "%04x", record->address);
+ fprintf(file, "%02x", record->type);
+ for (i = 0; i < record->length; i++)
+ fprintf(file, "%02x", record->data[i]);
+ fprintf(file, "%02x", record->checksum);
+ fputc('\n', file);
+ return true;
+}
+
+bool
+ao_hex_save(FILE *file, struct ao_hex_image *image,
+ struct ao_sym *symbols, int num_symbols)
+{
+ struct ao_hex_file *hex_file;
+ int i;
+ bool ret = false;
+
+ hex_file = ao_hex_file_create(image, symbols, num_symbols);
+ if (!hex_file)
+ goto create_failed;
+
+ for (i = 0; i < hex_file->nrecord; i++) {
+ if (!ao_hex_write_record(file, hex_file->records[i]))
+ goto write_failed;
+ }
+ ret = true;
+
+ if (fflush(file) != 0)
+ ret = false;
+write_failed:
+ ao_hex_file_free(hex_file);
+create_failed:
+ return ret;
+}
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_HEX_H_
+#define _AO_HEX_H_
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdio.h>
+
+#define AO_HEX_RECORD_NORMAL 0x00
+#define AO_HEX_RECORD_EOF 0x01
+#define AO_HEX_RECORD_EXTENDED_ADDRESS_4 0x02
+#define AO_HEX_RECORD_EXTENDED_ADDRESS_8 0x04
+#define AO_HEX_RECORD_SYMBOL 0xfe
+
+/* Intel hex file format data
+ */
+struct ao_hex_record {
+ uint8_t length;
+ uint16_t address;
+ uint8_t type;
+ uint8_t checksum;
+ uint8_t data[0];
+};
+
+struct ao_hex_file {
+ int nrecord;
+ struct ao_hex_record *records[0];
+};
+
+struct ao_hex_image {
+ uint32_t address;
+ uint32_t length;
+ uint8_t data[0];
+};
+
+struct ao_sym {
+ unsigned addr;
+ unsigned default_addr;
+ char *name;
+ bool required;
+ bool found;
+};
+
+struct ao_hex_file *
+ao_hex_file_read(FILE *file, char *name);
+
+void
+ao_hex_file_free(struct ao_hex_file *hex);
+
+struct ao_hex_image *
+ao_hex_image_create(struct ao_hex_file *hex);
+
+void
+ao_hex_image_free(struct ao_hex_image *image);
+
+struct ao_hex_image *
+ao_hex_load(char *filename, struct ao_sym **symbols, int *num_symbols);
+
+int
+ao_hex_image_equal(struct ao_hex_image *a, struct ao_hex_image *b);
+
+bool
+ao_hex_save(FILE *file, struct ao_hex_image *image,
+ struct ao_sym *symbols, int num_symbols);
+
+#endif /* _AO_HEX_H_ */
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sysexits.h>
+#include <unistd.h>
+#include <string.h>
+#include "ao-hex.h"
+#include "ao-selfload.h"
+#include "ao-verbose.h"
+
+#define TRACE(...) ao_printf(AO_VERBOSE_SELF, __VA_ARGS__)
+
+static void
+ao_self_block_read(struct cc_usb *cc, uint32_t address, uint8_t block[256])
+{
+ int byte;
+ cc_usb_sync(cc);
+ cc_usb_printf(cc, "R %x\n", address);
+ for (byte = 0; byte < 0x100; byte++) {
+ block[byte] = cc_usb_getchar(cc);
+ }
+ TRACE ("\nread %08x\n", address);
+ for (byte = 0; byte < 0x100; byte++) {
+ TRACE (" %02x", block[byte]);
+ if ((byte & 0xf) == 0xf)
+ TRACE ("\n");
+ }
+}
+
+static void
+ao_self_block_write(struct cc_usb *cc, uint32_t address, uint8_t block[256])
+{
+ int byte;
+ cc_usb_sync(cc);
+ cc_usb_printf(cc, "W %x\n", address);
+ TRACE ("write %08x\n", address);
+ for (byte = 0; byte < 0x100; byte++) {
+ TRACE (" %02x", block[byte]);
+ if ((byte & 0xf) == 0xf)
+ TRACE ("\n");
+ }
+ for (byte = 0; byte < 0x100; byte++) {
+ cc_usb_printf(cc, "%c", block[byte]);
+ }
+}
+
+struct ao_hex_image *
+ao_self_read(struct cc_usb *cc, uint32_t address, uint32_t length)
+{
+ struct ao_hex_image *image;
+ int pages;
+ int page;
+ uint32_t base = address & ~0xff;
+ uint32_t bound = (address + length + 0xff) & ~0xff;
+
+ image = calloc(sizeof (struct ao_hex_image) + (bound - base), 1);
+ image->address = base;
+ image->length = bound - base;
+ pages = image->length / 0x100;
+ for (page = 0; page < pages; page++)
+ ao_self_block_read(cc, image->address + page * 0x100, image->data + page * 0x100);
+ return image;
+}
+
+bool
+ao_self_write(struct cc_usb *cc, struct ao_hex_image *image)
+{
+ uint8_t block[256];
+ uint8_t check[256];
+ uint32_t base, bound, length, address;
+ uint32_t pages;
+ uint32_t page;
+
+ base = image->address & ~0xff;
+ bound = (image->address + image->length + 0xff) & ~0xff;
+
+ address = base;
+ length = bound - base;
+
+ pages = length / 0x100;
+ printf ("Write %08x %d pages: ", address, length/0x100); fflush(stdout);
+ for (page = 0; page < pages; page++) {
+ uint32_t start, stop;
+ address = base + page * 0x100;
+
+ if (address < image->address || address + 0x100 > image->address + image->length) {
+ ao_self_block_read(cc, address, block);
+ }
+ start = address;
+ stop = address + 0x100;
+ if (start < image->address)
+ start = image->address;
+ if (stop > image->address + image->length)
+ stop = image->address + image->length;
+ memcpy(block + start - address, image->data + start - image->address, stop - start);
+ ao_self_block_write(cc, address, block);
+ ao_self_block_read(cc, address, check);
+ if (memcmp(block, check, 0x100) != 0) {
+ fprintf(stderr, "Block at 0x%08x doesn't match\n", address);
+ return 0;
+ }
+ putchar('.'); fflush(stdout);
+ }
+ printf("done\n");
+ cc_usb_printf(cc,"a\n");
+ return 1;
+}
+
+/*
+ * Read a 16-bit value from the USB target
+ */
+
+uint16_t
+ao_self_get_uint16(struct cc_usb *cc, uint32_t addr)
+{
+ struct ao_hex_image *hex = ao_self_read(cc, addr, 2);
+ uint16_t v;
+ uint8_t *data;
+
+ if (!hex)
+ return 0;
+ data = hex->data + addr - hex->address;
+ v = data[0] | (data[1] << 8);
+ free(hex);
+ return v;
+}
+
+uint32_t
+ao_self_get_uint32(struct cc_usb *cc, uint32_t addr)
+{
+ struct ao_hex_image *hex = ao_self_read(cc, addr, 4);
+ uint32_t v;
+ uint8_t *data;
+
+ if (!hex)
+ return 0;
+ data = hex->data + addr - hex->address;
+ v = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
+ free(hex);
+ return v;
+}
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_SELFLOAD_H_
+#define _AO_SELFLOAD_H_
+
+#include <stdbool.h>
+#include "ao-hex.h"
+#include "cc-usb.h"
+
+struct ao_hex_image *
+ao_self_read(struct cc_usb *cc, uint32_t address, uint32_t length);
+
+bool
+ao_self_write(struct cc_usb *cc, struct ao_hex_image *image);
+
+uint16_t
+ao_self_get_uint16(struct cc_usb *cc, uint32_t addr);
+
+uint32_t
+ao_self_get_uint32(struct cc_usb *cc, uint32_t addr);
+
+#endif /* _AO_SELFLOAD_H_ */
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao-verbose.h"
+#include <stdio.h>
+
+uint32_t ao_verbose;
+
+void
+ao_printf(uint32_t verbose, const char *format, ...)
+{
+ va_list args;
+
+ if (!(ao_verbose & verbose))
+ return;
+
+ va_start(args, format);
+ vprintf(format, args);
+ va_end(args);
+}
+
+
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_VERBOSE_H_
+#define _AO_VERBOSE_H_
+
+#include <stdint.h>
+#include <stdarg.h>
+
+uint32_t ao_verbose;
+
+#define AO_VERBOSE_EXE 1
+#define AO_VERBOSE_SELF 2
+
+void
+ao_printf(uint32_t verbose, const char *format, ...);
+
+#endif /* _AO_VERBOSE_H_ */
--- /dev/null
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "cc.h"
+#include <string.h>
+#include <ctype.h>
+
+static const char *
+parse_hex(const char *data, int *result)
+{
+ char d[12];
+ int x;
+ int i;
+
+ while (isspace (*data))
+ data++;
+ for (i = 0; i < sizeof (d) - 1 && isxdigit(*data); i++)
+ d[i] = *data++;
+ d[i] = '\0';
+ if (sscanf(d, "%x", &x) != 1)
+ return NULL;
+ *result = x;
+ return data;
+}
+
+static const char *
+parse_uint16(const char *data, uint16_t *result)
+{
+ int x;
+ data = parse_hex(data, &x);
+ *result =x;
+ return data;
+}
+
+static const char *
+parse_uint8(const char *data, uint8_t *result)
+{
+ int x;
+ data = parse_hex(data, &x);
+ *result =x;
+ return data;
+}
+
+static int
+parse_eeprom(const char *input_line, struct ao_log_mega *l) {
+ const char *line;
+ int b;
+
+ if (input_line[1] != ' ')
+ return 0;
+ if (!isupper(input_line[0]))
+ return 0;
+
+ l->type = input_line[0];
+ l->is_config = 0;
+ line = input_line + 2;
+
+ line = parse_uint16(line, &l->tick);
+ for (b = 0; b < 28; b++) {
+ if (!line)
+ return 0;
+ line = parse_uint8(line, &l->u.bytes[b]);
+ }
+ return 1;
+}
+
+#define YUP(t) do { \
+ l->u.config_int.kind = (t); \
+ l->is_config = 1; \
+ return 1; \
+ } while (0);
+
+static int
+parse_config(const char *input_line, struct ao_log_mega *l) {
+ if (sscanf (input_line, "Config version: %d.%d",
+ &l->u.config_int.data[0],
+ &l->u.config_int.data[1]))
+ YUP(AO_CONFIG_CONFIG);
+ if (sscanf (input_line, "Main deploy: %d",
+ &l->u.config_int.data[0]))
+ YUP(AO_CONFIG_MAIN);
+ if (sscanf (input_line, "Apogee delay: %d",
+ &l->u.config_int.data[0]))
+ YUP(AO_CONFIG_APOGEE);
+ if (sscanf (input_line, "Apogee lockout: %d",
+ &l->u.config_int.data[0]))
+ YUP(AO_CONFIG_LOCKOUT);
+ if (sscanf (input_line, "Frequency: %d",
+ &l->u.config_int.data[0]))
+ YUP(AO_CONFIG_FREQUENCY);
+ if (sscanf (input_line, "Radio enable: %d",
+ &l->u.config_int.data[0]))
+ YUP(AO_CONFIG_RADIO_ENABLE);
+ if (sscanf (input_line, "Accel cal +1g: %d -1g: %d",
+ &l->u.config_int.data[0],
+ &l->u.config_int.data[1]))
+ YUP(AO_CONFIG_ACCEL_CAL);
+ if (sscanf (input_line, "Radio cal: %d",
+ &l->u.config_int.data[0]))
+ YUP(AO_CONFIG_RADIO_CAL);
+ if (sscanf (input_line, "Max flight log: %d",
+ &l->u.config_int.data[0]))
+ YUP(AO_CONFIG_MAX_LOG);
+ if (sscanf (input_line, "Ignite mode: %d",
+ &l->u.config_int.data[0]))
+ YUP(AO_CONFIG_IGNITE_MODE);
+ if (sscanf (input_line, "Pad orientation: %d",
+ &l->u.config_int.data[0]))
+ YUP(AO_CONFIG_PAD_ORIENTATION);
+ if (sscanf (input_line, "serial-number %d",
+ &l->u.config_int.data[0]))
+ YUP(AO_CONFIG_SERIAL_NUMBER);
+ if (sscanf (input_line, "log-format %d",
+ &l->u.config_int.data[0]))
+ YUP(AO_CONFIG_LOG_FORMAT);
+ if (sscanf (input_line, "ms5607 reserved: %d",
+ &l->u.config_int.data[0]))
+ YUP(AO_CONFIG_MS5607_RESERVED);
+ if (sscanf (input_line, "ms5607 sens: %d",
+ &l->u.config_int.data[0]))
+ YUP(AO_CONFIG_MS5607_SENS);
+ if (sscanf (input_line, "ms5607 off: %d",
+ &l->u.config_int.data[0]))
+ YUP(AO_CONFIG_MS5607_OFF);
+ if (sscanf (input_line, "ms5607 tcs: %d",
+ &l->u.config_int.data[0]))
+ YUP(AO_CONFIG_MS5607_TCS);
+ if (sscanf (input_line, "ms5607 tco: %d",
+ &l->u.config_int.data[0]))
+ YUP(AO_CONFIG_MS5607_TCO);
+ if (sscanf (input_line, "ms5607 tref: %d",
+ &l->u.config_int.data[0]))
+ YUP(AO_CONFIG_MS5607_TREF);
+ if (sscanf (input_line, "ms5607 tempsens: %d",
+ &l->u.config_int.data[0]))
+ YUP(AO_CONFIG_MS5607_TEMPSENS);
+ if (sscanf (input_line, "ms5607 crc: %d",
+ &l->u.config_int.data[0]))
+ YUP(AO_CONFIG_MS5607_CRC);
+ return 0;
+}
+
+int
+cc_mega_parse(const char *input_line, struct ao_log_mega *l) {
+ return parse_eeprom(input_line, l) || parse_config(input_line, l);
+}
/* 32 */
};
+#define AO_TELEMETRY_METRUM_SENSOR 0x0A
+
+struct ao_telemetry_metrum_sensor {
+ uint16_t serial; /* 0 */
+ uint16_t tick; /* 2 */
+ uint8_t type; /* 4 */
+
+ uint8_t state; /* 5 flight state */
+ int16_t accel; /* 6 Z axis */
+
+ int32_t pres; /* 8 Pa * 10 */
+ int16_t temp; /* 12 °C * 100 */
+
+ int16_t acceleration; /* 14 m/s² * 16 */
+ int16_t speed; /* 16 m/s * 16 */
+ int16_t height; /* 18 m */
+
+ int16_t v_batt; /* 20 battery voltage */
+ int16_t sense_a; /* 22 apogee continuity sense */
+ int16_t sense_m; /* 24 main continuity sense */
+
+ uint8_t pad[6]; /* 26 */
+ /* 32 */
+};
+
+#define AO_TELEMETRY_METRUM_DATA 0x0B
+
+struct ao_telemetry_metrum_data {
+ uint16_t serial; /* 0 */
+ uint16_t tick; /* 2 */
+ uint8_t type; /* 4 */
+
+ int32_t ground_pres; /* 8 average pres on pad */
+ int16_t ground_accel; /* 12 average accel on pad */
+ int16_t accel_plus_g; /* 14 accel calibration at +1g */
+ int16_t accel_minus_g; /* 16 accel calibration at -1g */
+
+ uint8_t pad[14]; /* 18 */
+ /* 32 */
+};
+
+#define AO_TELEMETRY_MINI 0x10
+
+struct ao_telemetry_mini {
+ uint16_t serial; /* 0 */
+ uint16_t tick; /* 2 */
+ uint8_t type; /* 4 */
+
+ uint8_t state; /* 5 flight state */
+ int16_t v_batt; /* 6 battery voltage */
+ int16_t sense_a; /* 8 apogee continuity */
+ int16_t sense_m; /* 10 main continuity */
+
+ int32_t pres; /* 12 Pa * 10 */
+ int16_t temp; /* 16 °C * 100 */
+
+ int16_t acceleration; /* 18 m/s² * 16 */
+ int16_t speed; /* 20 m/s * 16 */
+ int16_t height; /* 22 m */
+
+ int32_t ground_pres; /* 24 average pres on pad */
+
+ int32_t pad28; /* 28 */
+ /* 32 */
+};
+
/* #define AO_SEND_ALL_BARO */
#define AO_TELEMETRY_BARO 0x80
struct ao_telemetry_companion companion;
struct ao_telemetry_mega_sensor mega_sensor;
struct ao_telemetry_mega_data mega_data;
+ struct ao_telemetry_metrum_sensor metrum_sensor;
+ struct ao_telemetry_metrum_data metrum_data;
+ struct ao_telemetry_mini mini;
struct ao_telemetry_baro baro;
};
int16_t v_pbatt; /* 6 */
int16_t n_sense; /* 8 */
int16_t sense[10]; /* 10 */
- } volt; /* 30 */
+ uint16_t pyro; /* 30 */
+ } volt; /* 32 */
/* AO_LOG_GPS_TIME */
struct {
int32_t latitude; /* 4 */
}
uint8_t
-ccdbg_execute_hex_image(struct ccdbg *dbg, struct hex_image *image)
+ccdbg_execute_hex_image(struct ccdbg *dbg, struct ao_hex_image *image)
{
uint16_t pc;
uint8_t status;
#endif
uint8_t
-ccdbg_flash_hex_image(struct ccdbg *dbg, struct hex_image *image)
+ccdbg_flash_hex_image(struct ccdbg *dbg, struct ao_hex_image *image)
{
uint16_t flash_prog;
uint16_t flash_len;
+++ /dev/null
-/*
- * Copyright © 2008 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-#include "ccdbg.h"
-#include <stdarg.h>
-#include <ctype.h>
-
-struct hex_input {
- FILE *file;
- int line;
- char *name;
-};
-
-enum hex_read_state {
- read_marker,
- read_length,
- read_address,
- read_type,
- read_data,
- read_checksum,
- read_newline,
- read_white,
- read_done,
-};
-
-
-static void
-ccdbg_hex_error(struct hex_input *input, char *format, ...)
-{
- va_list ap;
-
- va_start(ap, format);
- fprintf(stderr, "Hex error %s:%d: ", input->name, input->line);
- vfprintf(stderr, format, ap);
- fprintf(stderr, "\n");
- va_end(ap);
-}
-
-static void
-ccdbg_hex_free(struct hex_record *record)
-{
- if (!record) return;
- free(record);
-}
-
-static struct hex_record *
-ccdbg_hex_alloc(uint8_t length)
-{
- struct hex_record *record;
-
- record = calloc(1, sizeof(struct hex_record) + length);
- record->length = length;
- return record;
-}
-
-static int
-ishex(char c)
-{
- return isdigit(c) || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F');
-}
-
-static int
-fromhex(char c)
-{
- if (isdigit(c))
- return c - '0';
- if ('a' <= c && c <= 'f')
- return c - 'a' + 10;
- if ('A' <= c && c <= 'F')
- return c - 'A' + 10;
- abort();
- return 0;
-}
-
-static uint8_t
-ccdbg_hex_checksum(struct hex_record *record)
-{
- uint8_t checksum = 0;
- int i;
-
- checksum += record->length;
- checksum += record->address >> 8;
- checksum += record->address & 0xff;
- checksum += record->type;
- for (i = 0; i < record->length; i++)
- checksum += record->data[i];
- return -checksum;
-}
-
-static struct hex_record *
-ccdbg_hex_read_record(struct hex_input *input)
-{
- struct hex_record *record = NULL;
- enum hex_read_state state = read_marker;
- char c;
- int nhexbytes;
- uint32_t hex;
- uint32_t ndata;
- uint8_t checksum;
-
- while (state != read_done) {
- c = getc(input->file);
- if (c == EOF && state != read_white) {
- ccdbg_hex_error(input, "Unexpected EOF");
- goto bail;
- }
- if (c == ' ')
- continue;
- if (c == '\n')
- input->line++;
- switch (state) {
- case read_marker:
- if (c != ':') {
- ccdbg_hex_error(input, "Missing ':'");
- goto bail;
- }
- state = read_length;
- nhexbytes = 2;
- hex = 0;
- break;
- case read_length:
- case read_address:
- case read_type:
- case read_data:
- case read_checksum:
- if (!ishex(c)) {
- ccdbg_hex_error(input, "Non-hex char '%c'",
- c);
- goto bail;
- }
- hex = hex << 4 | fromhex(c);
- --nhexbytes;
- if (nhexbytes != 0)
- break;
-
- switch (state) {
- case read_length:
- record = ccdbg_hex_alloc(hex);
- if (!record) {
- ccdbg_hex_error(input, "Out of memory");
- goto bail;
- }
- state = read_address;
- nhexbytes = 4;
- break;
- case read_address:
- record->address = hex;
- state = read_type;
- nhexbytes = 2;
- break;
- case read_type:
- record->type = hex;
- state = read_data;
- nhexbytes = 2;
- ndata = 0;
- break;
- case read_data:
- record->data[ndata] = hex;
- ndata++;
- nhexbytes = 2;
- break;
- case read_checksum:
- record->checksum = hex;
- state = read_newline;
- break;
- default:
- break;
- }
- if (state == read_data)
- if (ndata == record->length) {
- nhexbytes = 2;
- state = read_checksum;
- }
- hex = 0;
- break;
- case read_newline:
- if (c != '\n' && c != '\r') {
- ccdbg_hex_error(input, "Missing newline");
- goto bail;
- }
- state = read_white;
- break;
- case read_white:
- if (!isspace(c)) {
- if (c == '\n')
- input->line--;
- if (c != EOF)
- ungetc(c, input->file);
- state = read_done;
- }
- break;
- case read_done:
- break;
- }
- }
- checksum = ccdbg_hex_checksum(record);
- if (checksum != record->checksum) {
- ccdbg_hex_error(input, "Invalid checksum (read 0x%02x computed 0x%02x)\n",
- record->checksum, checksum);
- goto bail;
- }
- return record;
-
-bail:
- ccdbg_hex_free(record);
- return NULL;
-}
-
-void
-ccdbg_hex_file_free(struct hex_file *hex)
-{
- int i;
-
- if (!hex)
- return;
- for (i = 0; i < hex->nrecord; i++)
- ccdbg_hex_free(hex->records[i]);
- free(hex);
-}
-
-struct hex_file *
-ccdbg_hex_file_read(FILE *file, char *name)
-{
- struct hex_input input;
- struct hex_file *hex = NULL, *newhex;
- struct hex_record *record;
- int srecord = 1;
- int done = 0;
-
- hex = calloc(sizeof (struct hex_file) + sizeof (struct hex_record *), 1);
- input.name = name;
- input.line = 1;
- input.file = file;
- while (!done) {
- record = ccdbg_hex_read_record(&input);
- if (!record)
- goto bail;
- if (hex->nrecord == srecord) {
- srecord *= 2;
- newhex = realloc(hex,
- sizeof (struct hex_file) +
- srecord * sizeof (struct hex_record *));
- if (!newhex)
- goto bail;
- hex = newhex;
- }
- hex->records[hex->nrecord++] = record;
- if (record->type == HEX_RECORD_EOF)
- done = 1;
- }
- return hex;
-
-bail:
- ccdbg_hex_file_free(hex);
- return NULL;
-}
-
-struct hex_image *
-ccdbg_hex_image_create(struct hex_file *hex)
-{
- struct hex_image *image;
- struct hex_record *record;
- int i;
- uint32_t addr;
- uint32_t base, bound;
- uint32_t offset;
- uint32_t extended_addr;
-
- int length;
-
- base = 0xffffffff;
- bound = 0x0;
- extended_addr = 0;
- for (i = 0; i < hex->nrecord; i++) {
- uint32_t r_bound;
- record = hex->records[i];
- switch (record->type) {
- case 0:
- addr = extended_addr + record->address;
- r_bound = addr + record->length;
- if (addr < base)
- base = addr;
- if (r_bound > bound)
- bound = r_bound;
- break;
- case 1:
- break;
- case 2:
- if (record->length != 2)
- return NULL;
- extended_addr = ((record->data[0] << 8) | record->data[1]) << 4;
- break;
- case 4:
- if (record->length != 2)
- return NULL;
- extended_addr = ((record->data[0] << 8) | record->data[1]) << 16;
- break;
- }
-
- }
- length = bound - base;
- image = calloc(sizeof(struct hex_image) + length, 1);
- if (!image)
- return NULL;
- image->address = base;
- image->length = length;
- memset(image->data, 0xff, length);
- extended_addr = 0;
- for (i = 0; i < hex->nrecord; i++) {
- record = hex->records[i];
- switch (record->type) {
- case 0:
- addr = extended_addr + record->address;
- offset = addr - base;
- memcpy(image->data + offset, record->data, record->length);
- break;
- case 1:
- break;
- case 2:
- extended_addr = ((record->data[0] << 8) | record->data[1]) << 4;
- break;
- case 4:
- extended_addr = ((record->data[0] << 8) | record->data[1]) << 16;
- break;
- }
- }
- return image;
-}
-
-void
-ccdbg_hex_image_free(struct hex_image *image)
-{
- free(image);
-}
-
-int
-ccdbg_hex_image_equal(struct hex_image *a, struct hex_image *b)
-{
- if (a->length != b->length)
- return 0;
- if (memcmp(a->data, b->data, a->length) != 0)
- return 0;
- return 1;
-}
-
-struct hex_image *
-ccdbg_hex_load(char *filename)
-{
- FILE *file;
- struct hex_file *hex_file;
- struct hex_image *hex_image;
-
- file = fopen (filename, "r");
- if (!file)
- return 0;
-
- hex_file = ccdbg_hex_file_read(file, filename);
- fclose(file);
- if (!hex_file)
- return 0;
- hex_image = ccdbg_hex_image_create(hex_file);
- if (!hex_image)
- return 0;
- ccdbg_hex_file_free(hex_file);
- return hex_image;
-}
}
uint8_t
-ccdbg_write_hex_image(struct ccdbg *dbg, struct hex_image *image, uint16_t offset)
+ccdbg_write_hex_image(struct ccdbg *dbg, struct ao_hex_image *image, uint16_t offset)
{
ccdbg_write_memory(dbg, image->address + offset, image->data, image->length);
return 0;
}
-struct hex_image *
+struct ao_hex_image *
ccdbg_read_hex_image(struct ccdbg *dbg, uint16_t address, uint16_t length)
{
- struct hex_image *image;
+ struct ao_hex_image *image;
- image = calloc(sizeof(struct hex_image) + length, 1);
+ image = calloc(sizeof(struct ao_hex_image) + length, 1);
image->address = address;
image->length = length;
memset(image->data, 0xff, length);
#include "ccdbg.h"
uint8_t
-ccdbg_set_rom(struct ccdbg *dbg, struct hex_image *rom)
+ccdbg_set_rom(struct ccdbg *dbg, struct ao_hex_image *rom)
{
if (dbg->rom)
- ccdbg_hex_image_free(dbg->rom);
+ ao_hex_image_free(dbg->rom);
dbg->rom = rom;
return 0;
}
uint8_t
ccdbg_rom_contains(struct ccdbg *dbg, uint16_t addr, int nbytes)
{
- struct hex_image *rom = dbg->rom;
+ struct ao_hex_image *rom = dbg->rom;
if (!rom)
return 0;
if (addr < rom->address || rom->address + rom->length < addr + nbytes)
ccdbg_rom_replace_xmem(struct ccdbg *dbg,
uint16_t addr, uint8_t *bytes, int nbytes)
{
- struct hex_image *rom = dbg->rom;
+ struct ao_hex_image *rom = dbg->rom;
if (!rom)
return 0;
#include "ccdbg-debug.h"
#include "cc-bitbang.h"
#include "cc-usb.h"
+#include "ao-hex.h"
/* 8051 instructions
*/
struct ccdbg {
struct cc_bitbang *bb;
struct cc_usb *usb;
- struct hex_image *rom;
+ struct ao_hex_image *rom;
};
-/* Intel hex file format data
- */
-struct hex_record {
- uint8_t length;
- uint16_t address;
- uint8_t type;
- uint8_t checksum;
- uint8_t data[0];
-};
-
-struct hex_file {
- int nrecord;
- struct hex_record *records[0];
-};
-
-struct hex_image {
- uint32_t address;
- uint32_t length;
- uint8_t data[0];
-};
#define CC_STATE_ACC 0x1
#define CC_STATE_PSW 0x2
uint8_t sfr[CC_STATE_NSFR];
};
-#define HEX_RECORD_NORMAL 0x00
-#define HEX_RECORD_EOF 0x01
-#define HEX_RECORD_EXTENDED_ADDRESS 0x02
-
/* CC1111 debug port commands
*/
#define CC_CHIP_ERASE 0x14
ccdbg_set_pc(struct ccdbg *dbg, uint16_t pc);
uint8_t
-ccdbg_execute_hex_image(struct ccdbg *dbg, struct hex_image *image);
+ccdbg_execute_hex_image(struct ccdbg *dbg, struct ao_hex_image *image);
/* ccdbg-flash.c */
uint8_t
-ccdbg_flash_hex_image(struct ccdbg *dbg, struct hex_image *image);
-
-/* ccdbg-hex.c */
-struct hex_file *
-ccdbg_hex_file_read(FILE *file, char *name);
-
-void
-ccdbg_hex_file_free(struct hex_file *hex);
-
-struct hex_image *
-ccdbg_hex_image_create(struct hex_file *hex);
-
-void
-ccdbg_hex_image_free(struct hex_image *image);
-
-struct hex_image *
-ccdbg_hex_load(char *filename);
-
-int
-ccdbg_hex_image_equal(struct hex_image *a, struct hex_image *b);
+ccdbg_flash_hex_image(struct ccdbg *dbg, struct ao_hex_image *image);
/* ccdbg-io.c */
struct ccdbg *
ccdbg_write_uint8(struct ccdbg *dbg, uint16_t addr, uint8_t byte);
uint8_t
-ccdbg_write_hex_image(struct ccdbg *dbg, struct hex_image *image, uint16_t offset);
+ccdbg_write_hex_image(struct ccdbg *dbg, struct ao_hex_image *image, uint16_t offset);
-struct hex_image *
+struct ao_hex_image *
ccdbg_read_hex_image(struct ccdbg *dbg, uint16_t address, uint16_t length);
uint8_t
/* ccdbg-rom.c */
uint8_t
-ccdbg_set_rom(struct ccdbg *dbg, struct hex_image *rom);
+ccdbg_set_rom(struct ccdbg *dbg, struct ao_hex_image *rom);
uint8_t
ccdbg_rom_contains(struct ccdbg *dbg, uint16_t addr, int nbytes);
autoreconf --force -v --install || exit 1
cd $ORIGDIR || exit $?
-PKG_CONFIG_PATH=/opt/cortex/lib/pkgconfig \
- $srcdir/configure --enable-maintainer-mode "$@"
+$srcdir/configure --enable-maintainer-mode "$@"
dnl Process this file with autoconf to create configure.
AC_PREREQ(2.57)
+<<<<<<< HEAD
AC_INIT([altos], 1.2.1)
+=======
+AC_INIT([altos], 1.3)
+>>>>>>> branch-1.3
AC_CONFIG_SRCDIR([src/core/ao.h])
AM_INIT_AUTOMAKE([foreign dist-bzip2])
AM_MAINTAINER_MODE
VERSION_DASH=`echo $VERSION | sed 's/\./-/g'`
AC_SUBST(VERSION_DASH)
-
dnl ==========================================================================
dnl Java library versions
ALTOSUILIB_VERSION=1
-ALTOSLIB_VERSION=1
+ALTOSLIB_VERSION=2
AC_SUBST(ALTOSLIB_VERSION)
AC_DEFINE(ALTOSLIB_VERSION,$ALTOSLIB_VERSION,[Version of the AltosLib package])
fi
AC_SUBST(WARN_CFLAGS)
-AC_CHECK_PROG([HAVE_SDCC], [sdcc], yes, no)
+#
+# Configure SDCC
+#
+
+AC_ARG_WITH([sdcc],
+ [AS_HELP_STRING([--with-sdcc],
+ [Name of SDCC])],
+ [],
+ [with_sdcc=auto])
+
+if test "x$with_sdcc" != "xno"; then
+ if test "x$with_sdcc" = "xauto"; then
+ with_sdcc="sdcc"
+ AC_CHECK_PROG([HAVE_SDCC],[$with_sdcc], yes, no)
+ else
+ HAVE_SDCC=yes
+ fi
+else
+ HAVE_SDCC=no
+fi
+
if test "x$HAVE_SDCC" = "xno"; then
- AC_MSG_WARN([No sdcc found, cc1111 binaries will not be built])
+ AC_MSG_WARN([SDCC not found, cc1111 binaries will not be built])
+else
+ SDCC=$with_sdcc
+fi
+
+AC_SUBST(SDCC)
+AC_SUBST(HAVE_SDCC)
+
+#
+# Configure ARM compiler for STM32L and LPC11U14
+#
+
+AC_ARG_WITH([arm-cc],
+ [AS_HELP_STRING([--with-arm-cc],
+ [Name of ARM C compiler])],
+ [],
+ [with_arm_cc=auto])
+
+if test "x$with_arm_cc" != "xno"; then
+ if test "x$with_arm_cc" = "xauto"; then
+ with_arm_cc="arm-none-eabi-gcc"
+ AC_CHECK_PROG([HAVE_ARM_CC],[$with_arm_cc], yes, no)
+ else
+ HAVE_ARM_CC=yes
+ fi
+else
+ HAVE_ARM_CC=no
+fi
+
+if test "x$HAVE_ARM_CC" = "xno"; then
+ AC_MSG_WARN([Arm compiler not found, ARM binaries will not be built])
+else
+ ARM_CC=$with_arm_cc
+fi
+AC_SUBST(HAVE_ARM_CC)
+AC_SUBST(ARM_CC)
+
+if test -d pdclib -a x"$HAVE_ARM_CC" = xyes; then
+ PDCLIB_ROOT='$(TOPDIR)/../pdclib-root'
+ PDCLIB_INCLUDES='-I$(TOPDIR)/../pdclib-root/include'
+ PDCLIB_LIBS_M0='-L$(TOPDIR)/../pdclib-root/lib -lpdclib-cortex-m0'
+ PDCLIB_LIBS_M3='-L$(TOPDIR)/../pdclib-root/lib -lpdclib-cortex-m3'
+ HAVE_PDCLIB=yes
+else
+ PDCLIB_INCLUDES=''
+ PDCLIB_LIBS_M0='-lpdclib-cortex-m0'
+ PDCLIB_LIBS_M3='-lpdclib-cortex-m3'
+ HAVE_PDCLIB=no
+fi
+
+AM_CONDITIONAL(PDCLIB, [test x$HAVE_PDCLIB = xyes])
+
+AC_SUBST(PDCLIB_INCLUDES)
+AC_SUBST(PDCLIB_LIBS_M0)
+AC_SUBST(PDCLIB_LIBS_M3)
+AC_SUBST(PDCLIB_ROOT)
+AC_SUBST(HAVE_PDCLIB)
+
+if test "x$HAVE_ARM_CC" = "xyes"; then
+ save_CC="$CC"
+ save_CFLAGS="$CFLAGS"
+ save_LIBS="$LIBS"
+ CC="$ARM_CC"
+ CFLAGS="-mthumb -mcpu=cortex-m0"
+ LIBS="-ffreestanding -nostdlib"
+ AC_LANG_PUSH([C])
+
+ AC_MSG_CHECKING([if ]$ARM_CC[ supports cortex-m0])
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([int i;])],
+ [HAVE_ARM_M0_CC=yes],
+ [HAVE_ARM_M0_CC=no])
+ AC_MSG_RESULT([$HAVE_ARM_M0_CC])
+
+ CFLAGS="-mthumb -mcpu=cortex-m3"
+ AC_MSG_CHECKING([if ]$ARM_CC[ supports cortex-m3])
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([int i;])],
+ [HAVE_ARM_M3_CC=yes],
+ [HAVE_ARM_M3_CC=no])
+ AC_MSG_RESULT([$HAVE_ARM_M3_CC])
+
+ if test x$HAVE_PDCLIB != xyes; then
+ AC_CHECK_LIB(pdclib-cortex-m0,memcpy,
+ [],
+ [HAVE_ARM_M0_CC=no])
+
+ AC_CHECK_LIB(pdclib-cortex-m3,memcpy,
+ [],
+ [HAVE_ARM_M3_CC=no])
+ fi
+
+ AC_LANG_POP([C])
+ LIBS="$save_LIBS"
+ CFLAGS="$save_CFLAGS"
+ CC="$save_CC"
+else
+ HAVE_ARM_M3_CC=no
+ HAVE_ARM_M0_CC=no
+fi
+AC_SUBST(HAVE_ARM_M3_CC)
+AC_SUBST(HAVE_ARM_M0_CC)
+
+if test "x$HAVE_ARM_M3_CC" = "xno"; then
+ AC_MSG_WARN([No cortex-m3 arm compiler found, STM32L binaries will not be built])
fi
-AC_CHECK_PROG([HAVE_ARM_GCC], [arm-none-eabi-gcc], yes, no)
-if test "x$HAVE_ARM_GCC" = "xno"; then
- AC_MSG_WARN([No arm compiler found, STM32L and LPC11U14 binaries will not be built])
+if test "x$HAVE_ARM_M0_CC" = "xno"; then
+ AC_MSG_WARN([No cortex-m0 arm compiler found, LPC11U14 binaries will not be built])
fi
+#
+# Configure AVR compiler
+#
+
+AC_ARG_WITH([avr-cc],
+ [AS_HELP_STRING([--with-avr-cc],
+ [Name of AVR C compiler])],
+ [],
+ [with_avr_cc=auto])
+
+if test "x$with_avr_cc" != "xno"; then
+ if test "x$with_avr_cc" = "xauto"; then
+ with_avr_cc="avr-gcc"
+ AC_CHECK_PROG([HAVE_AVR_CC],[$with_avr_cc], yes, no)
+ else
+ HAVE_AVR_CC=yes
+ fi
+else
+ HAVE_AVR_CC=no
+fi
+
+AC_ARG_WITH([avr-objcopy],
+ [AS_HELP_STRING([--with-avr-objcopy],
+ [Name of AVR objcopy])],
+ [],
+ [with_avr_objcopy=auto])
+
+if test "x$with_avr_objcopy" != "xno"; then
+ if test "x$with_avr_objcopy" = "xauto"; then
+ with_avr_objcopy="avr-objcopy"
+ AC_CHECK_PROG([HAVE_AVR_OBJCOPY],[$with_avr_objcopy], yes, no)
+ else
+ HAVE_AVR_OBJCOPY=yes
+ fi
+else
+ HAVE_AVR_OBJCOPY=no
+fi
+
+if test "x$HAVE_AVR_CC" = "xno" -o "x$HAVE_AVR_OBJCOPY" = "xno"; then
+ AC_MSG_WARN([AVR compiler and objcopy not found, atmel binaries will not be built])
+ HAVE_AVR_CC=no
+else
+ save_CC="$CC"
+ save_CFLAGS="$CFLAGS"
+ save_LIBS="$LIBS"
+
+ CC="$with_avr_cc"
+ CFLAGS="-mmcu=attiny85"
+ AC_LANG_PUSH([C])
+ AC_MSG_CHECKING([if ]$with_avr_cc[ can link programs])
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([])],
+ [AVR_LINK=yes],
+ [AVR_LINK=no])
+ AC_MSG_RESULT([$AVR_LINK])
+ AC_LANG_POP([C])
+
+ LIBS="$save_LIBS"
+ CFLAGS="$save_CFLAGS"
+ CC="$save_CC"
+
+ if test "x$AVR_LINK" = xyes; then
+ AVR_CC=$with_avr_cc
+ AVR_OBJCOPY=$with_avr_objcopy
+ else
+ HAVE_AVR_CC=no;
+ fi
+fi
+
+AC_SUBST(AVR_CC)
+AC_SUBST(AVR_OBJCOPY)
+AC_SUBST(HAVE_AVR_CC)
+
AC_CHECK_PROG([HAVE_NICKLE], [nickle], yes, no)
if test "x$HAVE_NICKLE" = "xno"; then
AC_MSG_ERROR([Please install nickle to build AltOs])
fi
-AC_CHECK_LIB(readline, readline)
+AC_ARG_WITH([readline],
+ [AS_HELP_STRING([--with-readline],
+ [enable readline functionality in ao-dbg @<:@default=auto@:>@])],
+ [],
+ [with_readline=auto])
+
+LIBREADLINE_LIBS=
+
+if test x"$with_readline" != "xno"; then
+ AC_CHECK_LIB([readline], [main],
+ [AC_SUBST([LIBREADLINE], ["-lreadline -lncurses"])
+ AC_DEFINE([HAVE_LIBREADLINE], [1],
+ [Define if you have libreadline])],
+ [if test "x$with_readline" != xauto; then
+ AC_MSG_ERROR([--with-readline was given, but test for readline failed])
+ fi],
+ -lncurses)
+fi
PKG_CHECK_MODULES([LIBUSB], [libusb-1.0])
AC_CHECK_HEADERS(libelf.h libelf/libelf.h, [break])
AC_CHECK_HEADERS(gelf.h libelf/gelf.h, [break])
-PKG_CHECK_MODULES([LIBSTLINK], [stlink], [HAVE_STLINK=yes], [HAVE_STLINK=no])
+AC_ARG_WITH([stlink],
+ [AS_HELP_STRING([--with-stlink],
+ [Build tools that use the stlink library (default: auto)])],
+ [],
+ [with_stlink=auto])
+
+if test x"$with_stlink" != "xno"; then
+ PKG_CHECK_MODULES([STLINK], [stlink], [HAVE_STLINK=yes], [HAVE_STLINK=no])
+ if test x"$HAVE_STLINK" = "xno" -a x"$with_stlink" != "xauto"; then
+ AC_MSG_ERROR([--with-stlink was given, but stlink was not found])
+ fi
+else
+ HAVE_STLINK=no
+fi
+
+if test x"$HAVE_STLINK" = "xyes"; then
+ AC_DEFINE(HAVE_STLINK,1,[Using STlink library])
+fi
-AM_CONDITIONAL([LIBSTLINK], [test x$HAVE_STLINK != xno])
+AM_CONDITIONAL([LIBSTLINK], [test x$HAVE_STLINK == xyes])
AC_OUTPUT([
Makefile
+src/Makedefs
altoslib/Makefile
altosuilib/Makefile
altosuilib/AltosUIVersion.java
ao-tools/ao-dumpflash/Makefile
ao-tools/ao-edit-telem/Makefile
ao-tools/ao-dump-up/Makefile
+ao-tools/ao-elftohex/Makefile
+ao-tools/ao-usbload/Makefile
+ao-tools/ao-flash/Makefile
ao-utils/Makefile
src/Version
])
echo " Package: ${PACKAGE_NAME} ${PACKAGE_VERSION}"
echo ""
echo " Configuration"
-echo " STM32L/LPC11U14 support.....: ${HAVE_ARM_GCC}"
+echo " Arm compiler................: ${ARM_CC}"
+echo " STM32L support..............: ${HAVE_ARM_M3_CC}"
+echo " LPC11U14 support............: ${HAVE_ARM_M0_CC}"
+echo " SDCC........................: ${SDCC}"
echo " CC1111 support..............: ${HAVE_SDCC}"
+echo " AVR compiler................: ${AVR_CC} ${AVR_OBJCOPY}"
+echo " AVR support.................: ${HAVE_AVR_CC}"
echo " Android support.............: ${HAVE_ANDROID_SDK}"
echo " STlink support..............: ${HAVE_STLINK}"
+echo " Local pdclib................: ${HAVE_PDCLIB}"
echo ""
echo " Java paths"
echo " freetts.....................: ${FREETTS}"
debian/altos.desktop usr/share/applications
debian/altusmetrum.xpm usr/share/pixmaps
-src/*.ihx usr/share/altos
-src/*.map usr/share/altos
+src/*/*.ihx usr/share/altos
+src/*/*.map usr/share/altos
themes/background.png usr/share/altos/themes
themes/slim/panel.png usr/share/slim/themes/altusmetrum
themes/slim/slim.theme usr/share/slim/themes/altusmetrum
Priority: optional
Maintainer: Bdale Garbee <bdale@gag.com>
Uploaders: Keith Packard <keithp@keithp.com>
-Build-Depends: debhelper (>= 7), autoconf, automake, gawk, libreadline-dev, libusb-1.0-0-dev, nickle, cc1111, xsltproc, fop, docbook-xml, docbook-xsl, swig, default-jdk, freetts, libtool, libjfreechart-java, libbluetooth-dev, pkg-config, libelf-dev, libbluetooth-dev, libssl-dev, sox
-Standards-Version: 3.9.4
+Build-Depends: debhelper (>= 7), autoconf, automake, gawk, libreadline-dev, libusb-1.0-0-dev, nickle, cc1111, xsltproc, fop, xmlto, docbook-xml, docbook-xsl, swig, default-jdk, freetts, libtool, libjfreechart-java, libbluetooth-dev, pkg-config, libelf-dev, libbluetooth-dev, libssl-dev, gcc-arm-none-eabi
+Standards-Version: 3.9.5
Homepage: http://altusmetrum.org/AltOS
Vcs-Git: git://git.gag.com/fw/altos
Vcs-Browser: http://git.gag.com/?p=fw/altos
configure: configure-stamp
configure-stamp:
dh_testdir
- ./autogen.sh --prefix=/usr
+ PKG_CONFIG_PATH=/opt/stlink/lib/pkgconfig ./autogen.sh --prefix=/usr
touch configure-stamp
build: build-arch build-indep
release-notes-1.1.html \
release-notes-1.1.1.html \
release-notes-1.2.html \
- release-notes-1.2.1.html
+ release-notes-1.2.1.html \
+ release-notes-1.3.html
+
+PICTURES=\
+ altosui.png \
+ ascent.png \
+ configure-altimeter.png \
+ configure-altosui.png \
+ configure-groundstation.png \
+ configure-pyro.png \
+ descent.png \
+ device-selection.png \
+ easymini-top.jpg \
+ fire-igniter.png \
+ graph-configure.png \
+ graph-map.png \
+ graph.png \
+ graph-stats.png \
+ landed.png \
+ launch-pad.png \
+ load-maps.png \
+ scan-channels.png \
+ site-map.png \
+ table.png \
+ telemega-v1.0-top.jpg \
+ telemetrum-v1.1-thside.jpg \
+ telemini-v1-top.jpg \
+ telemini-v2-top.jpg
+SVG=\
+ easymini-outline.svg \
+ telemega-outline.svg \
+ telemetrum.svg \
+ telemini.svg
RELNOTES_XSL=$(RELNOTES:.html=.xsl)
HTML=altusmetrum.html altos.html telemetry.html companion.html micropeak.html $(RELNOTES)
PDF=altusmetrum.pdf altos.pdf telemetry.pdf companion.pdf micropeak.pdf
-DOC=$(HTML) $(PDF)
HTMLSTYLE=/usr/share/xml/docbook/stylesheet/docbook-xsl/html/docbook.xsl
-FOSTYLE=/usr/share/xml/docbook/stylesheet/docbook-xsl/fo/docbook.xsl
+FOSTYLE=xorg-fo.xsl
PDFSTYLE=
-IMAGES=telemetrum.svg telemini.svg
+IMAGES=$(PICTURES) $(SVG)
+DOC=$(HTML) $(PDF) $(PICTURES)
-.SUFFIXES: .xsl .html .fo .pdf
+.SUFFIXES: .xsl .html .pdf
XSLTFLAGS=--stringparam section.autolabel 1 --xinclude
.xsl.html:
xsltproc $(XSLTFLAGS) -o $@ $(HTMLSTYLE) $*.xsl
-.xsl.fo:
- xsltproc $(XSLTFLAGS) -o $@ $(FOSTYLE) $*.xsl
-
-.fo.pdf:
- fop -fo $*.fo -pdf $@
+.xsl.pdf:
+ xmlto -x $(FOSTYLE) --with-fop pdf $*.xsl
all: $(HTML) $(PDF)
git push)
clean:
- rm -f $(HTML) $(PDF) *.fo
+ rm -f $(HTML) $(PDF)
distclean:
- rm -f $(HTML) $(PDF) *.fo
+ rm -f $(HTML) $(PDF)
altusmetrum.html: $(RELNOTES_XSL) $(IMAGES)
-altusmetrum.fo: $(RELNOTES_XSL) $(IMAGES)
+altusmetrum.pdf: $(RELNOTES_XSL) $(IMAGES)
+
+$(PDF): $(FOSTYLE)
indent: altusmetrum.xsl
xmlindent -i 2 < altusmetrum.xsl > altusmetrum.new
will fail to compile.
<itemizedlist>
<listitem>
+<para>
AO_EXTI_MODE_PULL_UP. Apply a pull-up to the pin; a
disconnected pin will read as 1.
+</para>
</listitem>
<listitem>
+<para>
AO_EXTI_MODE_PULL_DOWN. Apply a pull-down to the pin;
a disconnected pin will read as 0.
+</para>
</listitem>
<listitem>
+<para>
0. Don't apply either a pull-up or pull-down. A
disconnected pin will read an undetermined value.
+</para>
</listitem>
</itemizedlist>
</para>
variable with one of the following values:
<variablelist>
<varlistentry>
- <title>ao_cmd_success</title>
+ <term>ao_cmd_success</term>
<listitem>
<para>
The command was parsed successfully. There is no
</listitem>
</varlistentry>
<varlistentry>
- <title>ao_cmd_lex_error</title>
+ <term>ao_cmd_lex_error</term>
<listitem>
<para>
A token in the line was invalid, such as a number
</listitem>
</varlistentry>
<varlistentry>
- <title>ao_syntax_error</title>
+ <term>ao_syntax_error</term>
<listitem>
<para>
The command line is invalid for some reason other
</chapter>
<chapter>
<title>CC1111 Radio peripheral</title>
- <para>
- The CC1111 radio transceiver sends and receives digital packets
- with forward error correction and detection. The AltOS driver is
- fairly specific to the needs of the TeleMetrum and TeleDongle
- devices, using it for other tasks may require customization of
- the driver itself. There are three basic modes of operation:
- <orderedlist>
- <listitem>
- <para>
- Telemetry mode. In this mode, TeleMetrum transmits telemetry
- frames at a fixed rate. The frames are of fixed size. This
- is strictly a one-way communication from TeleMetrum to
- TeleDongle.
- </para>
- </listitem>
- <listitem>
- <para>
- Packet mode. In this mode, the radio is used to create a
- reliable duplex byte stream between TeleDongle and
- TeleMetrum. This is an asymmetrical protocol with
- TeleMetrum only transmitting in response to a packet sent
- from TeleDongle. Thus getting data from TeleMetrum to
- TeleDongle requires polling. The polling rate is adaptive,
- when no data has been received for a while, the rate slows
- down. The packets are checked at both ends and invalid
- data are ignored.
- </para>
- <para>
- On the TeleMetrum side, the packet link is hooked into the
- stdio mechanism, providing an alternate data path for the
- command processor. It is enabled when the unit boots up in
- 'idle' mode.
- </para>
- <para>
- On the TeleDongle side, the packet link is enabled with a
- command; data from the stdio package is forwarded over the
- packet link providing a connection from the USB command
- stream to the remote TeleMetrum device.
- </para>
- </listitem>
- <listitem>
- <para>
- Radio Direction Finding mode. In this mode, TeleMetrum
- constructs a special packet that sounds like an audio tone
- when received by a conventional narrow-band FM
- receiver. This is designed to provide a beacon to track
- the device when other location mechanisms fail.
- </para>
- </listitem>
- </orderedlist>
- </para>
+ <section>
+ <title>Radio Introduction</title>
+ <para>
+ The CC1111 radio transceiver sends and receives digital packets
+ with forward error correction and detection. The AltOS driver is
+ fairly specific to the needs of the TeleMetrum and TeleDongle
+ devices, using it for other tasks may require customization of
+ the driver itself. There are three basic modes of operation:
+ <orderedlist>
+ <listitem>
+ <para>
+ Telemetry mode. In this mode, TeleMetrum transmits telemetry
+ frames at a fixed rate. The frames are of fixed size. This
+ is strictly a one-way communication from TeleMetrum to
+ TeleDongle.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Packet mode. In this mode, the radio is used to create a
+ reliable duplex byte stream between TeleDongle and
+ TeleMetrum. This is an asymmetrical protocol with
+ TeleMetrum only transmitting in response to a packet sent
+ from TeleDongle. Thus getting data from TeleMetrum to
+ TeleDongle requires polling. The polling rate is adaptive,
+ when no data has been received for a while, the rate slows
+ down. The packets are checked at both ends and invalid
+ data are ignored.
+ </para>
+ <para>
+ On the TeleMetrum side, the packet link is hooked into the
+ stdio mechanism, providing an alternate data path for the
+ command processor. It is enabled when the unit boots up in
+ 'idle' mode.
+ </para>
+ <para>
+ On the TeleDongle side, the packet link is enabled with a
+ command; data from the stdio package is forwarded over the
+ packet link providing a connection from the USB command
+ stream to the remote TeleMetrum device.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Radio Direction Finding mode. In this mode, TeleMetrum
+ constructs a special packet that sounds like an audio tone
+ when received by a conventional narrow-band FM
+ receiver. This is designed to provide a beacon to track
+ the device when other location mechanisms fail.
+ </para>
+ </listitem>
+ </orderedlist>
+ </para>
+ </section>
<section>
<title>ao_radio_set_telemetry</title>
<programlisting>
the radio operation.
</para>
</section>
- <para>
- In telemetry mode, you can send or receive a telemetry
- packet. The data from receiving a packet also includes the RSSI
- and status values supplied by the receiver. These are added
- after the telemetry data.
- </para>
<section>
- <title>ao_radio_send</title>
+ <title>Radio Telemetry</title>
+ <para>
+ In telemetry mode, you can send or receive a telemetry
+ packet. The data from receiving a packet also includes the RSSI
+ and status values supplied by the receiver. These are added
+ after the telemetry data.
+ </para>
+ <section>
+ <title>ao_radio_send</title>
<programlisting>
void
ao_radio_send(__xdata struct ao_telemetry *telemetry);
sending, and ao_radio_put() afterwards, to correctly
serialize access to the radio device.
</para>
- </section>
- <section>
- <title>ao_radio_recv</title>
+ </section>
+ <section>
+ <title>ao_radio_recv</title>
<programlisting>
void
ao_radio_recv(__xdata struct ao_radio_recv *radio);
received, or zero if the operation was aborted (from some
other task calling ao_radio_abort()).
</para>
+ </section>
</section>
- <para>
- In radio direction finding mode, there's just one function to
- use
- </para>
<section>
- <title>ao_radio_rdf</title>
+ <title>Radio Direction Finding</title>
+ <para>
+ In radio direction finding mode, there's just one function to
+ use
+ </para>
+ <section>
+ <title>ao_radio_rdf</title>
<programlisting>
void
ao_radio_rdf(int ms);
This sends an RDF packet lasting for the specified amount
of time. The maximum length is 1020 ms.
</para>
+ </section>
</section>
- <para>
- Packet mode is asymmetrical and is configured at compile time
- for either master or slave mode (but not both). The basic I/O
- functions look the same at both ends, but the internals are
- different, along with the initialization steps.
- </para>
<section>
- <title>ao_packet_putchar</title>
+ <title>Radio Packet Mode</title>
+ <para>
+ Packet mode is asymmetrical and is configured at compile time
+ for either master or slave mode (but not both). The basic I/O
+ functions look the same at both ends, but the internals are
+ different, along with the initialization steps.
+ </para>
+ <section>
+ <title>ao_packet_putchar</title>
<programlisting>
void
ao_packet_putchar(char c);
slave side, any pending data will be sent the next time
the master polls for data.
</para>
- </section>
- <section>
- <title>ao_packet_pollchar</title>
+ </section>
+ <section>
+ <title>ao_packet_pollchar</title>
<programlisting>
char
ao_packet_pollchar(void);
otherwise returns AO_READ_AGAIN. On the master side, if
this empties the buffer, it triggers a poll for more data.
</para>
- </section>
- <section>
- <title>ao_packet_slave_start</title>
+ </section>
+ <section>
+ <title>ao_packet_slave_start</title>
<programlisting>
void
ao_packet_slave_start(void);
This is available only on the slave side and starts a task
to listen for packet data.
</para>
- </section>
- <section>
- <title>ao_packet_slave_stop</title>
+ </section>
+ <section>
+ <title>ao_packet_slave_stop</title>
<programlisting>
void
ao_packet_slave_stop(void);
<para>
Disables the packet slave task, stopping the radio receiver.
</para>
- </section>
- <section>
- <title>ao_packet_slave_init</title>
+ </section>
+ <section>
+ <title>ao_packet_slave_init</title>
<programlisting>
void
ao_packet_slave_init(void);
that when packet slave mode is enabled, characters will
get send and received through the stdio functions.
</para>
- </section>
- <section>
- <title>ao_packet_master_init</title>
+ </section>
+ <section>
+ <title>ao_packet_master_init</title>
<programlisting>
void
ao_packet_master_init(void);
<para>
Adds the 'p' packet forward command to start packet mode.
</para>
+ </section>
</section>
</chapter>
</book>
-<?xml version="1.0" encoding="utf-8" ?>
+<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"/usr/share/xml/docbook/schema/dtd/4.5/docbookx.dtd">
<book>
<title>The Altus Metrum System</title>
- <subtitle>An Owner's Manual for TeleMetrum, TeleMini, TeleDongle and TeleBT Devices</subtitle>
+ <subtitle>An Owner's Manual for Altus Metrum Rocketry Electronics</subtitle>
<bookinfo>
<author>
<firstname>Bdale</firstname>
</para>
</legalnotice>
<revhistory>
+ <revision>
+ <revnumber>1.3</revnumber>
+ <date>12 November 2013</date>
+ <revremark>
+ Updated for software version 1.3. Version 1.3 adds support
+ for TeleMega, TeleMetrum v2.0, TeleMini v2.0 and EasyMini
+ and fixes bugs in AltosUI and the AltOS firmware.
+ </revremark>
+ </revision>
<revision>
<revnumber>1.2.1</revnumber>
<date>21 May 2013</date>
</revision>
</revhistory>
</bookinfo>
- <acknowledgements>
+ <dedication>
+ <title>Acknowledgments</title>
<para>
- Thanks to Bob Finch, W9YA, NAR 12965, TRA 12350 for writing "The
+ Thanks to Bob Finch, W9YA, NAR 12965, TRA 12350 for writing “The
Mere-Mortals Quick Start/Usage Guide to the Altus Metrum Starter
- Kit" which formed the basis of the original Getting Started chapter
+ Kit” which formed the basis of the original Getting Started chapter
in this manual. Bob was one of our first customers for a production
TeleMetrum, and his continued enthusiasm and contributions
are immensely gratifying and highly appreciated!
NAR #88757, TRA #12200
</literallayout>
</para>
- </acknowledgements>
+ </dedication>
<chapter>
<title>Introduction and Overview</title>
<para>
<para>
The first device created for our community was TeleMetrum, a dual
deploy altimeter with fully integrated GPS and radio telemetry
- as standard features, and a "companion interface" that will
- support optional capabilities in the future.
+ as standard features, and a “companion interface” that will
+ support optional capabilities in the future. The latest version
+ of TeleMetrum, v2.0, has all of the same features but with
+ improved sensors and radio to offer increased performance.
</para>
<para>
Our second device was TeleMini, a dual deploy altimeter with
- radio telemetry and radio direction finding. This device is only
- 13mm by 38mm (½ inch by 1½ inches) and can fit easily in an 18mm
- air-frame.
+ radio telemetry and radio direction finding. The first version
+ of this device was only 13mm by 38mm (½ inch by 1½ inches) and
+ could fit easily in an 18mm air-frame. The latest version, v2.0,
+ includes a beeper, USB data download and extended on-board
+ flight logging, along with an improved barometric sensor.
+ </para>
+ <para>
+ TeleMega is our most sophisticated device, including six pyro
+ channels (four of which are fully programmable), integrated GPS,
+ integrated gyroscopes for staging/air-start inhibit and high
+ performance telemetry.
+ </para>
+ <para>
+ EasyMini is a dual-deploy altimeter with logging and built-in
+ USB data download.
</para>
<para>
TeleDongle was our first ground station, providing a USB to RF
<para>
For a slightly more portable ground station experience that also
provides direct rocket recovery support, TeleBT offers flight
- monitoring and data logging using a Bluetooth connection between
- the receiver and an Android device that has the Altos Droid
+ monitoring and data logging using a Bluetooth™ connection between
+ the receiver and an Android device that has the AltosDroid
application installed from the Google Play store.
</para>
<para>
<title>Getting Started</title>
<para>
The first thing to do after you check the inventory of parts in your
- "starter kit" is to charge the battery.
+ “starter kit” is to charge the battery.
</para>
<para>
- The TeleMetrum battery can be charged by plugging it into the
- corresponding socket of the TeleMetrum and then using the USB A to
- mini B
- cable to plug the TeleMetrum into your computer's USB socket. The
- TeleMetrum circuitry will charge the battery whenever it is plugged
- in, because the TeleMetrum's on-off switch does NOT control the
+ For TeleMetrum and TeleMega, the battery can be charged by plugging it into the
+ corresponding socket of the device and then using the USB
+ cable to plug the flight computer into your computer's USB socket. The
+ on-board circuitry will charge the battery whenever it is plugged
+ in, because the on-off switch does NOT control the
charging circuitry.
</para>
<para>
- When the GPS chip is initially searching for
- satellites, TeleMetrum will consume more current than it can pull
- from the USB port, so the battery must be attached in order to get
- satellite lock. Once GPS is locked, the current consumption goes back
- down enough to enable charging while
- running. So it's a good idea to fully charge the battery as your
- first item of business so there is no issue getting and maintaining
- satellite lock. The yellow charge indicator led will go out when the
- battery is nearly full and the charger goes to trickle charge. It
- can take several hours to fully recharge a deeply discharged battery.
+ On TeleMetrum v1 boards, when the GPS chip is initially
+ searching for satellites, TeleMetrum will consume more current
+ than it pulls from the USB port, so the battery must be
+ attached in order to get satellite lock. Once GPS is locked,
+ the current consumption goes back down enough to enable charging
+ while running. So it's a good idea to fully charge the battery
+ as your first item of business so there is no issue getting and
+ maintaining satellite lock. The yellow charge indicator led
+ will go out when the battery is nearly full and the charger goes
+ to trickle charge. It can take several hours to fully recharge a
+ deeply discharged battery.
+ </para>
+ <para>
+ TeleMetrum v2.0 and TeleMega use a higher power battery charger,
+ allowing them to charge the battery while running the board at
+ maximum power. When the battery is charging, or when the board
+ is consuming a lot of power, the red LED will be lit. When the
+ battery is fully charged, the green LED will be lit. When the
+ battery is damaged or missing, both LEDs will be lit, which
+ appears yellow.
+ </para>
+ <para>
+ The Lithium Polymer TeleMini and EasyMini battery can be charged by
+ disconnecting it from the board and plugging it into a
+ standalone battery charger such as the LipoCharger product
+ included in TeleMini Starter Kits, and connecting that via a USB
+ cable to a laptop or other USB power source.
</para>
<para>
- The TeleMini battery can be charged by disconnecting it from the
- TeleMini board and plugging it into a standalone battery charger
- such as the LipoCharger product included in TeleMini Starter Kits,
- and connecting that via a USB cable to a laptop or other USB
- power source.
+ You can also choose to use another battery with TeleMini v2.0
+ and EasyMini, anything supplying between 4 and 12 volts should
+ work fine (like a standard 9V battery), but if you are planning
+ to fire pyro charges, ground testing is required to verify that
+ the battery supplies enough current to fire your chosen e-matches.
</para>
<para>
The other active device in the starter kit is the TeleDongle USB to
RF interface. If you plug it in to your Mac or Linux computer it should
- "just work", showing up as a serial port device. Windows systems need
+ “just work”, showing up as a serial port device. Windows systems need
driver information that is part of the AltOS download to know that the
existing USB modem driver will work. We therefore recommend installing
our software before plugging in TeleDongle if you are using a Windows
- computer. If you are using Linux and are having problems, try moving
- to a fresher kernel (2.6.33 or newer), as the USB serial driver had
- ugly bugs in some earlier versions.
+ computer. If you are using an older version of Linux and are having
+ problems, try moving to a fresher kernel (2.6.33 or newer).
</para>
<para>
- Next you should obtain and install the AltOS software. These include
- the AltosUI ground station program, current firmware images for
- TeleMetrum, TeleMini and TeleDongle, and a number of standalone
- utilities that are rarely needed. Pre-built binary packages are
- available for Linux, Microsoft Windows, and recent MacOSX versions.
- Full source code and build instructions are also available.
- The latest version may always be downloaded from
+ Next you should obtain and install the AltOS software. The AltOS
+ distribution includes the AltosUI ground station program, current
+ firmware
+ images for all of the hardware, and a number of standalone
+ utilities that are rarely needed. Pre-built binary packages are
+ available for Linux, Microsoft Windows, and recent MacOSX
+ versions. Full source code and build instructions are also
+ available. The latest version may always be downloaded from
<ulink url="http://altusmetrum.org/AltOS"/>.
</para>
<para>
- If you're using a TeleBT instead of the TeleDongle, you'll want
- to go install the Altos Droid application from the Google Play
- store. You don't need a data plan to use Altos Droid, but
+ If you're using a TeleBT instead of the TeleDongle, you'll want to
+ install the AltosDroid application from the Google Play store on an
+ Android device. You don't need a data plan to use AltosDroid, but
without network access, the Map view will be less useful as it
won't contain any map data. You can also use TeleBT connected
over USB with your laptop computer; it acts exactly like a
strapping them down, for example.
</para>
<para>
- The barometric sensors used on both TeleMetrum and TeleMini are
- sensitive to sunlight. In normal TeleMetrum mounting situations, it
+ The barometric sensors used on all of our flight computers are
+ sensitive to sunlight. In normal mounting situations, the baro sensor
and all of the other surface mount components
- are "down" towards whatever the underlying mounting surface is, so
- this is not normally a problem. Please consider this, though, when
- designing an installation, for example, in an air-frame with a
- see-through plastic payload bay. It is particularly important to
- consider this with TeleMini, both because the baro sensor is on the
- "top" of the board, and because many model rockets with payload bays
+ are “down” towards whatever the underlying mounting surface is, so
+ this is not normally a problem. Please consider this when designing an
+ installation in an air-frame with a see-through plastic payload bay. It
+ is particularly important to
+ consider this with TeleMini v1.0, both because the baro sensor is on the
+ “top” of the board, and because many model rockets with payload bays
use clear plastic for the payload bay! Replacing these with an opaque
cardboard tube, painting them, or wrapping them with a layer of masking
tape are all reasonable approaches to keep the sensor out of direct
sunlight.
</para>
<para>
- The barometric sensor sampling port must be able to "breathe",
+ The barometric sensor sampling port must be able to “breathe”,
both by not being covered by foam or tape or other materials that might
directly block the hole on the top of the sensor, and also by having a
suitable static vent to outside air.
</para>
</chapter>
<chapter>
- <title>Hardware Overview</title>
- <para>
- TeleMetrum is a 1 inch by 2.75 inch circuit board. It was designed to
- fit inside coupler for 29mm air-frame tubing, but using it in a tube that
- small in diameter may require some creativity in mounting and wiring
- to succeed! The presence of an accelerometer means TeleMetrum should
- be aligned along the flight axis of the airframe, and by default the 1/4
- wave UHF wire antenna should be on the nose-cone end of the board. The
- antenna wire is about 7 inches long, and wiring for a power switch and
- the e-matches for apogee and main ejection charges depart from the
- fin can end of the board, meaning an ideal "simple" avionics
- bay for TeleMetrum should have at least 10 inches of interior length.
- </para>
- <para>
- TeleMini is a 0.5 inch by 1.5 inch circuit board. It was designed to
- fit inside an 18mm air-frame tube, but using it in a tube that
- small in diameter may require some creativity in mounting and wiring
- to succeed! Since there is no accelerometer, TeleMini can be mounted
- in any convenient orientation. The default 1/4
- wave UHF wire antenna attached to the center of one end of
- the board is about 7 inches long, and wiring for a power switch and
- the e-matches for apogee and main ejection charges depart from the
- other end of the board, meaning an ideal "simple" avionics
- bay for TeleMini should have at least 9 inches of interior length.
- </para>
- <para>
- A typical TeleMetrum or TeleMini installation involves attaching
- only a suitable Lithium Polymer battery, a single pole switch for
- power on/off, and two pairs of wires connecting e-matches for the
- apogee and main ejection charges. All Altus Metrum products are
- designed for use with single-cell batteries with 3.7 volts nominal.
- </para>
- <para>
- The battery connectors are a standard 2-pin JST connector and
- match batteries sold by Spark Fun. These batteries are
- single-cell Lithium Polymer batteries that nominally provide 3.7
- volts. Other vendors sell similar batteries for RC aircraft
- using mating connectors, however the polarity for those is
- generally reversed from the batteries used by Altus Metrum
- products. In particular, the Tenergy batteries supplied for use
- in Featherweight flight computers are not compatible with Altus
- Metrum flight computers or battery chargers. <emphasis>Check
- polarity and voltage before connecting any battery not purchased
- from Altus Metrum or Spark Fun.</emphasis>
- </para>
- <para>
- By default, we use the unregulated output of the Li-Po battery directly
- to fire ejection charges. This works marvelously with standard
- low-current e-matches like the J-Tek from MJG Technologies, and with
- Quest Q2G2 igniters. However, if you want or need to use a separate
- pyro battery, check out the "External Pyro Battery" section in this
- manual for instructions on how to wire that up. The altimeters are
- designed to work with an external pyro battery of no more than 15 volts.
- </para>
- <para>
- Ejection charges are wired directly to the screw terminal block
- at the aft end of the altimeter. You'll need a very small straight
- blade screwdriver for these screws, such as you might find in a
- jeweler's screwdriver set.
- </para>
- <para>
- TeleMetrum also uses the screw terminal block for the power
- switch leads. On TeleMini, the power switch leads are soldered
- directly to the board and can be connected directly to a switch.
- </para>
- <para>
- For most air-frames, the integrated antennas are more than
- adequate. However, if you are installing in a carbon-fiber or
- metal electronics bay which is opaque to RF signals, you may need to
- use off-board external antennas instead. In this case, you can
- order an altimeter with an SMA connector for the UHF antenna
- connection, and, on TeleMetrum, you can unplug the integrated GPS
- antenna and select an appropriate off-board GPS antenna with
- cable terminating in a U.FL connector.
- </para>
+ <title>Altus Metrum Hardware</title>
+ <section>
+ <title>Overview</title>
+ <para>
+ Here's the full set of Altus Metrum products, both in
+ production and retired.
+ </para>
+ <table frame='all'>
+ <title>Altus Metrum Electronics</title>
+ <?dbfo keep-together="always"?>
+ <tgroup cols='8' align='center' colsep='1' rowsep='1'>
+ <colspec align='center' colwidth='*' colname='Device'/>
+ <colspec align='center' colwidth='*' colname='Barometer'/>
+ <colspec align='center' colwidth='*' colname='Z-axis accelerometer'/>
+ <colspec align='center' colwidth='*' colname='GPS'/>
+ <colspec align='center' colwidth='*' colname='3D sensors'/>
+ <colspec align='center' colwidth='*' colname='Storage'/>
+ <colspec align='center' colwidth='*' colname='RF'/>
+ <colspec align='center' colwidth='*' colname='Battery'/>
+ <thead>
+ <row>
+ <entry align='center'>Device</entry>
+ <entry align='center'>Barometer</entry>
+ <entry align='center'>Z-axis accelerometer</entry>
+ <entry align='center'>GPS</entry>
+ <entry align='center'>3D sensors</entry>
+ <entry align='center'>Storage</entry>
+ <entry align='center'>RF Output</entry>
+ <entry align='center'>Battery</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>TeleMetrum v1.0</entry>
+ <entry><para>MP3H6115 10km (33k')</para></entry>
+ <entry><para>MMA2202 50g</para></entry>
+ <entry>SkyTraq</entry>
+ <entry>-</entry>
+ <entry>1MB</entry>
+ <entry>10mW</entry>
+ <entry>3.7V</entry>
+ </row>
+ <row>
+ <entry>TeleMetrum v1.1</entry>
+ <entry><para>MP3H6115 10km (33k')</para></entry>
+ <entry><para>MMA2202 50g</para></entry>
+ <entry>SkyTraq</entry>
+ <entry>-</entry>
+ <entry>2MB</entry>
+ <entry>10mW</entry>
+ <entry>3.7V</entry>
+ </row>
+ <row>
+ <entry>TeleMetrum v1.2</entry>
+ <entry><para>MP3H6115 10km (33k')</para></entry>
+ <entry><para>ADXL78 70g</para></entry>
+ <entry>SkyTraq</entry>
+ <entry>-</entry>
+ <entry>2MB</entry>
+ <entry>10mW</entry>
+ <entry>3.7V</entry>
+ </row>
+ <row>
+ <entry>TeleMetrum v2.0</entry>
+ <entry><para>MS5607 30km (100k')</para></entry>
+ <entry><para>MMA6555 102g</para></entry>
+ <entry>uBlox Max-7Q</entry>
+ <entry>-</entry>
+ <entry>8MB</entry>
+ <entry>40mW</entry>
+ <entry>3.7V</entry>
+ </row>
+ <row>
+ <entry><para>TeleMini <?linebreak?>v1.0</para></entry>
+ <entry><para>MP3H6115 10km (33k')</para></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>5kB</entry>
+ <entry>10mW</entry>
+ <entry>3.7V</entry>
+ </row>
+ <row>
+ <entry>TeleMini <?linebreak?>v2.0</entry>
+ <entry><para>MS5607 30km (100k')</para></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>1MB</entry>
+ <entry>10mW</entry>
+ <entry>3.7-12V</entry>
+ </row>
+ <row>
+ <entry>EasyMini <?linebreak?>v1.0</entry>
+ <entry><para>MS5607 30km (100k')</para></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>1MB</entry>
+ <entry>-</entry>
+ <entry>3.7-12V</entry>
+ </row>
+ <row>
+ <entry>TeleMega <?linebreak?>v1.0</entry>
+ <entry><para>MS5607 30km (100k')</para></entry>
+ <entry><para>MMA6555 102g</para></entry>
+ <entry>uBlox Max-7Q</entry>
+ <entry><para>MPU6000 HMC5883</para></entry>
+ <entry>8MB</entry>
+ <entry>40mW</entry>
+ <entry>3.7V</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ <table frame='all'>
+ <title>Altus Metrum Boards</title>
+ <?dbfo keep-together="always"?>
+ <tgroup cols='6' align='center' colsep='1' rowsep='1'>
+ <colspec align='center' colwidth='*' colname='Device'/>
+ <colspec align='center' colwidth='*' colname='Connectors'/>
+ <colspec align='center' colwidth='*' colname='Screw Terminals'/>
+ <colspec align='center' colwidth='*' colname='Width'/>
+ <colspec align='center' colwidth='*' colname='Length'/>
+ <colspec align='center' colwidth='*' colname='Tube Size'/>
+ <thead>
+ <row>
+ <entry align='center'>Device</entry>
+ <entry align='center'>Connectors</entry>
+ <entry align='center'>Screw Terminals</entry>
+ <entry align='center'>Width</entry>
+ <entry align='center'>Length</entry>
+ <entry align='center'>Tube Size</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>TeleMetrum</entry>
+ <entry><para>
+ Antenna<?linebreak?>
+ Debug<?linebreak?>
+ Companion<?linebreak?>
+ USB<?linebreak?>
+ Battery
+ </para></entry>
+ <entry><para>Apogee pyro <?linebreak?>Main pyro <?linebreak?>Switch</para></entry>
+ <entry>1 inch (2.54cm)</entry>
+ <entry>2 ¾ inch (6.99cm)</entry>
+ <entry>29mm coupler</entry>
+ </row>
+ <row>
+ <entry><para>TeleMini <?linebreak?>v1.0</para></entry>
+ <entry><para>
+ Antenna<?linebreak?>
+ Debug<?linebreak?>
+ Battery
+ </para></entry>
+ <entry><para>
+ Apogee pyro <?linebreak?>
+ Main pyro
+ </para></entry>
+ <entry>½ inch (1.27cm)</entry>
+ <entry>1½ inch (3.81cm)</entry>
+ <entry>18mm coupler</entry>
+ </row>
+ <row>
+ <entry>TeleMini <?linebreak?>v2.0</entry>
+ <entry><para>
+ Antenna<?linebreak?>
+ Debug<?linebreak?>
+ USB<?linebreak?>
+ Battery
+ </para></entry>
+ <entry><para>
+ Apogee pyro <?linebreak?>
+ Main pyro <?linebreak?>
+ Battery <?linebreak?>
+ Switch
+ </para></entry>
+ <entry>0.8 inch (2.03cm)</entry>
+ <entry>1½ inch (3.81cm)</entry>
+ <entry>24mm coupler</entry>
+ </row>
+ <row>
+ <entry>EasyMini</entry>
+ <entry><para>
+ Debug<?linebreak?>
+ USB<?linebreak?>
+ Battery
+ </para></entry>
+ <entry><para>
+ Apogee pyro <?linebreak?>
+ Main pyro <?linebreak?>
+ Battery <?linebreak?>
+ Switch
+ </para></entry>
+ <entry>0.8 inch (2.03cm)</entry>
+ <entry>1½ inch (3.81cm)</entry>
+ <entry>24mm coupler</entry>
+ </row>
+ <row>
+ <entry>TeleMega</entry>
+ <entry><para>
+ Antenna<?linebreak?>
+ Debug<?linebreak?>
+ Companion<?linebreak?>
+ USB<?linebreak?>
+ Battery
+ </para></entry>
+ <entry><para>
+ Apogee pyro <?linebreak?>
+ Main pyro<?linebreak?>
+ Pyro A-D<?linebreak?>
+ Switch<?linebreak?>
+ Pyro battery
+ </para></entry>
+ <entry>1¼ inch (3.18cm)</entry>
+ <entry>3¼ inch (8.26cm)</entry>
+ <entry>38mm coupler</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </section>
+ <section>
+ <title>TeleMetrum</title>
+ <informalfigure>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="telemetrum-v1.1-thside.jpg" width="5.5in" scalefit="1"/>
+ </imageobject>
+ </mediaobject>
+ </informalfigure>
+ <para>
+ TeleMetrum is a 1 inch by 2¾ inch circuit board. It was designed to
+ fit inside coupler for 29mm air-frame tubing, but using it in a tube that
+ small in diameter may require some creativity in mounting and wiring
+ to succeed! The presence of an accelerometer means TeleMetrum should
+ be aligned along the flight axis of the airframe, and by default the ¼
+ wave UHF wire antenna should be on the nose-cone end of the board. The
+ antenna wire is about 7 inches long, and wiring for a power switch and
+ the e-matches for apogee and main ejection charges depart from the
+ fin can end of the board, meaning an ideal “simple” avionics
+ bay for TeleMetrum should have at least 10 inches of interior length.
+ </para>
+ </section>
+ <section>
+ <title>TeleMini</title>
+ <informalfigure>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="telemini-v1-top.jpg" width="5.5in" scalefit="1"/>
+ </imageobject>
+ </mediaobject>
+ </informalfigure>
+ <para>
+ TeleMini v1.0 is ½ inches by 1½ inches. It was
+ designed to fit inside an 18mm air-frame tube, but using it in
+ a tube that small in diameter may require some creativity in
+ mounting and wiring to succeed! Since there is no
+ accelerometer, TeleMini can be mounted in any convenient
+ orientation. The default ¼ wave UHF wire antenna attached to
+ the center of one end of the board is about 7 inches long. Two
+ wires for the power switch are connected to holes in the
+ middle of the board. Screw terminals for the e-matches for
+ apogee and main ejection charges depart from the other end of
+ the board, meaning an ideal “simple” avionics bay for TeleMini
+ should have at least 9 inches of interior length.
+ </para>
+ <informalfigure>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="telemini-v2-top.jpg" width="5.5in" scalefit="1"/>
+ </imageobject>
+ </mediaobject>
+ </informalfigure>
+ <para>
+ TeleMini v2.0 is 0.8 inches by 1½ inches. It adds more
+ on-board data logging memory, a built-in USB connector and
+ screw terminals for the battery and power switch. The larger
+ board fits in a 24mm coupler. There's also a battery connector
+ for a LiPo battery if you want to use one of those.
+ </para>
+ </section>
+ <section>
+ <title>EasyMini</title>
+ <informalfigure>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="easymini-top.jpg" width="5.5in" scalefit="1"/>
+ </imageobject>
+ </mediaobject>
+ </informalfigure>
+ <para>
+ EasyMini is built on a 0.8 inch by 1½ inch circuit board. It's
+ designed to fit in a 24mm coupler tube. The connectors and
+ screw terminals match TeleMini v2.0, so you can easily swap between
+ EasyMini and TeleMini.
+ </para>
+ </section>
+ <section>
+ <title>TeleMega</title>
+ <informalfigure>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="telemega-v1.0-top.jpg" width="5.5in" scalefit="1"/>
+ </imageobject>
+ </mediaobject>
+ </informalfigure>
+ <para>
+ TeleMega is a 1¼ inch by 3¼ inch circuit board. It was
+ designed to easily fit in a 38mm coupler. Like TeleMetrum,
+ TeleMega has an accelerometer and so it must be mounted so that
+ the board is aligned with the flight axis. It can be mounted
+ either antenna up or down.
+ </para>
+ </section>
+ <section>
+ <title>Flight Data Recording</title>
+ <para>
+ Each flight computer logs data at 100 samples per second
+ during ascent and 10 samples per second during descent, except
+ for TeleMini v1.0, which records ascent at 10 samples per
+ second and descent at 1 sample per second. Data are logged to
+ an on-board flash memory part, which can be partitioned into
+ several equal-sized blocks, one for each flight.
+ </para>
+ <table frame='all'>
+ <title>Data Storage on Altus Metrum altimeters</title>
+ <?dbfo keep-together="always"?>
+ <tgroup cols='4' align='center' colsep='1' rowsep='1'>
+ <colspec align='center' colwidth='*' colname='Device'/>
+ <colspec align='center' colwidth='*' colname='Bytes per sample'/>
+ <colspec align='center' colwidth='*' colname='Total storage'/>
+ <colspec align='center' colwidth='*' colname='Minutes of
+ full-rate'/>
+ <thead>
+ <row>
+ <entry align='center'>Device</entry>
+ <entry align='center'>Bytes per Sample</entry>
+ <entry align='center'>Total Storage</entry>
+ <entry align='center'>Minutes at Full Rate</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>TeleMetrum v1.0</entry>
+ <entry>8</entry>
+ <entry>1MB</entry>
+ <entry>20</entry>
+ </row>
+ <row>
+ <entry>TeleMetrum v1.1 v1.2</entry>
+ <entry>8</entry>
+ <entry>2MB</entry>
+ <entry>40</entry>
+ </row>
+ <row>
+ <entry>TeleMetrum v2.0</entry>
+ <entry>16</entry>
+ <entry>8MB</entry>
+ <entry>80</entry>
+ </row>
+ <row>
+ <entry>TeleMini v1.0</entry>
+ <entry>2</entry>
+ <entry>5kB</entry>
+ <entry>4</entry>
+ </row>
+ <row>
+ <entry>TeleMini v2.0</entry>
+ <entry>16</entry>
+ <entry>1MB</entry>
+ <entry>10</entry>
+ </row>
+ <row>
+ <entry>EasyMini</entry>
+ <entry>16</entry>
+ <entry>1MB</entry>
+ <entry>10</entry>
+ </row>
+ <row>
+ <entry>TeleMega</entry>
+ <entry>32</entry>
+ <entry>8MB</entry>
+ <entry>40</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ <para>
+ The on-board flash is partitioned into separate flight logs,
+ each of a fixed maximum size. Increase the maximum size of
+ each log and you reduce the number of flights that can be
+ stored. Decrease the size and you can store more flights.
+ </para>
+ <para>
+ Configuration data is also stored in the flash memory on
+ TeleMetrum v1.x, TeleMini and EasyMini. This consumes 64kB
+ of flash space. This configuration space is not available
+ for storing flight log data. TeleMetrum v2.0 and TeleMega
+ store configuration data in a bit of eeprom available within
+ the processor chip, leaving that space available in flash for
+ more flight data.
+ </para>
+ <para>
+ To compute the amount of space needed for a single flight, you
+ can multiply the expected ascent time (in seconds) by 100
+ times bytes-per-sample, multiply the expected descent time (in
+ seconds) by 10 times the bytes per sample and add the two
+ together. That will slightly under-estimate the storage (in
+ bytes) needed for the flight. For instance, a TeleMetrum v2.0 flight spending
+ 20 seconds in ascent and 150 seconds in descent will take
+ about (20 * 1600) + (150 * 160) = 56000 bytes of storage. You
+ could store dozens of these flights in the on-board flash.
+ </para>
+ <para>
+ The default size allows for several flights on each flight
+ computer, except for TeleMini v1.0, which only holds data for a
+ single flight. You can adjust the size.
+ </para>
+ <para>
+ Altus Metrum flight computers will not overwrite existing
+ flight data, so be sure to download flight data and erase it
+ from the flight computer before it fills up. The flight
+ computer will still successfully control the flight even if it
+ cannot log data, so the only thing you will lose is the data.
+ </para>
+ </section>
+ <section>
+ <title>Installation</title>
+ <para>
+ A typical installation involves attaching
+ only a suitable battery, a single pole switch for
+ power on/off, and two pairs of wires connecting e-matches for the
+ apogee and main ejection charges. All Altus Metrum products are
+ designed for use with single-cell batteries with 3.7 volts
+ nominal. TeleMini v2.0 and EasyMini may also be used with other
+ batteries as long as they supply between 4 and 12 volts.
+ </para>
+ <para>
+ The battery connectors are a standard 2-pin JST connector and
+ match batteries sold by Spark Fun. These batteries are
+ single-cell Lithium Polymer batteries that nominally provide 3.7
+ volts. Other vendors sell similar batteries for RC aircraft
+ using mating connectors, however the polarity for those is
+ generally reversed from the batteries used by Altus Metrum
+ products. In particular, the Tenergy batteries supplied for use
+ in Featherweight flight computers are not compatible with Altus
+ Metrum flight computers or battery chargers. <emphasis>Check
+ polarity and voltage before connecting any battery not purchased
+ from Altus Metrum or Spark Fun.</emphasis>
+ </para>
+ <para>
+ By default, we use the unregulated output of the battery directly
+ to fire ejection charges. This works marvelously with standard
+ low-current e-matches like the J-Tek from MJG Technologies, and with
+ Quest Q2G2 igniters. However, if you want or need to use a separate
+ pyro battery, check out the “External Pyro Battery” section in this
+ manual for instructions on how to wire that up. The altimeters are
+ designed to work with an external pyro battery of no more than 15 volts.
+
+ </para>
+ <para>
+ Ejection charges are wired directly to the screw terminal block
+ at the aft end of the altimeter. You'll need a very small straight
+ blade screwdriver for these screws, such as you might find in a
+ jeweler's screwdriver set.
+ </para>
+ <para>
+ Except for TeleMini v1.0, the flight computers also use the
+ screw terminal block for the power switch leads. On TeleMini v1.0,
+ the power switch leads are soldered directly to the board and
+ can be connected directly to a switch.
+ </para>
+ <para>
+ For most air-frames, the integrated antennas are more than
+ adequate. However, if you are installing in a carbon-fiber or
+ metal electronics bay which is opaque to RF signals, you may need to
+ use off-board external antennas instead. In this case, you can
+ replace the stock UHF antenna wire with an edge-launched SMA connector,
+ and, on TeleMetrum v1, you can unplug the integrated GPS
+ antenna and select an appropriate off-board GPS antenna with
+ cable terminating in a U.FL connector.
+ </para>
+ </section>
</chapter>
<chapter>
<title>System Operation</title>
<title>Firmware Modes </title>
<para>
The AltOS firmware build for the altimeters has two
- fundamental modes, "idle" and "flight". Which of these modes
+ fundamental modes, “idle” and “flight”. Which of these modes
the firmware operates in is determined at start up time. For
- TeleMetrum, the mode is controlled by the orientation of the
+ TeleMetrum and TeleMega, which have accelerometers, the mode is
+ controlled by the orientation of the
rocket (well, actually the board, of course...) at the time
- power is switched on. If the rocket is "nose up", then
- TeleMetrum assumes it's on a rail or rod being prepared for
+ power is switched on. If the rocket is “nose up”, then
+ the flight computer assumes it's on a rail or rod being prepared for
launch, so the firmware chooses flight mode. However, if the
rocket is more or less horizontal, the firmware instead enters
- idle mode. Since TeleMini doesn't have an accelerometer we can
- use to determine orientation, "idle" mode is selected when the
- board receives a command packet within the first five seconds
- of operation; if no packet is received, the board enters
- "flight" mode.
+ idle mode. Since TeleMini v2.0 and EasyMini don't have an
+ accelerometer we can use to determine orientation, “idle” mode
+ is selected if the board is connected via USB to a computer,
+ otherwise the board enters “flight” mode. TeleMini v1.0
+ selects “idle” mode if it receives a command packet within the
+ first five seconds of operation.
</para>
<para>
At power on, you will hear three beeps or see three flashes
- ("S" in Morse code for start up) and then a pause while
+ (“S” in Morse code for start up) and then a pause while
the altimeter completes initialization and self test, and decides
which mode to enter next.
</para>
<para>
- In flight or "pad" mode, the altimeter engages the flight
- state machine, goes into transmit-only mode to
- send telemetry, and waits for launch to be detected.
- Flight mode is indicated by an "di-dah-dah-dit" ("P" for pad)
- on the beeper or lights, followed by beeps or flashes
- indicating the state of the pyrotechnic igniter continuity.
- One beep/flash indicates apogee continuity, two beeps/flashes
- indicate main continuity, three beeps/flashes indicate both
- apogee and main continuity, and one longer "brap" sound or
- rapidly alternating lights indicates no continuity. For a
+ Here's a short summary of all of the modes and the beeping (or
+ flashing, in the case of TeleMini v1) that accompanies each
+ mode. In the description of the beeping pattern, “dit” means a
+ short beep while "dah" means a long beep (three times as
+ long). “Brap” means a long dissonant tone.
+ <table frame='all'>
+ <title>AltOS Modes</title>
+ <?dbfo keep-together="always"?>
+ <tgroup cols='4' align='center' colsep='1' rowsep='1'>
+ <colspec align='center' colwidth='*' colname='Mode Name'/>
+ <colspec align='center' colwidth='*' colname='Letter'/>
+ <colspec align='center' colwidth='*' colname='Beeps'/>
+ <colspec align='center' colwidth='*' colname='Description'/>
+ <thead>
+ <row>
+ <entry>Mode Name</entry>
+ <entry>Abbreviation</entry>
+ <entry>Beeps</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>Startup</entry>
+ <entry>S</entry>
+ <entry>dit dit dit</entry>
+ <entry>
+ <para>
+ Calibrating sensors, detecting orientation.
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>Idle</entry>
+ <entry>I</entry>
+ <entry>dit dit</entry>
+ <entry>
+ <para>
+ Ready to accept commands over USB or radio link.
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>Pad</entry>
+ <entry>P</entry>
+ <entry>dit dah dah dit</entry>
+ <entry>
+ <para>
+ Waiting for launch. Not listening for commands.
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>Boost</entry>
+ <entry>B</entry>
+ <entry>dah dit dit dit</entry>
+ <entry>
+ <para>
+ Accelerating upwards.
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>Fast</entry>
+ <entry>F</entry>
+ <entry>dit dit dah dit</entry>
+ <entry>
+ <para>
+ Decellerating, but moving faster than 200m/s.
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>Coast</entry>
+ <entry>C</entry>
+ <entry>dah dit dah dit</entry>
+ <entry>
+ <para>
+ Decellerating, moving slower than 200m/s
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>Drogue</entry>
+ <entry>D</entry>
+ <entry>dah dit dit</entry>
+ <entry>
+ <para>
+ Descending after apogee. Above main height.
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>Main</entry>
+ <entry>M</entry>
+ <entry>dah dah</entry>
+ <entry>
+ <para>
+ Descending. Below main height.
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>Landed</entry>
+ <entry>L</entry>
+ <entry>dit dah dit dit</entry>
+ <entry>
+ <para>
+ Stable altitude for at least ten seconds.
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>Sensor error</entry>
+ <entry>X</entry>
+ <entry>dah dit dit dah</entry>
+ <entry>
+ <para>
+ Error detected during sensor calibration.
+ </para>
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </para>
+ <para>
+ In flight or “pad” mode, the altimeter engages the flight
+ state machine, goes into transmit-only mode to send telemetry,
+ and waits for launch to be detected. Flight mode is indicated
+ by an “di-dah-dah-dit” (“P” for pad) on the beeper or lights,
+ followed by beeps or flashes indicating the state of the
+ pyrotechnic igniter continuity. One beep/flash indicates
+ apogee continuity, two beeps/flashes indicate main continuity,
+ three beeps/flashes indicate both apogee and main continuity,
+ and one longer “brap” sound which is made by rapidly
+ alternating between two tones indicates no continuity. For a
dual deploy flight, make sure you're getting three beeps or
flashes before launching! For apogee-only or motor eject
flights, do what makes sense.
</para>
<para>
- If idle mode is entered, you will hear an audible "di-dit" or
- see two short flashes ("I" for idle), and the flight state
+ If idle mode is entered, you will hear an audible “di-dit” or
+ see two short flashes (“I” for idle), and the flight state
machine is disengaged, thus no ejection charges will fire.
The altimeters also listen for the radio link when in idle
mode for requests sent via TeleDongle. Commands can be issued
- to a TeleMetrum in idle mode over either USB or the radio link
- equivalently. TeleMini only has the radio link. Idle mode is
- useful for configuring the altimeter, for extracting data from
- the on-board storage chip after flight, and for ground testing
- pyro charges.
+ in idle mode over either USB or the radio link
+ equivalently. TeleMini v1.0 only has the radio link. Idle
+ mode is useful for configuring the altimeter, for extracting
+ data from the on-board storage chip after flight, and for
+ ground testing pyro charges.
+ </para>
+ <para>
+ In “Idle” and “Pad” modes, once the mode indication
+ beeps/flashes and continuity indication has been sent, if
+ there is no space available to log the flight in on-board
+ memory, the flight computer will emit a warbling tone (much
+ slower than the “no continuity tone”)
+ </para>
+ <para>
+ Here's a summary of all of the “pad” and “idle” mode indications.
+ <table frame='all'>
+ <title>Pad/Idle Indications</title>
+ <?dbfo keep-together="always"?>
+ <tgroup cols='3' align='center' colsep='1' rowsep='1'>
+ <colspec align='center' colwidth='*' colname='Name'/>
+ <colspec align='center' colwidth='*' colname='Beeps'/>
+ <colspec align='center' colwidth='*' colname='Description'/>
+ <thead>
+ <row>
+ <entry>Name</entry>
+ <entry>Beeps</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>Neither</entry>
+ <entry>brap</entry>
+ <entry>
+ <para>
+ No continuity detected on either apogee or main
+ igniters.
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>Apogee</entry>
+ <entry>dit</entry>
+ <entry>
+ <para>
+ Continuity detected only on apogee igniter.
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>Main</entry>
+ <entry>dit dit</entry>
+ <entry>
+ <para>
+ Continuity detected only on main igniter.
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>Both</entry>
+ <entry>dit dit dit</entry>
+ <entry>
+ <para>
+ Continuity detected on both igniters.
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>Storage Full</entry>
+ <entry>warble</entry>
+ <entry>
+ <para>
+ On-board data logging storage is full. This will
+ not prevent the flight computer from safely
+ controlling the flight or transmitting telemetry
+ signals, but no record of the flight will be
+ stored in on-board flash.
+ </para>
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </para>
+ <para>
+ Once landed, the flight computer will signal that by emitting
+ the “Landed” sound described above, after which it will beep
+ out the apogee height (in meters). Each digit is represented
+ by a sequence of short “dit” beeps, with a pause between
+ digits. A zero digit is represented with one long “dah”
+ beep. The flight computer will continue to report landed mode
+ and beep out the maximum height until turned off.
</para>
<para>
- One "neat trick" of particular value when TeleMetrum is used with
+ One “neat trick” of particular value when TeleMetrum or TeleMega are used with
very large air-frames, is that you can power the board up while the
rocket is horizontal, such that it comes up in idle mode. Then you can
raise the air-frame to launch position, and issue a 'reset' command
installing igniters!
</para>
<para>
- TeleMini is configured via the radio link. Of course, that
+ TeleMini v1.0 is configured solely via the radio link. Of course, that
means you need to know the TeleMini radio configuration values
or you won't be able to communicate with it. For situations
- when you don't have the radio configuration values, TeleMini
+ when you don't have the radio configuration values, TeleMini v1.0
offers an 'emergency recovery' mode. In this mode, TeleMini is
configured as follows:
<itemizedlist>
<listitem>
+ <para>
Sets the radio frequency to 434.550MHz
+ </para>
</listitem>
<listitem>
+ <para>
Sets the radio calibration back to the factory value.
+ </para>
</listitem>
<listitem>
+ <para>
Sets the callsign to N0CALL
+ </para>
</listitem>
<listitem>
+ <para>
Does not go to 'pad' mode after five seconds.
+ </para>
</listitem>
</itemizedlist>
</para>
<section>
<title>GPS </title>
<para>
- TeleMetrum includes a complete GPS receiver. A complete explanation
- of how GPS works is beyond the scope of this manual, but the bottom
- line is that the TeleMetrum GPS receiver needs to lock onto at least
- four satellites to obtain a solid 3 dimensional position fix and know
- what time it is.
+ TeleMetrum and TeleMega include a complete GPS receiver. A
+ complete explanation of how GPS works is beyond the scope of
+ this manual, but the bottom line is that the GPS receiver
+ needs to lock onto at least four satellites to obtain a solid
+ 3 dimensional position fix and know what time it is.
</para>
<para>
- TeleMetrum provides backup power to the GPS chip any time a
- battery is connected. This allows the receiver to "warm start" on
+ The flight computers provide backup power to the GPS chip any time a
+ battery is connected. This allows the receiver to “warm start” on
the launch rail much faster than if every power-on were a GPS
- "cold start". In typical operations, powering up TeleMetrum
+ “cold start”. In typical operations, powering up
on the flight line in idle mode while performing final air-frame
preparation will be sufficient to allow the GPS receiver to cold
start and acquire lock. Then the board can be powered down during
computer.
</para>
<para>
- Any operation which can be performed with TeleMetrum can
- either be done with TeleMetrum directly connected to the
+ Any operation which can be performed with a flight computer can
+ either be done with the device directly connected to the
computer via the USB cable, or through the radio
- link. TeleMini doesn't provide a USB connector and so it is
+ link. TeleMini v1.0 doesn't provide a USB connector and so it is
always communicated with over radio. Select the appropriate
TeleDongle device when the list of devices is presented and
AltosUI will interact with an altimeter over the radio link.
</listitem>
<listitem>
<para>
- Configure altimeter apogee delays or main deploy heights
+ Configure altimeter apogee delays, main deploy heights
+ and additional pyro event conditions
to respond to changing launch conditions. You can also
'reboot' the altimeter. Use this to remotely enable the
- flight computer by turning TeleMetrum on in "idle" mode,
+ flight computer by turning TeleMetrum or TeleMega on in “idle” mode,
then once the air-frame is oriented for launch, you can
reboot the altimeter and have it restart in pad mode
without having to climb the scary ladder.
<listitem>
<para>
Fire Igniters—Test your deployment charges without snaking
- wires out through holes in the air-frame. Simply assembly the
+ wires out through holes in the air-frame. Simply assemble the
rocket as if for flight with the apogee and main charges
loaded, then remotely command the altimeter to fire the
igniters.
close the window before performing other desired radio operations.
</para>
<para>
- TeleMetrum only enables radio commanding in 'idle' mode, so
- make sure you have TeleMetrum lying horizontally when you turn
- it on. Otherwise, TeleMetrum will start in 'pad' mode ready for
+ The flight computers only enable radio commanding in 'idle' mode.
+ TeleMetrum and TeleMega use the accelerometer to detect which orientation they
+ start up in, so make sure you have the flight computer lying horizontally when you turn
+ it on. Otherwise, it will start in 'pad' mode ready for
flight, and will not be listening for command packets from TeleDongle.
</para>
<para>
An important aspect of preparing a rocket using electronic deployment
for flight is ground testing the recovery system. Thanks
to the bi-directional radio link central to the Altus Metrum system,
- this can be accomplished in a TeleMetrum or TeleMini equipped rocket
+ this can be accomplished in a TeleMega, TeleMetrum or TeleMini equipped rocket
with less work than you may be accustomed to with other systems. It
can even be fun!
</para>
<para>
Just prep the rocket for flight, then power up the altimeter
- in "idle" mode (placing air-frame horizontal for TeleMetrum or
- selected the Configure Altimeter tab for TeleMini). This will cause
- the firmware to go into "idle" mode, in which the normal flight
+ in “idle” mode (placing air-frame horizontal for TeleMetrum or TeleMega, or
+ selecting the Configure Altimeter tab for TeleMini). This will cause
+ the firmware to go into “idle” mode, in which the normal flight
state machine is disabled and charges will not fire without
manual command. You can now command the altimeter to fire the apogee
or main charges from a safe distance using your computer and
<section>
<title>Radio Link </title>
<para>
- The chip our boards are based on incorporates an RF transceiver, but
+ Our flight computers all incorporate an RF transceiver, but
it's not a full duplex system... each end can only be transmitting or
receiving at any given moment. So we had to decide how to manage the
link.
</para>
<para>
By design, the altimeter firmware listens for the radio link when
- it's in "idle mode", which
+ it's in “idle mode”, which
allows us to use the radio link to configure the rocket, do things like
ejection tests, and extract data after a flight without having to
- crack open the air-frame. However, when the board is in "flight
- mode", the altimeter only
+ crack open the air-frame. However, when the board is in “flight
+ mode”, the altimeter only
transmits and doesn't listen at all. That's because we want to put
ultimate priority on event detection and getting telemetry out of
the rocket through
data later...
</para>
<para>
- We don't use a 'normal packet radio' mode like APRS because they're
- just too inefficient. The GFSK modulation we use is FSK with the
- base-band pulses passed through a
- Gaussian filter before they go into the modulator to limit the
- transmitted bandwidth. When combined with the hardware forward error
- correction support in the cc1111 chip, this allows us to have a very
- robust 38.4 kilobit data link with only 10 milliwatts of transmit
- power, a whip antenna in the rocket, and a hand-held Yagi on the
- ground. We've had flights to above 21k feet AGL with great reception,
- and calculations suggest we should be good to well over 40k feet AGL
- with a 5-element yagi on the ground. We hope to fly boards to higher
- altitudes over time, and would of course appreciate customer feedback
- on performance in higher altitude flights!
+ We don't generally use a 'normal packet radio' mode like APRS
+ because they're just too inefficient. The GFSK modulation we
+ use is FSK with the base-band pulses passed through a Gaussian
+ filter before they go into the modulator to limit the
+ transmitted bandwidth. When combined with forward error
+ correction and interleaving, this allows us to have a very
+ robust 19.2 kilobit data link with only 10-40 milliwatts of
+ transmit power, a whip antenna in the rocket, and a hand-held
+ Yagi on the ground. We've had flights to above 21k feet AGL
+ with great reception, and calculations suggest we should be
+ good to well over 40k feet AGL with a 5-element yagi on the
+ ground with our 10mW units and over 100k feet AGL with the
+ 40mW devices. We hope to fly boards to higher altitudes over
+ time, and would of course appreciate customer feedback on
+ performance in higher altitude flights!
+ </para>
+ <para>
+ TeleMetrum v2.0 and TeleMega can send APRS if desired, and the
+ interval between APRS packets can be configured. As each APRS
+ packet takes a full second to transmit, we recommend an
+ interval of at least 5 seconds to avoid consuming too much
+ battery power or radio channel bandwidth.
</para>
</section>
<section>
<title>Configurable Parameters</title>
<para>
Configuring an Altus Metrum altimeter for flight is very
- simple. Even on our baro-only TeleMini board, the use of a Kalman
- filter means there is no need to set a "mach delay". The few
+ simple. Even on our baro-only TeleMini and EasyMini boards, the use of a Kalman
+ filter means there is no need to set a “mach delay”. The few
configurable parameters can all be set using AltosUI over USB or
or radio link via TeleDongle.
</para>
<para>
Altus Metrum boards support radio frequencies in the 70cm
band. By default, the configuration interface provides a
- list of 10 "standard" frequencies in 100kHz channels starting at
+ list of 10 “standard” frequencies in 100kHz channels starting at
434.550MHz. However, the firmware supports use of
any 50kHz multiple within the 70cm band. At any given
launch, we highly recommend coordinating when and by whom each
<section>
<title>Maximum Flight Log</title>
<para>
- TeleMetrum version 1.1 and 1.2 have 2MB of on-board flash storage,
- enough to hold over 40 minutes of data at full data rate
- (100 samples/second). TeleMetrum 1.0 has 1MB of on-board
- storage. As data are stored at a reduced rate during descent
- (10 samples/second), there's plenty of space to store many
- flights worth of data.
- </para>
- <para>
- The on-board flash is partitioned into separate flight logs,
- each of a fixed maximum size. Increase the maximum size of
- each log and you reduce the number of flights that can be
- stored. Decrease the size and TeleMetrum can store more
- flights.
- </para>
- <para>
- All of the configuration data is also stored in the flash
- memory, which consumes 64kB on TeleMetrum v1.1/v1.2 and 256B on
- TeleMetrum v1.0. This configuration space is not available
- for storing flight log data.
- </para>
- <para>
- To compute the amount of space needed for a single flight,
- you can multiply the expected ascent time (in seconds) by
- 800, multiply the expected descent time (in seconds) by 80
- and add the two together. That will slightly under-estimate
- the storage (in bytes) needed for the flight. For instance,
- a flight spending 20 seconds in ascent and 150 seconds in
- descent will take about (20 * 800) + (150 * 80) = 28000
- bytes of storage. You could store dozens of these flights in
- the on-board flash.
+ Changing this value will set the maximum amount of flight
+ log storage that an individual flight will use. The
+ available storage is divided into as many flights of the
+ specified size as can fit in the available space. You can
+ download and erase individual flight logs. If you fill up
+ the available storage, future flights will not get logged
+ until you erase some of the stored ones.
</para>
<para>
- The default size, 192kB, allows for 10 flights of storage on
- TeleMetrum v1.1/v1.2 and 5 flights on TeleMetrum v1.0. This
- ensures that you won't need to erase the memory before
- flying each time while still allowing more than sufficient
- storage for each flight.
- </para>
- <para>
- As TeleMini does not contain an accelerometer, it stores
- data at 10 samples per second during ascent and one sample
- per second during descent. Each sample is a two byte reading
- from the barometer. These are stored in 5kB of
- on-chip flash memory which can hold 256 seconds at the
- ascent rate or 2560 seconds at the descent rate. Because of
- the limited storage, TeleMini cannot hold data for more than
- one flight, and so must be erased after each flight or it
- will not capture data for subsequent flights.
+ Even though our flight computers (except TeleMini v1.0) can store
+ multiple flights, we strongly recommend downloading and saving
+ flight data after each flight.
</para>
</section>
<section>
Instead of firing one charge at apogee and another charge at
a fixed height above the ground, you can configure the
altimeter to fire both at apogee or both during
- descent. This was added to support an airframe that has two
- TeleMetrum computers, one in the fin can and one in the
- nose.
+ descent. This was added to support an airframe Bdale designed that
+ had two altimeters, one in the fin can and one in the nose.
</para>
<para>
Providing the ability to use both igniters for apogee or
<section>
<title>Pad Orientation</title>
<para>
- TeleMetrum measures acceleration along the axis of the
- board. Which way the board is oriented affects the sign of
- the acceleration value. Instead of trying to guess which way
- the board is mounted in the air frame, TeleMetrum must be
- explicitly configured for either Antenna Up or Antenna
- Down. The default, Antenna Up, expects the end of the
- TeleMetrum board connected to the 70cm antenna to be nearest
- the nose of the rocket, with the end containing the screw
+ TeleMetrum and TeleMega measure acceleration along the axis
+ of the board. Which way the board is oriented affects the
+ sign of the acceleration value. Instead of trying to guess
+ which way the board is mounted in the air frame, the
+ altimeter must be explicitly configured for either Antenna
+ Up or Antenna Down. The default, Antenna Up, expects the end
+ of the board connected to the 70cm antenna to be nearest the
+ nose of the rocket, with the end containing the screw
terminals nearest the tail.
</para>
</section>
+ <section>
+ <title>Configurable Pyro Channels</title>
+ <para>
+ In addition to the usual Apogee and Main pyro channels,
+ TeleMega has four additional channels that can be configured
+ to activate when various flight conditions are
+ satisfied. You can select as many conditions as necessary;
+ all of them must be met in order to activate the
+ channel. The conditions available are:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ Acceleration away from the ground. Select a value, and
+ then choose whether acceleration should be above or
+ below that value. Acceleration is positive upwards, so
+ accelerating towards the ground would produce negative
+ numbers. Acceleration during descent is noisy and
+ inaccurate, so be careful when using it during these
+ phases of the flight.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Vertical speed. Select a value, and then choose whether
+ vertical speed should be above or below that
+ value. Speed is positive upwards, so moving towards the
+ ground would produce negative numbers. Speed during
+ descent is a bit noisy and so be careful when using it
+ during these phases of the flight.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Height. Select a value, and then choose whether the
+ height above the launch pad should be above or below
+ that value.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Orientation. TeleMega contains a 3-axis gyroscope and
+ accelerometer which is used to measure the current
+ angle. Note that this angle is not the change in angle
+ from the launch pad, but rather absolute relative to
+ gravity; the 3-axis accelerometer is used to compute the
+ angle of the rocket on the launch pad and initialize the
+ system. Because this value is computed by integrating
+ rate gyros, it gets progressively less accurate as the
+ flight goes on. It should have an accumulated error of
+ less than 0.2°/second (after 10 seconds of flight, the
+ error should be less than 2°).
+ </para>
+ <para>
+ The usual use of the orientation configuration is to
+ ensure that the rocket is traveling mostly upwards when
+ deciding whether to ignite air starts or additional
+ stages. For that, choose a reasonable maximum angle
+ (like 20°) and set the motor igniter to require an angle
+ of less than that value.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Flight Time. Time since boost was detected. Select a
+ value and choose whether to activate the pyro channel
+ before or after that amount of time.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Ascending. A simple test saying whether the rocket is
+ going up or not. This is exactly equivalent to testing
+ whether the speed is > 0.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Descending. A simple test saying whether the rocket is
+ going down or not. This is exactly equivalent to testing
+ whether the speed is < 0.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ After Motor. The flight software counts each time the
+ rocket starts accelerating (presumably due to a motor or
+ motors igniting). Use this value to count ignitions for
+ multi-staged or multi-airstart launches.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Delay. This value doesn't perform any checks, instead it
+ inserts a delay between the time when the other
+ parameters become true and when the pyro channel is
+ activated.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Flight State. The flight software tracks the flight
+ through a sequence of states:
+ <orderedlist>
+ <listitem>
+ <para>
+ Boost. The motor has lit and the rocket is
+ accelerating upwards.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Fast. The motor has burned out and the rocket is
+ descellerating, but it is going faster than 200m/s.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Coast. The rocket is still moving upwards and
+ decelerating, but the speed is less than 200m/s.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Drogue. The rocket has reached apogee and is heading
+ back down, but is above the configured Main
+ altitude.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Main. The rocket is still descending, and is below
+ the Main altitude
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Landed. The rocket is no longer moving.
+ </para>
+ </listitem>
+ </orderedlist>
+ </para>
+ <para>
+ You can select a state to limit when the pyro channel
+ may activate; note that the check is based on when the
+ rocket transitions <emphasis>into</emphasis> the state, and so checking for
+ “greater than Boost” means that the rocket is currently
+ in boost or some later state.
+ </para>
+ <para>
+ When a motor burns out, the rocket enters either Fast or
+ Coast state (depending on how fast it is moving). If the
+ computer detects upwards acceleration again, it will
+ move back to Boost state.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </section>
</section>
</chapter>
<chapter>
-
<title>AltosUI</title>
+ <informalfigure>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="altosui.png" width="5.5in"/>
+ </imageobject>
+ </mediaobject>
+ </informalfigure>
<para>
The AltosUI program provides a graphical user interface for
- interacting with the Altus Metrum product family, including
- TeleMetrum, TeleMini and TeleDongle. AltosUI can monitor telemetry data,
- configure TeleMetrum, TeleMini and TeleDongle devices and many other
+ interacting with the Altus Metrum product family. AltosUI can
+ monitor telemetry data, configure devices and many other
tasks. The primary interface window provides a selection of
- buttons, one for each major activity in the system. This manual
- is split into chapters, each of which documents one of the tasks
+ buttons, one for each major activity in the system. This chapter
+ is split into sections, each of which documents one of the tasks
provided from the top-level toolbar.
</para>
<section>
AltosUI will create a window to display telemetry data as
received by the selected TeleDongle device.
</para>
+ <informalfigure>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="device-selection.png" width="3.5in"/>
+ </imageobject>
+ </mediaobject>
+ </informalfigure>
<para>
All telemetry data received are automatically recorded in
suitable log files. The name of the files includes the current
</para>
<section>
<title>Launch Pad</title>
+ <informalfigure>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="launch-pad.png" width="5.5in"/>
+ </imageobject>
+ </mediaobject>
+ </informalfigure>
<para>
The 'Launch Pad' tab shows information used to decide when the
rocket is ready for flight. The first elements include red/green
indicators, if any of these is red, you'll want to evaluate
whether the rocket is ready to launch:
- <itemizedlist>
- <listitem>
- <para>
- Battery Voltage. This indicates whether the Li-Po battery
- powering the TeleMetrum has sufficient charge to last for
- the duration of the flight. A value of more than
- 3.7V is required for a 'GO' status.
- </para>
- </listitem>
- <listitem>
- <para>
- Apogee Igniter Voltage. This indicates whether the apogee
- igniter has continuity. If the igniter has a low
- resistance, then the voltage measured here will be close
- to the Li-Po battery voltage. A value greater than 3.2V is
- required for a 'GO' status.
- </para>
- </listitem>
- <listitem>
- <para>
- Main Igniter Voltage. This indicates whether the main
- igniter has continuity. If the igniter has a low
- resistance, then the voltage measured here will be close
- to the Li-Po battery voltage. A value greater than 3.2V is
- required for a 'GO' status.
- </para>
- </listitem>
- <listitem>
- <para>
- On-board Data Logging. This indicates whether there is
- space remaining on-board to store flight data for the
- upcoming flight. If you've downloaded data, but failed
- to erase flights, there may not be any space
- left. TeleMetrum can store multiple flights, depending
- on the configured maximum flight log size. TeleMini
- stores only a single flight, so it will need to be
- downloaded and erased after each flight to capture
- data. This only affects on-board flight logging; the
- altimeter will still transmit telemetry and fire
- ejection charges at the proper times.
- </para>
- </listitem>
- <listitem>
- <para>
- GPS Locked. For a TeleMetrum device, this indicates whether the GPS receiver is
- currently able to compute position information. GPS requires
- at least 4 satellites to compute an accurate position.
- </para>
- </listitem>
- <listitem>
- <para>
- GPS Ready. For a TeleMetrum device, this indicates whether GPS has reported at least
- 10 consecutive positions without losing lock. This ensures
- that the GPS receiver has reliable reception from the
- satellites.
- </para>
- </listitem>
- </itemizedlist>
- <para>
- The Launchpad tab also shows the computed launch pad position
- and altitude, averaging many reported positions to improve the
- accuracy of the fix.
- </para>
+ <variablelist>
+ <varlistentry>
+ <term>Battery Voltage</term>
+ <listitem>
+ <para>
+ This indicates whether the Li-Po battery powering the
+ flight computer has sufficient charge to last for
+ the duration of the flight. A value of more than
+ 3.8V is required for a 'GO' status.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Apogee Igniter Voltage</term>
+ <listitem>
+ <para>
+ This indicates whether the apogee
+ igniter has continuity. If the igniter has a low
+ resistance, then the voltage measured here will be close
+ to the Li-Po battery voltage. A value greater than 3.2V is
+ required for a 'GO' status.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Main Igniter Voltage</term>
+ <listitem>
+ <para>
+ This indicates whether the main
+ igniter has continuity. If the igniter has a low
+ resistance, then the voltage measured here will be close
+ to the Li-Po battery voltage. A value greater than 3.2V is
+ required for a 'GO' status.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>On-board Data Logging</term>
+ <listitem>
+ <para>
+ This indicates whether there is
+ space remaining on-board to store flight data for the
+ upcoming flight. If you've downloaded data, but failed
+ to erase flights, there may not be any space
+ left. Most of our flight computers can store multiple
+ flights, depending on the configured maximum flight log
+ size. TeleMini v1.0 stores only a single flight, so it
+ will need to be
+ downloaded and erased after each flight to capture
+ data. This only affects on-board flight logging; the
+ altimeter will still transmit telemetry and fire
+ ejection charges at the proper times even if the flight
+ data storage is full.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>GPS Locked</term>
+ <listitem>
+ <para>
+ For a TeleMetrum or TeleMega device, this indicates whether the GPS receiver is
+ currently able to compute position information. GPS requires
+ at least 4 satellites to compute an accurate position.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>GPS Ready</term>
+ <listitem>
+ <para>
+ For a TeleMetrum or TeleMega device, this indicates whether GPS has reported at least
+ 10 consecutive positions without losing lock. This ensures
+ that the GPS receiver has reliable reception from the
+ satellites.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
</para>
+ <para>
+ The Launchpad tab also shows the computed launch pad position
+ and altitude, averaging many reported positions to improve the
+ accuracy of the fix.
+ </para>
</section>
<section>
<title>Ascent</title>
+ <informalfigure>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="ascent.png" width="5.5in"/>
+ </imageobject>
+ </mediaobject>
+ </informalfigure>
<para>
This tab is shown during Boost, Fast and Coast
phases. The information displayed here helps monitor the
flight.
</para>
<para>
- The current latitude and longitude reported by the TeleMetrum GPS are
+ The current latitude and longitude reported by the GPS are
also shown. Note that under high acceleration, these values
may not get updated as the GPS receiver loses position
fix. Once the rocket starts coasting, the receiver should
</section>
<section>
<title>Descent</title>
+ <informalfigure>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="descent.png" width="5.5in"/>
+ </imageobject>
+ </mediaobject>
+ </informalfigure>
<para>
Once the rocket has reached apogee and (we hope) activated the
apogee charge, attention switches to tracking the rocket on
be below 10m/s when under the main parachute in a dual-deploy flight.
</para>
<para>
- For TeleMetrum altimeters, you can locate the rocket in the
+ With GPS-equipped flight computers, you can locate the rocket in the
sky using the elevation and bearing information to figure
out where to look. Elevation is in degrees above the
horizon. Bearing is reported in degrees relative to true
</section>
<section>
<title>Landed</title>
+ <informalfigure>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="landed.png" width="5.5in"/>
+ </imageobject>
+ </mediaobject>
+ </informalfigure>
<para>
Once the rocket is on the ground, attention switches to
recovery. While the radio signal is often lost once the
unit and have that compute a track to the landing location.
</para>
<para>
- Both TeleMini and TeleMetrum will continue to transmit RDF
+ Our flight computers will continue to transmit RDF
tones after landing, allowing you to locate the rocket by
following the radio signal if necessary. You may need to get
away from the clutter of the flight line, or even get up on
during the flight are displayed for your admiring observers.
The accuracy of these immediate values depends on the quality
of your radio link and how many packets were received.
- Recovering the on-board data after flight will likely yield
+ Recovering the on-board data after flight may yield
more precise results.
</para>
<para>
graph window for the current flight.
</para>
</section>
+ <section>
+ <title>Table</title>
+ <informalfigure>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="table.png" width="5.5in"/>
+ </imageobject>
+ </mediaobject>
+ </informalfigure>
+ <para>
+ The table view shows all of the data available from the
+ flight computer. Probably the most useful data on
+ this tab is the detailed GPS information, which includes
+ horizontal dilution of precision information, and
+ information about the signal being received from the satellites.
+ </para>
+ </section>
<section>
<title>Site Map</title>
+ <informalfigure>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="site-map.png" width="5.5in"/>
+ </imageobject>
+ </mediaobject>
+ </informalfigure>
<para>
When the TeleMetrum has a GPS fix, the Site Map tab will map
the rocket's position to make it easier for you to locate the
system can handle, and is not subject to radio drop-outs. As
such, it provides a more complete and precise record of the
flight. The 'Save Flight Data' button allows you to read the
- flash memory and write it to disk. As TeleMini has only a barometer, it
- records data at the same rate as the telemetry signal, but there will be
- no data lost due to telemetry drop-outs.
+ flash memory and write it to disk.
</para>
<para>
Clicking on the 'Save Flight Data' button brings up a list of
- connected TeleMetrum and TeleDongle devices. If you select a
- TeleMetrum device, the flight data will be downloaded from that
+ connected flight computers and TeleDongle devices. If you select a
+ flight computer, the flight data will be downloaded from that
device directly. If you select a TeleDongle device, flight data
- will be downloaded from an altimeter over radio link via the
+ will be downloaded from a flight computer over radio link via the
specified TeleDongle. See the chapter on Controlling An Altimeter
Over The Radio Link for more information.
</para>
flash memory.
</para>
<para>
- Once a flight record is selected, a window with four tabs is
- opened. The first tab contains a graph with acceleration
- (blue), velocity (green) and altitude (red) of the flight,
- measured in metric units. The apogee(yellow) and main(magenta)
- igniter voltages are also displayed; high voltages indicate
- continuity, low voltages indicate open circuits. The second
- tab lets you configure which data to show in the graph. The
- third contains some basic flight statistics while the fourth
- has a map with the ground track of the flight displayed.
+ Note that telemetry files will generally produce poor graphs
+ due to the lower sampling rate and missed telemetry packets.
+ Use saved flight data in .eeprom files for graphing where possible.
+ </para>
+ <para>
+ Once a flight record is selected, a window with multiple tabs is
+ opened.
</para>
+ <section>
+ <title>Flight Graph</title>
+ <informalfigure>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="graph.png" width="5.5in" scalefit="1"/>
+ </imageobject>
+ </mediaobject>
+ </informalfigure>
+ <para>
+ By default, the graph contains acceleration (blue),
+ velocity (green) and altitude (red).
+ </para>
<para>
The graph can be zoomed into a particular area by clicking and
dragging down and to the right. Once zoomed, the graph can be
The right mouse button causes a pop-up menu to be displayed, giving
you the option save or print the plot.
</para>
- <para>
- Note that telemetry files will generally produce poor graphs
- due to the lower sampling rate and missed telemetry packets.
- Use saved flight data in .eeprom files for graphing where possible.
- </para>
+ </section>
+ <section>
+ <title>Configure Graph</title>
+ <informalfigure>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="graph-configure.png" width="5.5in" scalefit="1"/>
+ </imageobject>
+ </mediaobject>
+ </informalfigure>
+ <para>
+ This selects which graph elements to show, and, at the
+ very bottom, lets you switch between metric and
+ imperial units
+ </para>
+ </section>
+ <section>
+ <title>Flight Statistics</title>
+ <informalfigure>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="graph-stats.png" width="5.5in" scalefit="1"/>
+ </imageobject>
+ </mediaobject>
+ </informalfigure>
+ <para>
+ Shows overall data computed from the flight.
+ </para>
+ </section>
+ <section>
+ <title>Map</title>
+ <informalfigure>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="graph-map.png" width="5.5in" scalefit="1"/>
+ </imageobject>
+ </mediaobject>
+ </informalfigure>
+ <para>
+ Shows a satellite image of the flight area overlaid
+ with the path of the flight. The red concentric
+ circles mark the launch pad, the black concentric
+ circles mark the landing location.
+ </para>
+ </section>
</section>
<section>
<title>Export Data</title>
<para>
This tool takes the raw data files and makes them available for
external analysis. When you select this button, you are prompted to
- select a flight
- data file (either .eeprom or .telem will do, remember that
- .eeprom files contain higher resolution and more continuous
- data). Next, a second dialog appears which is used to select
+ select a flight data file, which can be either a .eeprom or .telem.
+ The .eeprom files contain higher resolution and more continuous data,
+ while .telem files contain receiver signal strength information.
+ Next, a second dialog appears which is used to select
where to write the resulting file. It has a selector to choose
between CSV and KML file formats.
</para>
</section>
<section>
<title>Configure Altimeter</title>
+ <informalfigure>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="configure-altimeter.png" width="3in" scalefit="1"/>
+ </imageobject>
+ </mediaobject>
+ </informalfigure>
<para>
- Select this button and then select either a TeleMetrum or
+ Select this button and then select either an altimeter or
TeleDongle Device from the list provided. Selecting a TeleDongle
device will use the radio link to configure a remote altimeter.
</para>
<para>
At the bottom of the dialog, there are four buttons:
</para>
- <itemizedlist>
- <listitem>
- <para>
- Save. This writes any changes to the
- configuration parameter block in flash memory. If you don't
- press this button, any changes you make will be lost.
- </para>
- </listitem>
- <listitem>
- <para>
- Reset. This resets the dialog to the most recently saved values,
- erasing any changes you have made.
- </para>
- </listitem>
- <listitem>
- <para>
- Reboot. This reboots the device. Use this to
- switch from idle to pad mode by rebooting once the rocket is
- oriented for flight, or to confirm changes you think you saved
- are really saved.
- </para>
- </listitem>
- <listitem>
- <para>
- Close. This closes the dialog. Any unsaved changes will be
- lost.
- </para>
- </listitem>
- </itemizedlist>
+ <variablelist>
+ <varlistentry>
+ <term>Save</term>
+ <listitem>
+ <para>
+ This writes any changes to the
+ configuration parameter block in flash memory. If you don't
+ press this button, any changes you make will be lost.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Reset</term>
+ <listitem>
+ <para>
+ This resets the dialog to the most recently saved values,
+ erasing any changes you have made.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Reboot</term>
+ <listitem>
+ <para>
+ This reboots the device. Use this to
+ switch from idle to pad mode by rebooting once the rocket is
+ oriented for flight, or to confirm changes you think you saved
+ are really saved.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Close</term>
+ <listitem>
+ <para>
+ This closes the dialog. Any unsaved changes will be
+ lost.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
<para>
The rest of the dialog contains the parameters to be configured.
</para>
<section>
<title>Radio Frequency</title>
<para>
- This configures which of the configured frequencies to use for both
+ This configures which of the frequencies to use for both
telemetry and packet command mode. Note that if you set this
- value via packet command mode, you will have to reconfigure
- the TeleDongle frequency before you will be able to use packet
- command mode again.
+ value via packet command mode, the TeleDongle frequency will
+ also be automatically reconfigured to match so that
+ communication will continue afterwards.
</para>
</section>
<section>
- <title>Radio Calibration</title>
+ <title>RF Calibration</title>
<para>
The radios in every Altus Metrum device are calibrated at the
factory to ensure that they transmit and receive on the
</para>
</section>
<section>
- <title>Callsign</title>
- <para>
- This sets the call sign included in each telemetry packet. Set this
- as needed to conform to your local radio regulations.
- </para>
- </section>
+ <title>Telemetry/RDF/APRS Enable</title>
+ <para>
+ Enables the radio for transmission during flight. When
+ disabled, the radio will not transmit anything during flight
+ at all.
+ </para>
+ </section>
+ <section>
+ <title>APRS Interval</title>
+ <para>
+ How often to transmit GPS information via APRS. This option
+ is available on TeleMetrum v2 and TeleMega
+ boards. TeleMetrum v1 boards cannot transmit APRS
+ packets. Note that a single APRS packet takes nearly a full
+ second to transmit, so enabling this option will prevent
+ sending any other telemetry during that time.
+ </para>
+ </section>
+ <section>
+ <title>Callsign</title>
+ <para>
+ This sets the call sign included in each telemetry packet. Set this
+ as needed to conform to your local radio regulations.
+ </para>
+ </section>
<section>
<title>Maximum Flight Log Size</title>
<para>
computers. This configuration parameter allows the two
channels to be used in different configurations.
</para>
- <itemizedlist>
- <listitem>
- <para>
- Dual Deploy. This is the usual mode of operation; the
- 'apogee' channel is fired at apogee and the 'main'
- channel at the height above ground specified by the
- 'Main Deploy Altitude' during descent.
- </para>
- </listitem>
- <listitem>
- <para>
- Redundant Apogee. This fires both channels at
- apogee, the 'apogee' channel first followed after a two second
- delay by the 'main' channel.
- </para>
- </listitem>
- <listitem>
- <para>
- Redundant Main. This fires both channels at the
- height above ground specified by the Main Deploy
- Altitude setting during descent. The 'apogee'
- channel is fired first, followed after a two second
- delay by the 'main' channel.
- </para>
- </listitem>
- </itemizedlist>
+ <variablelist>
+ <varlistentry>
+ <term>Dual Deploy</term>
+ <listitem>
+ <para>
+ This is the usual mode of operation; the
+ 'apogee' channel is fired at apogee and the 'main'
+ channel at the height above ground specified by the
+ 'Main Deploy Altitude' during descent.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Redundant Apogee</term>
+ <listitem>
+ <para>
+ This fires both channels at
+ apogee, the 'apogee' channel first followed after a two second
+ delay by the 'main' channel.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Redundant Main</term>
+ <listitem>
+ <para>
+ This fires both channels at the
+ height above ground specified by the Main Deploy
+ Altitude setting during descent. The 'apogee'
+ channel is fired first, followed after a two second
+ delay by the 'main' channel.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
</section>
<section>
<title>Pad Orientation</title>
<para>
- Because it includes an accelerometer, TeleMetrum is
- sensitive to the orientation of the board. By default, it
- expects the antenna end to point forward. This parameter
- allows that default to be changed, permitting the board to
- be mounted with the antenna pointing aft instead.
+ Because they include accelerometers, TeleMetrum and
+ TeleMega are sensitive to the orientation of the board. By
+ default, they expect the antenna end to point forward. This
+ parameter allows that default to be changed, permitting the
+ board to be mounted with the antenna pointing aft instead.
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term>Antenna Up</term>
+ <listitem>
+ <para>
+ In this mode, the antenna end of the
+ flight computer must point forward, in line with the
+ expected flight path.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Antenna Down</term>
+ <listitem>
+ <para>
+ In this mode, the antenna end of the
+ flight computer must point aft, in line with the
+ expected flight path.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+ <section>
+ <title>Configure Pyro Channels</title>
+ <informalfigure>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="configure-pyro.png" width="6in" scalefit="1"/>
+ </imageobject>
+ </mediaobject>
+ </informalfigure>
+ <para>
+ This opens a separate window to configure the additional
+ pyro channels available on TeleMega. One column is
+ presented for each channel. Each row represents a single
+ parameter, if enabled the parameter must meet the specified
+ test for the pyro channel to be fired. See the Pyro Channels
+ section in the System Operation chapter above for a
+ description of these parameters.
+ </para>
+ <para>
+ Select conditions and set the related value; the pyro
+ channel will be activated when <emphasis>all</emphasis> of the
+ conditions are met. Each pyro channel has a separate set of
+ configuration values, so you can use different values for
+ the same condition with different channels.
+ </para>
+ <para>
+ Once you have selected the appropriate configuration for all
+ of the necessary pyro channels, you can save the pyro
+ configuration along with the rest of the flight computer
+ configuration by pressing the 'Save' button in the main
+ Configure Flight Computer window.
</para>
- <itemizedlist>
- <listitem>
- <para>
- Antenna Up. In this mode, the antenna end of the
- TeleMetrum board must point forward, in line with the
- expected flight path.
- </para>
- </listitem>
- <listitem>
- <para>
- Antenna Down. In this mode, the antenna end of the
- TeleMetrum board must point aft, in line with the
- expected flight path.
- </para>
- </listitem>
- </itemizedlist>
</section>
</section>
<section>
<title>Configure AltosUI</title>
+ <informalfigure>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="configure-altosui.png" width="2.5in" scalefit="1"/>
+ </imageobject>
+ </mediaobject>
+ </informalfigure>
<para>
This button presents a dialog so that you can configure the AltosUI global settings.
</para>
the current flight status. However, sometimes you don't want
to hear them.
</para>
- <itemizedlist>
- <listitem>
- <para>Enable—turns all voice announcements on and off</para>
- </listitem>
- <listitem>
- <para>
- Test Voice—Plays a short message allowing you to verify
- that the audio system is working and the volume settings
- are reasonable
- </para>
- </listitem>
- </itemizedlist>
+ <variablelist>
+ <varlistentry>
+ <term>Enable</term>
+ <listitem>
+ <para>Turns all voice announcements on and off</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Test Voice</term>
+ <listitem>
+ <para>
+ Plays a short message allowing you to verify
+ that the audio system is working and the volume settings
+ are reasonable
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
</section>
<section>
<title>Log Directory</title>
with the AltosUI operators call sign as needed to comply with
your local radio regulations.
</para>
+ <para>
+ Note that to successfully command a flight computer over the radio
+ (to configure the altimeter, monitor idle, or fire pyro charges),
+ the callsign configured here must exactly match the callsign
+ configured in the flight computer. This matching is case
+ sensitive.
+ </para>
</section>
<section>
<title>Imperial Units</title>
<para>
This switches between metric units (meters) and imperial
units (feet and miles). This affects the display of values
- use during flight monitoring, data graphing and all of the
- voice announcements. It does not change the units used when
- exporting to CSV files, those are always produced in metric units.
+ use during flight monitoring, configuration, data graphing
+ and all of the voice announcements. It does not change the
+ units used when exporting to CSV files, those are always
+ produced in metric units.
</para>
</section>
<section>
</section>
<section>
<title>Configure Groundstation</title>
+ <informalfigure>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="configure-groundstation.png" width="3in" scalefit="1"/>
+ </imageobject>
+ </mediaobject>
+ </informalfigure>
<para>
Select this button and then select a TeleDongle Device from the list provided.
</para>
<para>
At the bottom of the dialog, there are three buttons:
</para>
- <itemizedlist>
- <listitem>
- <para>
- Save. This writes any changes to the
- local Java preferences file. If you don't
- press this button, any changes you make will be lost.
- </para>
- </listitem>
- <listitem>
- <para>
- Reset. This resets the dialog to the most recently saved values,
- erasing any changes you have made.
- </para>
- </listitem>
- <listitem>
- <para>
- Close. This closes the dialog. Any unsaved changes will be
- lost.
- </para>
- </listitem>
- </itemizedlist>
+ <variablelist>
+ <varlistentry>
+ <term>Save</term>
+ <listitem>
+ <para>
+ This writes any changes to the
+ local Java preferences file. If you don't
+ press this button, any changes you make will be lost.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Reset</term>
+ <listitem>
+ <para>
+ This resets the dialog to the most recently saved values,
+ erasing any changes you have made.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Close</term>
+ <listitem>
+ <para>
+ This closes the dialog. Any unsaved changes will be
+ lost.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
<para>
The rest of the dialog contains the parameters to be configured.
</para>
<section>
<title>Flash Image</title>
<para>
- This reprograms any Altus Metrum device by using a TeleMetrum
- or TeleDongle as a programming dongle. Please read the
- directions for flashing devices in the Updating Device
- Firmware chapter below.
- </para>
- <para>
- Once you have the programmer and target devices connected,
- push the 'Flash Image' button. That will present a dialog box
- listing all of the connected devices. Carefully select the
- programmer device, not the device to be programmed.
- </para>
- <para>
- Next, select the image to flash to the device. These are named
- with the product name and firmware version. The file selector
- will start in the directory containing the firmware included
- with the AltosUI package. Navigate to the directory containing
- the desired firmware if it isn't there.
- </para>
- <para>
- Next, a small dialog containing the device serial number and
- RF calibration values should appear. If these values are
- incorrect (possibly due to a corrupted image in the device),
- enter the correct values here.
- </para>
- <para>
- Finally, a dialog containing a progress bar will follow the
- programming process.
- </para>
- <para>
- When programming is complete, the target device will
- reboot. Note that if the target device is connected via USB, you
- will have to unplug it and then plug it back in for the USB
- connection to reset so that you can communicate with the device
- again.
+ This reprograms Altus Metrum devices with new
+ firmware. TeleMetrum v1.x, TeleDongle, TeleMini and TeleBT are
+ all reprogrammed by using another similar unit as a
+ programming dongle (pair programming). TeleMega, TeleMetrum v2
+ and EasyMini are all programmed directly over their USB ports
+ (self programming). Please read the directions for flashing
+ devices in the Updating Device Firmware chapter below.
</para>
</section>
<section>
<title>Fire Igniter</title>
+ <informalfigure>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="fire-igniter.png" width="1in" scalefit="1"/>
+ </imageobject>
+ </mediaobject>
+ </informalfigure>
<para>
- This activates the igniter circuits in TeleMetrum to help test
- recovery systems deployment. Because this command can operate
+ This activates the igniter circuits in the flight computer to help
+ test recovery systems deployment. Because this command can operate
over the Packet Command Link, you can prepare the rocket as
for flight and then test the recovery system without needing
to snake wires inside the air-frame.
</para>
<para>
Selecting the 'Fire Igniter' button brings up the usual device
- selection dialog. Pick the desired TeleDongle or TeleMetrum
- device. This brings up another window which shows the current
- continuity test status for both apogee and main charges.
+ selection dialog. Pick the desired device. This brings up another
+ window which shows the current continuity test status for both
+ apogee and main charges.
</para>
<para>
Next, select the desired igniter to fire. This will enable the
</section>
<section>
<title>Scan Channels</title>
+ <informalfigure>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="scan-channels.png" width="2.75in" scalefit="1"/>
+ </imageobject>
+ </mediaobject>
+ </informalfigure>
<para>
This listens for telemetry packets on all of the configured
frequencies, displaying information about each device it
</section>
<section>
<title>Load Maps</title>
+ <informalfigure>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="load-maps.png" width="5.5in" scalefit="1"/>
+ </imageobject>
+ </mediaobject>
+ </informalfigure>
<para>
Before heading out to a new launch site, you can use this to
load satellite images in case you don't have internet
There's a drop-down menu of launch sites we know about; if
your favorites aren't there, please let us know the lat/lon
and name of the site. The contents of this list are actually
- downloaded at run-time, so as new sites are sent in, they'll
- get automatically added to this list.
+ downloaded from our server at run-time, so as new sites are sent
+ in, they'll get automatically added to this list.
</para>
<para>
If the launch site isn't in the list, you can manually enter the lat/lon values
<title>Monitor Idle</title>
<para>
This brings up a dialog similar to the Monitor Flight UI,
- except it works with the altimeter in "idle" mode by sending
+ except it works with the altimeter in “idle” mode by sending
query commands to discover the current state rather than
- listening for telemetry packets.
+ listening for telemetry packets. Because this uses command
+ mode, it needs to have the TeleDongle and flight computer
+ callsigns match exactly. If you can receive telemetry, but
+ cannot manage to run Monitor Idle, then it's very likely that
+ your callsigns are different in some way.
</para>
</section>
</chapter>
<para>
AltosDroid provides the same flight monitoring capabilities as
AltosUI, but runs on Android devices and is designed to connect
- to a TeleBT receiver over Bluetooth™. Altos Droid monitors
+ to a TeleBT receiver over Bluetooth™. AltosDroid monitors
telemetry data, logging it to internal storage in the Android
device, and presents that data in a UI the same way the 'Monitor
Flight' window does in AltosUI.
<section>
<title>Installing AltosDroid</title>
<para>
- AltosDroid is included in the Google Play store. To install
- it on your Android device, open open the Google Play Store
- application and search for "altosdroid". Make sure you don't
- have a space between "altos" and "droid" or you probably won't
+ AltosDroid is available from the Google Play store. To install
+ it on your Android device, open the Google Play Store
+ application and search for “altosdroid”. Make sure you don't
+ have a space between “altos” and “droid” or you probably won't
find what you want. That should bring you to the right page
from which you can download and install the application.
</para>
</para>
</section>
<section>
- <title>Altos Droid Flight Monitoring</title>
+ <title>AltosDroid Flight Monitoring</title>
<para>
- Altos Droid is designed to mimic the AltosUI flight monitoring
+ AltosDroid is designed to mimic the AltosUI flight monitoring
display, providing separate tabs for each stage of your rocket
flight along with a tab containing a map of the local area
with icons marking the current location of the altimeter and
rocket is ready for flight. The first elements include red/green
indicators, if any of these is red, you'll want to evaluate
whether the rocket is ready to launch:
- <itemizedlist>
- <listitem>
- <para>
- Battery Voltage. This indicates whether the Li-Po battery
- powering the TeleMetrum has sufficient charge to last for
- the duration of the flight. A value of more than
- 3.7V is required for a 'GO' status.
- </para>
- </listitem>
- <listitem>
- <para>
- Apogee Igniter Voltage. This indicates whether the apogee
- igniter has continuity. If the igniter has a low
- resistance, then the voltage measured here will be close
- to the Li-Po battery voltage. A value greater than 3.2V is
- required for a 'GO' status.
- </para>
- </listitem>
- <listitem>
- <para>
- Main Igniter Voltage. This indicates whether the main
- igniter has continuity. If the igniter has a low
- resistance, then the voltage measured here will be close
- to the Li-Po battery voltage. A value greater than 3.2V is
- required for a 'GO' status.
- </para>
- </listitem>
- <listitem>
- <para>
- On-board Data Logging. This indicates whether there is
- space remaining on-board to store flight data for the
- upcoming flight. If you've downloaded data, but failed
- to erase flights, there may not be any space
- left. TeleMetrum can store multiple flights, depending
- on the configured maximum flight log size. TeleMini
- stores only a single flight, so it will need to be
- downloaded and erased after each flight to capture
- data. This only affects on-board flight logging; the
- altimeter will still transmit telemetry and fire
- ejection charges at the proper times.
- </para>
- </listitem>
- <listitem>
- <para>
- GPS Locked. For a TeleMetrum device, this indicates whether the GPS receiver is
- currently able to compute position information. GPS requires
- at least 4 satellites to compute an accurate position.
- </para>
- </listitem>
- <listitem>
- <para>
- GPS Ready. For a TeleMetrum device, this indicates whether GPS has reported at least
- 10 consecutive positions without losing lock. This ensures
- that the GPS receiver has reliable reception from the
- satellites.
- </para>
- </listitem>
- </itemizedlist>
- <para>
- The Launchpad tab also shows the computed launch pad position
- and altitude, averaging many reported positions to improve the
- accuracy of the fix.
- </para>
- </para>
+ <variablelist>
+ <varlistentry>
+ <term>Battery Voltage</term>
+ <listitem>
+ <para>
+ This indicates whether the Li-Po battery
+ powering the TeleMetrum has sufficient charge to last for
+ the duration of the flight. A value of more than
+ 3.8V is required for a 'GO' status.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Apogee Igniter Voltage</term>
+ <listitem>
+ <para>
+ This indicates whether the apogee
+ igniter has continuity. If the igniter has a low
+ resistance, then the voltage measured here will be close
+ to the Li-Po battery voltage. A value greater than 3.2V is
+ required for a 'GO' status.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Main Igniter Voltage</term>
+ <listitem>
+ <para>
+ This indicates whether the main
+ igniter has continuity. If the igniter has a low
+ resistance, then the voltage measured here will be close
+ to the Li-Po battery voltage. A value greater than 3.2V is
+ required for a 'GO' status.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>On-board Data Logging</term>
+ <listitem>
+ <para>
+ This indicates whether there is
+ space remaining on-board to store flight data for the
+ upcoming flight. If you've downloaded data, but failed
+ to erase flights, there may not be any space
+ left. TeleMetrum can store multiple flights, depending
+ on the configured maximum flight log size. TeleMini
+ stores only a single flight, so it will need to be
+ downloaded and erased after each flight to capture
+ data. This only affects on-board flight logging; the
+ altimeter will still transmit telemetry and fire
+ ejection charges at the proper times.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>GPS Locked</term>
+ <listitem>
+ <para>
+ For a TeleMetrum or TeleMega device, this indicates whether the GPS receiver is
+ currently able to compute position information. GPS requires
+ at least 4 satellites to compute an accurate position.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>GPS Ready</term>
+ <listitem>
+ <para>
+ For a TeleMetrum or TeleMega device, this indicates whether GPS has reported at least
+ 10 consecutive positions without losing lock. This ensures
+ that the GPS receiver has reliable reception from the
+ satellites.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ <para>
+ The Launchpad tab also shows the computed launch pad position
+ and altitude, averaging many reported positions to improve the
+ accuracy of the fix.
+ </para>
</section>
</section>
<section>
<title>Downloading Flight Logs</title>
<para>
- Altos Droid always saves every bit of telemetry data it
+ AltosDroid always saves every bit of telemetry data it
receives. To download that to a computer for use with AltosUI,
simply remove the SD card from your Android device, or connect
your device to your computer's USB port and browse the files
<section>
<title>In the Rocket</title>
<para>
- In the rocket itself, you just need a <ulink url="http://www.altusmetrum.org/TeleMetrum/">TeleMetrum</ulink> or
- <ulink url="http://www.altusmetrum.org/TeleMini/">TeleMini</ulink> board and
+ In the rocket itself, you just need a flight computer and
a single-cell, 3.7 volt nominal Li-Po rechargeable battery. An
850mAh battery weighs less than a 9V alkaline battery, and will
- run a TeleMetrum for hours.
- A 110mAh battery weighs less than a triple A battery and will run a TeleMetrum for
- a few hours, or a TeleMini for much (much) longer.
+ run a TeleMetrum or TeleMega for hours.
+ A 110mAh battery weighs less than a triple A battery and is a good
+ choice for use with TeleMini.
</para>
<para>
- By default, we ship the altimeters with a simple wire antenna. If your
- electronics bay or the air-frame it resides within is made of carbon fiber,
- which is opaque to RF signals, you may choose to have an SMA connector
- installed so that you can run a coaxial cable to an antenna mounted
- elsewhere in the rocket.
+ By default, we ship flight computers with a simple wire antenna.
+ If your electronics bay or the air-frame it resides within is made
+ of carbon fiber, which is opaque to RF signals, you may prefer to
+ install an SMA connector so that you can run a coaxial cable to an
+ antenna mounted elsewhere in the rocket. However, note that the
+ GPS antenna is fixed on all current products, so you really want
+ to install the flight computer in a bay made of RF-transparent
+ materials if at all possible.
</para>
</section>
<section>
Linux, Mac OS and Windows. There's also a suite of C tools
for Linux which can perform most of the same tasks.
</para>
+ <para>
+ Alternatively, a TeleBT attached with an SMA to BNC adapter at the
+ feed point of a hand-held yagi used in conjunction with an Android
+ device running AltosDroid makes an outstanding ground station.
+ </para>
<para>
After the flight, you can use the radio link to extract the more detailed data
logged in either TeleMetrum or TeleMini devices, or you can use a mini USB cable to plug into the
of digital cameras and other modern electronic stuff will work fine.
</para>
<para>
- If your TeleMetrum-equipped rocket lands out of sight, you may enjoy having a hand-held GPS
- receiver, so that you can put in a way-point for the last reported rocket
- position before touch-down. This makes looking for your rocket a lot like
- Geo-Caching... just go to the way-point and look around starting from there.
+ If your rocket lands out of sight, you may enjoy having a hand-held
+ GPS receiver, so that you can put in a way-point for the last
+ reported rocket position before touch-down. This makes looking for
+ your rocket a lot like Geo-Caching... just go to the way-point and
+ look around starting from there. AltosDroid on an Android device
+ with GPS receiver works great for this, too!
</para>
<para>
- You may also enjoy having a ham radio "HT" that covers the 70cm band... you
+ You may also enjoy having a ham radio “HT” that covers the 70cm band... you
can use that with your antenna to direction-find the rocket on the ground
the same way you can use a Walston or Beeline tracker. This can be handy
if the rocket is hiding in sage brush or a tree, or if the last GPS position
doesn't get you close enough because the rocket dropped into a canyon, or
the wind is blowing it across a dry lake bed, or something like that... Keith
- and Bdale both currently own and use the Yaesu VX-7R at launches.
+ currently uses a Yaesu VX-7R, Bdale has a Baofung UV-5R
+ which isn't as nice, but was a whole lot cheaper.
</para>
<para>
So, to recap, on the ground the hardware you'll need includes:
<orderedlist inheritnum='inherit' numeration='arabic'>
<listitem>
- an antenna and feed-line or adapter
+ <para>
+ an antenna and feed-line or adapter
+ </para>
</listitem>
<listitem>
- a TeleDongle
+ <para>
+ a TeleDongle
+ </para>
</listitem>
<listitem>
- a notebook computer
+ <para>
+ a notebook computer
+ </para>
</listitem>
<listitem>
- optionally, a hand-held GPS receiver
+ <para>
+ optionally, a hand-held GPS receiver
+ </para>
</listitem>
<listitem>
- optionally, an HT or receiver covering 435 MHz
+ <para>
+ optionally, an HT or receiver covering 435 MHz
+ </para>
</listitem>
</orderedlist>
</para>
</section>
<section>
<title>Future Plans</title>
+ <para>
+ We've designed a simple GPS based radio tracker called TeleGPS.
+ If all goes well, we hope to introduce this in the first
+ half of 2014.
+ </para>
<para>
- In the future, we intend to offer "companion boards" for the rocket
- that will plug in to TeleMetrum to collect additional data, provide
- more pyro channels, and so forth.
- </para>
- <para>
- Also under design is a new flight computer with more sensors, more
- pyro channels, and a more powerful radio system designed for use
- in multi-stage, complex, and extreme altitude projects.
- </para>
- <para>
- We are also working on alternatives to TeleDongle. One is a
- a stand-alone, hand-held ground terminal that will allow monitoring
- the rocket's status, collecting data during flight, and logging data
- after flight without the need for a notebook computer on the
- flight line. Particularly since it is so difficult to read most
- notebook screens in direct sunlight, we think this will be a great
- thing to have. We are also working on a TeleDongle variant with
- Bluetooth that will work with Android phones and tablets.
+ We have designed and prototyped several “companion boards” that
+ can attach to the companion connector on TeleMetrum and TeleMega
+ flight computers to collect more data, provide more pyro channels,
+ and so forth. We do not yet know if or when any of these boards
+ will be produced in enough quantity to sell. If you have specific
+ interests for data collection or control of events in your rockets
+ beyond the capabilities of our existing productions, please let
+ us know!
</para>
<para>
Because all of our work is open, both the hardware designs and the
<para>
Building high-power rockets that fly safely is hard enough. Mix
in some sophisticated electronics and a bunch of radio energy
- and oftentimes you find few perfect solutions. This chapter
+ and some creativity and/or compromise may be required. This chapter
contains some suggestions about how to install Altus Metrum
- products into the rocket air-frame, including how to safely and
+ products into a rocket air-frame, including how to safely and
reliably mix a variety of electronics into the same air-frame.
</para>
<section>
<title>Mounting the Altimeter</title>
<para>
The first consideration is to ensure that the altimeter is
- securely fastened to the air-frame. For TeleMetrum, we use
- nylon standoffs and nylon screws; they're good to at least 50G
- and cannot cause any electrical issues on the board. For
- TeleMini, we usually cut small pieces of 1/16" balsa to fit
+ securely fastened to the air-frame. For most of our products, we
+ prefer nylon standoffs and nylon screws; they're good to at least 50G
+ and cannot cause any electrical issues on the board. Metal screws
+ and standoffs are fine, too, just be careful to avoid electrical
+ shorts! For TeleMini v1.0, we usually cut small pieces of 1/16 inch
+ balsa to fit
under the screw holes, and then take 2x56 nylon screws and
screw them through the TeleMini mounting holes, through the
balsa and into the underlying material.
</para>
<orderedlist inheritnum='inherit' numeration='arabic'>
<listitem>
- Make sure TeleMetrum is aligned precisely along the axis of
- acceleration so that the accelerometer can accurately
- capture data during the flight.
+ <para>
+ Make sure accelerometer-equipped products like TeleMetrum and
+ TeleMega are aligned precisely along the axis of
+ acceleration so that the accelerometer can accurately
+ capture data during the flight.
+ </para>
</listitem>
<listitem>
- Watch for any metal touching components on the
- board. Shorting out connections on the bottom of the board
- can cause the altimeter to fail during flight.
+ <para>
+ Watch for any metal touching components on the
+ board. Shorting out connections on the bottom of the board
+ can cause the altimeter to fail during flight.
+ </para>
</listitem>
</orderedlist>
</section>
culprit here -- CF is a good conductor and will effectively
shield the antenna, dramatically reducing signal strength and
range. Metallic flake paint is another effective shielding
- material which is to be avoided around any antennas.
+ material which should be avoided around any antennas.
</para>
<para>
If the ebay is large enough, it can be convenient to simply
consuming very little space.
</para>
<para>
- If you need to place the antenna at a distance from the
+ If you need to place the UHF antenna at a distance from the
altimeter, you can replace the antenna with an edge-mounted
SMA connector, and then run 50Ω coax from the board to the
antenna. Building a remote antenna is beyond the scope of this
<section>
<title>Preserving GPS Reception</title>
<para>
- The GPS antenna and receiver in TeleMetrum are highly
- sensitive and normally have no trouble tracking enough
+ The GPS antenna and receiver used in TeleMetrum and TeleMega is
+ highly sensitive and normally have no trouble tracking enough
satellites to provide accurate position information for
- recovering the rocket. However, there are many ways to
- attenuate the GPS signal.
+ recovering the rocket. However, there are many ways the GPS signal
+ can end up attenuated, negatively affecting GPS performance.
<orderedlist inheritnum='inherit' numeration='arabic'>
<listitem>
- Conductive tubing or coatings. Carbon fiber and metal
- tubing, or metallic paint will all dramatically attenuate the
- GPS signal. We've never heard of anyone successfully
- receiving GPS from inside these materials.
+ <para>
+ Conductive tubing or coatings. Carbon fiber and metal
+ tubing, or metallic paint will all dramatically attenuate the
+ GPS signal. We've never heard of anyone successfully
+ receiving GPS from inside these materials.
+ </para>
</listitem>
<listitem>
- Metal components near the GPS patch antenna. These will
- de-tune the patch antenna, changing the resonant frequency
- away from the L1 carrier and reduce the effectiveness of the
- antenna. You can place as much stuff as you like beneath the
- antenna as that's covered with a ground plane. But, keep
- wires and metal out from above the patch antenna.
+ <para>
+ Metal components near the GPS patch antenna. These will
+ de-tune the patch antenna, changing the resonant frequency
+ away from the L1 carrier and reduce the effectiveness of the
+ antenna. You can place as much stuff as you like beneath the
+ antenna as that's covered with a ground plane. But, keep
+ wires and metal out from above the patch antenna.
+ </para>
</listitem>
</orderedlist>
</para>
</para>
<itemizedlist>
<listitem>
- Keep wires from different circuits apart. Moving circuits
- further apart will reduce RFI.
+ <para>
+ Keep wires from different circuits apart. Moving circuits
+ further apart will reduce RFI.
+ </para>
</listitem>
<listitem>
+ <para>
Avoid parallel wires from different circuits. The longer two
wires run parallel to one another, the larger the amount of
transferred energy. Cross wires at right angles to reduce
RFI.
+ </para>
</listitem>
<listitem>
+ <para>
Twist wires from the same circuits. Two wires the same
distance from the transmitter will get the same amount of
induced energy which will then cancel out. Any time you have
even out distances and reduce RFI. For altimeters, this
includes battery leads, switch hookups and igniter
circuits.
+ </para>
</listitem>
<listitem>
+ <para>
Avoid resonant lengths. Know what frequencies are present
in the environment and avoid having wire lengths near a
- natural resonant length. Altusmetrum products transmit on the
+ natural resonant length. Altus Metrum products transmit on the
70cm amateur band, so you should avoid lengths that are a
- simple ratio of that length; essentially any multiple of 1/4
+ simple ratio of that length; essentially any multiple of ¼
of the wavelength (17.5cm).
+ </para>
</listitem>
</itemizedlist>
</section>
decreasing pressure.
</para>
<para>
- The barometric sensor in the altimeter is quite sensitive to
- chemical damage from the products of APCP or BP combustion, so
- make sure the ebay is carefully sealed from any compartment
- which contains ejection charges or motors.
+ All barometric sensors are quite sensitive to chemical damage from
+ the products of APCP or BP combustion, so make sure the ebay is
+ carefully sealed from any compartment which contains ejection
+ charges or motors.
</para>
</section>
<section>
<chapter>
<title>Updating Device Firmware</title>
<para>
- The big concept to understand is that you have to use a
- TeleDongle as a programmer to update a TeleMetrum or TeleMini,
- and a TeleMetrum or other TeleDongle to program the TeleDongle
- Due to limited memory resources in the cc1111, we don't support
- programming directly over USB.
+ TeleMega, TeleMetrum v2 and EasyMini are all programmed directly
+ over their USB connectors (self programming). TeleMetrum v1, TeleMini and
+ TeleDongle are all programmed by using another device as a
+ programmer (pair programming). It's important to recognize which
+ kind of devices you have before trying to reprogram them.
</para>
<para>
You may wish to begin by ensuring you have current firmware images.
version from <ulink url="http://www.altusmetrum.org/AltOS/"/>.
</para>
<para>
- We recommend updating the altimeter first, before updating TeleDongle.
+ If you need to update the firmware on a TeleDongle, we recommend
+ updating the altimeter first, before updating TeleDongle. However,
+ note that TeleDongle rarely need to be updated. Any firmware version
+ 1.0.1 or later will work, version 1.2.1 may have improved receiver
+ performance slightly.
+ </para>
+ <para>
+ Self-programmable devices (TeleMega, TeleMetrum v2 and EasyMini)
+ are reprogrammed by connecting them to your computer over USB
</para>
<section>
- <title>Updating TeleMetrum Firmware</title>
+ <title>
+ Updating TeleMega, TeleMetrum v2 or EasyMini Firmware
+ </title>
<orderedlist inheritnum='inherit' numeration='arabic'>
+ <listitem>
+ <para>
+ Attach a battery and power switch to the target
+ device. Power up the device.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Using a Micro USB cable, connect the target device to your
+ computer's USB socket.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Run AltosUI, and select 'Flash Image' from the File menu.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Select the target device in the Device Selection dialog.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Select the image you want to flash to the device, which
+ should have a name in the form
+ <product>-v<product-version>-<software-version>.ihx, such
+ as TeleMega-v1.0-1.3.0.ihx.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Make sure the configuration parameters are reasonable
+ looking. If the serial number and/or RF configuration
+ values aren't right, you'll need to change them.
+ </para>
+ </listitem>
<listitem>
+ <para>
+ Hit the 'OK' button and the software should proceed to flash
+ the device with new firmware, showing a progress bar.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Verify that the device is working by using the 'Configure
+ Altimeter' item to check over the configuration.
+ </para>
+ </listitem>
+ </orderedlist>
+ <section>
+ <title>Recovering From Self-Flashing Failure</title>
+ <para>
+ If the firmware loading fails, it can leave the device
+ unable to boot. Not to worry, you can force the device to
+ start the boot loader instead, which will let you try to
+ flash the device again.
+ </para>
+ <para>
+ On each device, connecting two pins from one of the exposed
+ connectors will force the boot loader to start, even if the
+ regular operating system has been corrupted in some way.
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term>TeleMega</term>
+ <listitem>
+ <para>
+ Connect pin 6 and pin 1 of the companion connector. Pin 1
+ can be identified by the square pad around it, and then
+ the pins could sequentially across the board. Be very
+ careful to <emphasis>not</emphasis> short pin 8 to
+ anything as that is connected directly to the battery. Pin
+ 7 carries 3.3V and the board will crash if that is
+ connected to pin 1, but shouldn't damage the board.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>TeleMetrum v2</term>
+ <listitem>
+ <para>
+ Connect pin 6 and pin 1 of the companion connector. Pin 1
+ can be identified by the square pad around it, and then
+ the pins could sequentially across the board. Be very
+ careful to <emphasis>not</emphasis> short pin 8 to
+ anything as that is connected directly to the battery. Pin
+ 7 carries 3.3V and the board will crash if that is
+ connected to pin 1, but shouldn't damage the board.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>EasyMini</term>
+ <listitem>
+ <para>
+ Connect pin 6 and pin 1 of the debug connector, which is
+ the six holes next to the beeper. Pin 1 can be identified
+ by the square pad around it, and then the pins could
+ sequentially across the board, making Pin 6 the one on the
+ other end of the row.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+ </section>
+ <section>
+ <title>Pair Programming</title>
+ <para>
+ The big concept to understand is that you have to use a
+ TeleMega, TeleMetrum or TeleDongle as a programmer to update a
+ pair programmed device. Due to limited memory resources in the
+ cc1111, we don't support programming directly over USB for these
+ devices.
+ </para>
+ </section>
+ <section>
+ <title>Updating TeleMetrum v1.x Firmware</title>
+ <orderedlist inheritnum='inherit' numeration='arabic'>
+ <listitem>
+ <para>
Find the 'programming cable' that you got as part of the starter
kit, that has a red 8-pin MicroMaTch connector on one end and a
red 4-pin MicroMaTch connector on the other end.
+ </para>
</listitem>
<listitem>
+ <para>
Take the 2 screws out of the TeleDongle case to get access
to the circuit board.
+ </para>
</listitem>
<listitem>
+ <para>
Plug the 8-pin end of the programming cable to the
matching connector on the TeleDongle, and the 4-pin end to the
matching connector on the TeleMetrum.
Note that each MicroMaTch connector has an alignment pin that
goes through a hole in the PC board when you have the cable
oriented correctly.
+ </para>
</listitem>
<listitem>
+ <para>
Attach a battery to the TeleMetrum board.
+ </para>
</listitem>
<listitem>
+ <para>
Plug the TeleDongle into your computer's USB port, and power
up the TeleMetrum.
+ </para>
</listitem>
<listitem>
+ <para>
Run AltosUI, and select 'Flash Image' from the File menu.
+ </para>
</listitem>
<listitem>
+ <para>
Pick the TeleDongle device from the list, identifying it as the
programming device.
+ </para>
</listitem>
<listitem>
+ <para>
Select the image you want put on the TeleMetrum, which should have a
name in the form telemetrum-v1.2-1.0.0.ihx. It should be visible
in the default directory, if not you may have to poke around
your system to find it.
+ </para>
</listitem>
<listitem>
+ <para>
Make sure the configuration parameters are reasonable
looking. If the serial number and/or RF configuration
values aren't right, you'll need to change them.
+ </para>
</listitem>
<listitem>
+ <para>
Hit the 'OK' button and the software should proceed to flash
the TeleMetrum with new firmware, showing a progress bar.
+ </para>
</listitem>
<listitem>
+ <para>
Confirm that the TeleMetrum board seems to have updated OK, which you
can do by plugging in to it over USB and using a terminal program
to connect to the board and issue the 'v' command to check
the version, etc.
+ </para>
</listitem>
<listitem>
+ <para>
If something goes wrong, give it another try.
+ </para>
</listitem>
</orderedlist>
</section>
<title>Updating TeleMini Firmware</title>
<orderedlist inheritnum='inherit' numeration='arabic'>
<listitem>
+<para>
You'll need a special 'programming cable' to reprogram the
- TeleMini. It's available on the Altus Metrum web store, or
- you can make your own using an 8-pin MicroMaTch connector on
- one end and a set of four pins on the other.
- </listitem>
+ TeleMini. You can make your own using an 8-pin MicroMaTch
+ connector on one end and a set of four pins on the other.
+ </para>
+</listitem>
<listitem>
+<para>
Take the 2 screws out of the TeleDongle case to get access
to the circuit board.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Plug the 8-pin end of the programming cable to the matching
connector on the TeleDongle, and the 4-pins into the holes
in the TeleMini circuit board. Note that the MicroMaTch
the PC board when you have the cable oriented correctly, and
that pin 1 on the TeleMini board is marked with a square pad
while the other pins have round pads.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Attach a battery to the TeleMini board.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Plug the TeleDongle into your computer's USB port, and power
up the TeleMini
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Run AltosUI, and select 'Flash Image' from the File menu.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Pick the TeleDongle device from the list, identifying it as the
programming device.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Select the image you want put on the TeleMini, which should have a
name in the form telemini-v1.0-1.0.0.ihx. It should be visible
in the default directory, if not you may have to poke around
your system to find it.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Make sure the configuration parameters are reasonable
looking. If the serial number and/or RF configuration
values aren't right, you'll need to change them.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Hit the 'OK' button and the software should proceed to flash
the TeleMini with new firmware, showing a progress bar.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Confirm that the TeleMini board seems to have updated OK, which you
can do by configuring it over the radio link through the TeleDongle, or
- letting it come up in "flight" mode and listening for telemetry.
- </listitem>
+ letting it come up in “flight” mode and listening for telemetry.
+ </para>
+</listitem>
<listitem>
+<para>
If something goes wrong, give it another try.
- </listitem>
+ </para>
+</listitem>
</orderedlist>
</section>
<section>
</para>
<orderedlist inheritnum='inherit' numeration='arabic'>
<listitem>
+<para>
Find the 'programming cable' that you got as part of the starter
kit, that has a red 8-pin MicroMaTch connector on one end and a
red 4-pin MicroMaTch connector on the other end.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Find the USB cable that you got as part of the starter kit, and
- plug the "mini" end in to the mating connector on TeleMetrum or TeleDongle.
- </listitem>
+ plug the “mini” end in to the mating connector on TeleMetrum or TeleDongle.
+ </para>
+</listitem>
<listitem>
+<para>
Take the 2 screws out of the TeleDongle case to get access
to the circuit board.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Plug the 8-pin end of the programming cable to the
matching connector on the programmer, and the 4-pin end to the
matching connector on the TeleDongle.
Note that each MicroMaTch connector has an alignment pin that
goes through a hole in the PC board when you have the cable
oriented correctly.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Attach a battery to the TeleMetrum board if you're using one.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Plug both the programmer and the TeleDongle into your computer's USB
ports, and power up the programmer.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Run AltosUI, and select 'Flash Image' from the File menu.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Pick the programmer device from the list, identifying it as the
programming device.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Select the image you want put on the TeleDongle, which should have a
name in the form teledongle-v0.2-1.0.0.ihx. It should be visible
in the default directory, if not you may have to poke around
your system to find it.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Make sure the configuration parameters are reasonable
looking. If the serial number and/or RF configuration
values aren't right, you'll need to change them. The TeleDongle
- serial number is on the "bottom" of the circuit board, and can
+ serial number is on the “bottom” of the circuit board, and can
usually be read through the translucent blue plastic case without
needing to remove the board from the case.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Hit the 'OK' button and the software should proceed to flash
the TeleDongle with new firmware, showing a progress bar.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Confirm that the TeleDongle board seems to have updated OK, which you
can do by plugging in to it over USB and using a terminal program
to connect to the board and issue the 'v' command to check
the version, etc. Once you're happy, remove the programming cable
and put the cover back on the TeleDongle.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
If something goes wrong, give it another try.
- </listitem>
+ </para>
+</listitem>
</orderedlist>
<para>
Be careful removing the programming cable from the locking 8-pin
<chapter>
<title>Hardware Specifications</title>
<section>
- <title>TeleMetrum Specifications</title>
+ <title>
+ TeleMega Specifications
+ </title>
+ <itemizedlist>
+ <listitem>
+ <para>
+ Recording altimeter for model rocketry.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Supports dual deployment and four auxiliary pyro channels
+ (a total of 6 events).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ 70cm 40mW ham-band transceiver for telemetry down-link.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Barometric pressure sensor good to 100k feet MSL.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ 1-axis high-g accelerometer for motor characterization, capable of
+ +/- 102g.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ 9-axis IMU including integrated 3-axis accelerometer,
+ 3-axis gyroscope and 3-axis magnetometer.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ On-board, integrated uBlox Max 7 GPS receiver with 5Hz update rate capability.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ On-board 8 Megabyte non-volatile memory for flight data storage.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ USB interface for battery charging, configuration, and data recovery.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Fully integrated support for Li-Po rechargeable batteries.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Can use either main system Li-Po or optional separate pyro battery
+ to fire e-matches.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ 3.25 x 1.25 inch board designed to fit inside 38mm air-frame coupler tube.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </section>
+ <section>
+ <title>
+ TeleMetrum v2 Specifications
+ </title>
+ <itemizedlist>
+ <listitem>
+ <para>
+ Recording altimeter for model rocketry.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Supports dual deployment (can fire 2 ejection charges).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ 70cm, 40mW ham-band transceiver for telemetry down-link.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Barometric pressure sensor good to 100k feet MSL.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ 1-axis high-g accelerometer for motor characterization, capable of
+ +/- 102g.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ On-board, integrated uBlox Max 7 GPS receiver with 5Hz update rate capability.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ On-board 8 Megabyte non-volatile memory for flight data storage.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ USB interface for battery charging, configuration, and data recovery.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Fully integrated support for Li-Po rechargeable batteries.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Uses Li-Po to fire e-matches, can be modified to support
+ optional separate pyro battery if needed.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ 2.75 x 1 inch board designed to fit inside 29mm air-frame coupler tube.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </section>
+ <section>
+ <title>TeleMetrum v1 Specifications</title>
<itemizedlist>
<listitem>
<para>
</listitem>
<listitem>
<para>
- 70cm ham-band transceiver for telemetry down-link.
+ 70cm, 10mW ham-band transceiver for telemetry down-link.
</para>
</listitem>
<listitem>
</itemizedlist>
</section>
<section>
- <title>TeleMini Specifications</title>
+ <title>
+ TeleMini v2.0 Specifications
+ </title>
<itemizedlist>
<listitem>
<para>
</listitem>
<listitem>
<para>
- 70cm ham-band transceiver for telemetry down-link.
+ 70cm, 10mW ham-band transceiver for telemetry down-link.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Barometric pressure sensor good to 100k feet MSL.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ On-board 1 megabyte non-volatile memory for flight data storage.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ USB interface for configuration, and data recovery.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Support for Li-Po rechargeable batteries (using an
+ external charger), or any 3.7-15V external battery.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Uses Li-Po to fire e-matches, can be modified to support
+ optional separate pyro battery if needed.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ 1.5 x .8 inch board designed to fit inside 24mm air-frame coupler tube.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </section>
+ <section>
+ <title>
+ TeleMini v1.0 Specifications
+ </title>
+ <itemizedlist>
+ <listitem>
+ <para>
+ Recording altimeter for model rocketry.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Supports dual deployment (can fire 2 ejection charges).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ 70cm, 10mW ham-band transceiver for telemetry down-link.
</para>
</listitem>
<listitem>
</listitem>
</itemizedlist>
</section>
+ <section>
+ <title>
+ EasyMini Specifications
+ </title>
+ <itemizedlist>
+ <listitem>
+ <para>
+ Recording altimeter for model rocketry.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Supports dual deployment (can fire 2 ejection charges).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Barometric pressure sensor good to 100k feet MSL.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ On-board 1 megabyte non-volatile memory for flight data storage.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ USB interface for configuration, and data recovery.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Support for Li-Po rechargeable batteries (using an
+ external charger), or any 3.7-15V external battery.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Uses Li-Po to fire e-matches, can be modified to support
+ optional separate pyro battery if needed.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ 1.5 x .8 inch board designed to fit inside 24mm air-frame coupler tube.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </section>
</chapter>
<chapter>
<title>FAQ</title>
<para>
- TeleMetrum seems to shut off when disconnected from the
- computer. Make sure the battery is adequately charged. Remember the
+ <emphasis>TeleMetrum seems to shut off when disconnected from the
+ computer.</emphasis> <?linebreak?>
+ Make sure the battery is adequately charged. Remember the
unit will pull more power than the USB port can deliver before the
- GPS enters "locked" mode. The battery charges best when TeleMetrum
+ GPS enters “locked” mode. The battery charges best when TeleMetrum
is turned off.
</para>
<para>
- It's impossible to stop the TeleDongle when it's in "p" mode, I have
- to unplug the USB cable? Make sure you have tried to "escape out" of
+ <emphasis>It's impossible to stop the TeleDongle when it's in “p” mode, I have
+ to unplug the USB cable? </emphasis><?linebreak?>
+ Make sure you have tried to “escape out” of
this mode. If this doesn't work the reboot procedure for the
TeleDongle *is* to simply unplug it. 'cu' however will retain it's
- outgoing buffer IF your "escape out" ('~~') does not work.
+ outgoing buffer IF your “escape out” ('~~') does not work.
At this point using either 'ao-view' (or possibly
'cutemon') instead of 'cu' will 'clear' the issue and allow renewed
communication.
</para>
<para>
- The amber LED (on the TeleMetrum) lights up when both
- battery and USB are connected. Does this mean it's charging?
+ <emphasis>The amber LED (on the TeleMetrum) lights up when both
+ battery and USB are connected. Does this mean it's charging?
+ </emphasis><?linebreak?>
Yes, the yellow LED indicates the charging at the 'regular' rate.
If the led is out but the unit is still plugged into a USB port,
then the battery is being charged at a 'trickle' rate.
</para>
<para>
- There are no "dit-dah-dah-dit" sound or lights like the manual mentions?
- That's the "pad" mode. Weak batteries might be the problem.
- It is also possible that the TeleMetrum is horizontal and the output
- is instead a "dit-dit" meaning 'idle'. For TeleMini, it's possible that
- it received a command packet which would have left it in "pad" mode.
+ <emphasis>There are no “dit-dah-dah-dit” sound or lights like the manual
+ mentions?</emphasis><?linebreak?>
+ That's the “pad” mode. Weak batteries might be the problem.
+ It is also possible that the flight computer is horizontal and the
+ output
+ is instead a “dit-dit” meaning 'idle'. For TeleMini, it's possible that
+ it received a command packet which would have left it in “pad” mode.
</para>
<para>
- How do I save flight data?
+ <emphasis>How do I save flight data?</emphasis><?linebreak?>
Live telemetry is written to file(s) whenever AltosUI is connected
to the TeleDongle. The file area defaults to ~/TeleMetrum
but is easily changed using the menus in AltosUI. The files that
</para>
<para>
Now might be a good time to take a break and read the rest of this
- manual, particularly about the two "modes" that the altimeters
+ manual, particularly about the two “modes” that the altimeters
can be placed in. TeleMetrum uses the position of the device when booting
- up will determine whether the unit is in "pad" or "idle" mode. TeleMini
- enters "idle" mode when it receives a command packet within the first 5 seconds
- of being powered up, otherwise it enters "pad" mode.
+ up will determine whether the unit is in “pad” or “idle” mode. TeleMini
+ enters “idle” mode when it receives a command packet within the first 5 seconds
+ of being powered up, otherwise it enters “pad” mode.
</para>
<para>
You can access an altimeter in idle mode from the TeleDongle's USB
connection using the radio link
by issuing a 'p' command to the TeleDongle. Practice connecting and
disconnecting ('~~' while using 'cu') from the altimeter. If
- you cannot escape out of the "p" command, (by using a '~~' when in
+ you cannot escape out of the “p” command, (by using a '~~' when in
CU) then it is likely that your kernel has issues. Try a newer version.
</para>
<para>
is in 'idle mode' and then place the
rocket vertically on the launch pad, walk away and then issue a
reboot command. The altimeter will reboot and start sending data
- having changed to the "pad" mode. If the TeleDongle is not receiving
+ having changed to the “pad” mode. If the TeleDongle is not receiving
this data, you can disconnect 'cu' from the TeleDongle using the
procedures mentioned above and THEN connect to the TeleDongle from
inside 'ao-view'. If this doesn't work, disconnect from the
These images, when printed, provide precise templates for the
mounting holes in Altus Metrum flight computers
</para>
+ <section>
+ <title>TeleMega template</title>
+ <para>
+ TeleMega has overall dimensions of 1.250 x 3.250 inches, and
+ the mounting holes are sized for use with 4-40 or M3 screws.
+ </para>
+ <informalfigure>
+ <mediaobject id="TeleMegaTemplate">
+ <imageobject>
+ <imagedata format="SVG" fileref="telemega-outline.svg"/>
+ </imageobject>
+ </mediaobject>
+ </informalfigure>
+ </section>
<section>
<title>TeleMetrum template</title>
<para>
TeleMetrum has overall dimensions of 1.000 x 2.750 inches, and the
mounting holes are sized for use with 4-40 or M3 screws.
</para>
- <mediaobject id="TeleMetrumTemplate">
- <imageobject>
- <imagedata format="SVG" fileref="telemetrum.svg"/>
- </imageobject>
- </mediaobject>
+ <informalfigure>
+ <mediaobject id="TeleMetrumTemplate">
+ <imageobject>
+ <imagedata format="SVG" fileref="telemetrum.svg"/>
+ </imageobject>
+ </mediaobject>
+ </informalfigure>
+ </section>
+ <section>
+ <title>TeleMini v2/EasyMini template</title>
+ <para>
+ TeleMini v2 and EasyMini have overall dimensions of 0.800 x 1.500 inches, and the
+ mounting holes are sized for use with 4-40 or M3 screws.
+ </para>
+ <informalfigure>
+ <mediaobject id="MiniTemplate">
+ <imageobject>
+ <imagedata format="SVG" fileref="easymini-outline.svg"/>
+ </imageobject>
+ </mediaobject>
+ </informalfigure>
</section>
<section>
- <title>TeleMini template</title>
+ <title>TeleMini v1 template</title>
<para>
TeleMini has overall dimensions of 0.500 x 1.500 inches, and the
mounting holes are sized for use with 2-56 or M2 screws.
</para>
- <mediaobject id="TeleMiniTemplate">
- <imageobject>
- <imagedata format="SVG" fileref="telemini.svg"/>
- </imageobject>
- </mediaobject>
+ <informalfigure>
+ <mediaobject id="TeleMiniTemplate">
+ <imageobject>
+ <imagedata format="SVG" fileref="telemini.svg"/>
+ </imageobject>
+ </mediaobject>
+ </informalfigure>
</section>
</appendix>
<appendix>
<title>Calibration</title>
<para>
- There are only two calibrations required for a TeleMetrum board, and
- only one for TeleDongle and TeleMini. All boards are shipped from
- the factory pre-calibrated, but the procedures are documented here
- in case they are ever needed. Re-calibration is not supported by
- AltosUI, you must connect to the board with a serial terminal program
- and interact directly with the on-board command interpreter to effect
- calibration.
+ There are only two calibrations required for TeleMetrum and
+ TeleMega, and only one for TeleDongle, TeleMini and EasyMini.
+ All boards are shipped from the factory pre-calibrated, but
+ the procedures are documented here in case they are ever
+ needed. Re-calibration is not supported by AltosUI, you must
+ connect to the board with a serial terminal program and
+ interact directly with the on-board command interpreter to
+ effect calibration.
</para>
<section>
<title>Radio Frequency</title>
<para>
- The radio frequency is synthesized from a clock based on the 48 MHz
+ The radio frequency is synthesized from a clock based on the
crystal on the board. The actual frequency of this oscillator
must be measured to generate a calibration constant. While our
GFSK modulation
should generally not be required.
</para>
<para>
- To calibrate the radio frequency, connect the UHF antenna port to a
- frequency counter, set the board to 434.550MHz, and use the 'C'
- command in the on-board command interpreter to generate a CW
- carrier. For TeleMetrum, this is best done over USB. For TeleMini,
- note that the only way to escape the 'C' command is via power cycle
- since the board will no longer be listening for commands once it
- starts generating a CW carrier.
+ To calibrate the radio frequency, connect the UHF antenna
+ port to a frequency counter, set the board to 434.550MHz,
+ and use the 'C' command in the on-board command interpreter
+ to generate a CW carrier. For USB-enabled boards, this is
+ best done over USB. For TeleMini v1, note that the only way
+ to escape the 'C' command is via power cycle since the board
+ will no longer be listening for commands once it starts
+ generating a CW carrier.
</para>
<para>
Wait for the transmitter temperature to stabilize and the frequency
command. Testing with the 'C' command again should show a carrier
within a few tens of Hertz of the intended frequency.
As with all 'c' sub-commands, follow this with a 'c w' to write the
- change to the parameter block in the on-board DataFlash chip.
+ change to the parameter block in the on-board storage chip.
</para>
<para>
Note that any time you re-do the radio frequency calibration, the
</para>
</section>
<section>
- <title>TeleMetrum Accelerometer</title>
+ <title>TeleMetrum and TeleMega Accelerometers</title>
<para>
- The TeleMetrum accelerometer we use has its own 5 volt power
- supply and
- the output must be passed through a resistive voltage divider to match
- the input of our 3.3 volt ADC. This means that unlike the barometric
- sensor, the output of the acceleration sensor is not ratio-metric to
- the ADC converter, and calibration is required. Explicitly
- calibrating the accelerometers also allows us to load any device
- from a Freescale family that includes at least +/- 40g, 50g, 100g,
- and 200g parts. Using gravity,
- a simple 2-point calibration yields acceptable results capturing both
- the different sensitivities and ranges of the different accelerometer
- parts and any variation in power supply voltages or resistor values
- in the divider network.
+ While barometric sensors are factory-calibrated,
+ accelerometers are not, and so each must be calibrated once
+ installed in a flight computer. Explicitly calibrating the
+ accelerometers also allows us to load any compatible device.
+ We perform a two-point calibration using gravity.
</para>
<para>
To calibrate the acceleration sensor, use the 'c a 0' command. You
The +1g and -1g calibration points are included in each telemetry
frame and are part of the header stored in onboard flash to be
downloaded after flight. We always store and return raw ADC
- samples for each sensor... so nothing is permanently "lost" or
- "damaged" if the calibration is poor.
+ samples for each sensor... so nothing is permanently “lost” or
+ “damaged” if the calibration is poor.
</para>
<para>
In the unlikely event an accel cal goes badly, it is possible
- that TeleMetrum may always come up in 'pad mode' and as such not be
- listening to either the USB or radio link. If that happens,
- there is a special hook in the firmware to force the board back
- in to 'idle mode' so you can re-do the cal. To use this hook, you
- just need to ground the SPI clock pin at power-on. This pin is
- available as pin 2 on the 8-pin companion connector, and pin 1 is
- ground. So either carefully install a fine-gauge wire jumper
- between the two pins closest to the index hole end of the 8-pin
- connector, or plug in the programming cable to the 8-pin connector
- and use a small screwdriver or similar to short the two pins closest
- to the index post on the 4-pin end of the programming cable, and
- power up the board. It should come up in 'idle mode' (two beeps),
- allowing a re-cal.
+ that TeleMetrum or TeleMega may always come up in 'pad mode'
+ and as such not be listening to either the USB or radio link.
+ If that happens, there is a special hook in the firmware to
+ force the board back in to 'idle mode' so you can re-do the
+ cal. To use this hook, you just need to ground the SPI clock
+ pin at power-on. This pin is available as pin 2 on the 8-pin
+ companion connector, and pin 1 is ground. So either
+ carefully install a fine-gauge wire jumper between the two
+ pins closest to the index hole end of the 8-pin connector, or
+ plug in the programming cable to the 8-pin connector and use
+ a small screwdriver or similar to short the two pins closest
+ to the index post on the 4-pin end of the programming cable,
+ and power up the board. It should come up in 'idle mode'
+ (two beeps), allowing a re-cal.
</para>
</section>
</appendix>
- <appendix
- xmlns:xi="http://www.w3.org/2001/XInclude">
+ <appendix>
<title>Release Notes</title>
- <simplesect><title>Version 1.21</title><xi:include href="release-notes-1.2.1.xsl" xpointer="xpointer(/article/*)"/></simplesect>
- <simplesect><title>Version 1.2</title><xi:include href="release-notes-1.2.xsl" xpointer="xpointer(/article/*)"/></simplesect>
- <simplesect><title>Version 1.1.1</title><xi:include href="release-notes-1.1.1.xsl" xpointer="xpointer(/article/*)"/></simplesect>
- <simplesect><title>Version 1.1</title><xi:include href="release-notes-1.1.xsl" xpointer="xpointer(/article/*)"/></simplesect>
- <simplesect><title>Version 1.0.1</title><xi:include href="release-notes-1.0.1.xsl" xpointer="xpointer(/article/*)"/></simplesect>
- <simplesect><title>Version 0.9.2</title><xi:include href="release-notes-0.9.2.xsl" xpointer="xpointer(/article/*)"/></simplesect>
- <simplesect><title>Version 0.9</title><xi:include href="release-notes-0.9.xsl" xpointer="xpointer(/article/*)"/></simplesect>
- <simplesect><title>Version 0.8</title><xi:include href="release-notes-0.8.xsl" xpointer="xpointer(/article/*)"/></simplesect>
- <simplesect><title>Version 0.7.1</title><xi:include href="release-notes-0.7.1.xsl" xpointer="xpointer(/article/*)"/></simplesect>
+ <simplesect>
+ <title>Version 1.3</title>
+ <xi:include
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ href="release-notes-1.3.xsl"
+ xpointer="xpointer(/article/*)"/>
+ </simplesect>
+ <simplesect>
+ <title>Version 1.2.1</title>
+ <xi:include
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ href="release-notes-1.2.1.xsl"
+ xpointer="xpointer(/article/*)"/>
+ </simplesect>
+ <simplesect>
+ <title>Version 1.2</title>
+ <xi:include
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ href="release-notes-1.2.xsl"
+ xpointer="xpointer(/article/*)"/>
+ </simplesect>
+ <simplesect>
+ <title>Version 1.1.1</title>
+ <xi:include
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ href="release-notes-1.1.1.xsl"
+ xpointer="xpointer(/article/*)"/>
+ </simplesect>
+ <simplesect>
+ <title>Version 1.1</title>
+ <xi:include
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ href="release-notes-1.1.xsl"
+ xpointer="xpointer(/article/*)"/>
+ </simplesect>
+ <simplesect>
+ <title>Version 1.0.1</title>
+ <xi:include
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ href="release-notes-1.0.1.xsl"
+ xpointer="xpointer(/article/*)"/>
+ </simplesect>
+ <simplesect>
+ <title>Version 0.9.2</title>
+ <xi:include
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ href="release-notes-0.9.2.xsl"
+ xpointer="xpointer(/article/*)"/>
+ </simplesect>
+ <simplesect>
+ <title>Version 0.9</title>
+ <xi:include
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ href="release-notes-0.9.xsl"
+ xpointer="xpointer(/article/*)"/>
+ </simplesect>
+ <simplesect>
+ <title>Version 0.8</title>
+ <xi:include
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ href="release-notes-0.8.xsl"
+ xpointer="xpointer(/article/*)"/>
+ </simplesect>
+ <simplesect>
+ <title>Version 0.7.1</title>
+ <xi:include
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ href="release-notes-0.7.1.xsl"
+ xpointer="xpointer(/article/*)"/>
+ </simplesect>
</appendix>
</book>
-<!-- LocalWords: Altusmetrum
+<!-- LocalWords: Altusmetrum
-->
<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"/usr/share/xml/docbook/schema/dtd/4.5/docbookx.dtd">
<article>
The Companion Port provides two different functions:
<itemizedlist>
<listitem>
+ <para>
Power. Both battery-level and 3.3V regulated power are
available. Note that the amount of regulated power is not
huge; TeleMetrum contains a 150mA regulator and uses, at
peak, about 120mA or so. For applications needing more than
a few dozen mA, placing a separate regulator on them and
using the battery for power is probably a good idea.
+ </para>
</listitem>
<listitem>
+ <para>
SPI. The flight computer operates as a SPI master, using
a protocol defined in this document. Companion boards
provide a matching SPI slave implementation which supplies
telemetry information for the radio downlink during flight
+ </para>
</listitem>
</itemizedlist>
</para>
</section>
<section>
<title>SPI Message Formats</title>
+ <para>
This section first defines the command message format sent from
the flight computer to the companion board, and then the various
reply message formats for each type of command message.
+ </para>
<section>
<title>Command Message</title>
<table frame='all'>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="427.5"
+ height="270"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="easymini-outline.svg">
+ <defs
+ id="defs4">
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Arrow2Lend"
+ style="overflow:visible;">
+ <path
+ id="path3866"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(1.1) rotate(180) translate(1,0)" />
+ </marker>
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 526.18109 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="744.09448 : 526.18109 : 1"
+ inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+ id="perspective10" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="6.4827171"
+ inkscape:cx="163.56238"
+ inkscape:cy="128.7277"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ inkscape:window-width="1146"
+ inkscape:window-height="846"
+ inkscape:window-x="0"
+ inkscape:window-y="26"
+ inkscape:window-maximized="0"
+ units="in">
+ <inkscape:grid
+ type="xygrid"
+ id="grid3005" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(0,-782.35975)">
+ <rect
+ style="fill:none;stroke:#000000;stroke-width:0.29770368;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ id="rect2816"
+ width="135.0623"
+ height="72.062294"
+ x="89.986351"
+ y="890.31354" />
+ <g
+ inkscape:tile-y0="681.11218"
+ inkscape:tile-x0="90"
+ id="use3601"
+ transform="translate(5.5965353,264.43715)">
+ <path
+ sodipodi:type="arc"
+ style="fill:none;stroke:#000000;stroke-width:1.41507304;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ id="path3611"
+ sodipodi:cx="116"
+ sodipodi:cy="739.36218"
+ sodipodi:rx="17"
+ sodipodi:ry="18"
+ d="m 133,739.36218 c 0,9.94113 -7.61116,18 -17,18 -9.38884,0 -17,-8.05887 -17,-18 0,-9.94112 7.61116,-18 17,-18 9.38884,0 17,8.05888 17,18 z"
+ transform="matrix(0.32722728,0,0,0.3090422,57.632964,458.24316)" />
+ <path
+ style="color:#000000;fill:#67615b;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.10785132;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="m 95.625,692.36218 0,-11.25"
+ id="path3613"
+ sodipodi:nodetypes="cc"
+ inkscape:connector-curvature="0" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path3615"
+ d="m 90,686.73718 11.25,0"
+ style="color:#000000;fill:#67615b;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.09;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ inkscape:tile-y0="681.11218"
+ inkscape:tile-x0="90"
+ id="use3603"
+ transform="translate(118.09654,214.93471)">
+ <path
+ sodipodi:type="arc"
+ style="fill:none;stroke:#000000;stroke-width:1.41507304;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ id="path3619"
+ sodipodi:cx="116"
+ sodipodi:cy="739.36218"
+ sodipodi:rx="17"
+ sodipodi:ry="18"
+ d="m 133,739.36218 c 0,9.94113 -7.61116,18 -17,18 -9.38884,0 -17,-8.05887 -17,-18 0,-9.94112 7.61116,-18 17,-18 9.38884,0 17,8.05888 17,18 z"
+ transform="matrix(0.32722728,0,0,0.3090422,57.632964,458.24316)" />
+ <path
+ style="color:#000000;fill:#67615b;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.10785132;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="m 95.625,692.36218 0,-11.25"
+ id="path3621"
+ sodipodi:nodetypes="cc"
+ inkscape:connector-curvature="0" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path3623"
+ d="m 90,686.73718 11.25,0"
+ style="color:#000000;fill:#67615b;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.09;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ inkscape:tile-y0="681.11218"
+ inkscape:tile-x0="90"
+ id="use3605"
+ transform="translate(118.09654,264.39215)">
+ <path
+ sodipodi:type="arc"
+ style="fill:none;stroke:#000000;stroke-width:1.41507304;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ id="path3627"
+ sodipodi:cx="116"
+ sodipodi:cy="739.36218"
+ sodipodi:rx="17"
+ sodipodi:ry="18"
+ d="m 133,739.36218 c 0,9.94113 -7.61116,18 -17,18 -9.38884,0 -17,-8.05887 -17,-18 0,-9.94112 7.61116,-18 17,-18 9.38884,0 17,8.05888 17,18 z"
+ transform="matrix(0.32722728,0,0,0.3090422,57.632964,458.24316)" />
+ <path
+ style="color:#000000;fill:#67615b;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.10785132;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="m 95.625,692.36218 0,-11.25"
+ id="path3629"
+ sodipodi:nodetypes="cc"
+ inkscape:connector-curvature="0" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path3631"
+ d="m 90,686.73718 11.25,0"
+ style="color:#000000;fill:#67615b;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.09;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ inkscape:tile-y0="681.11218"
+ inkscape:tile-x0="90"
+ id="use3607"
+ transform="translate(5.5965353,214.93471)">
+ <path
+ sodipodi:type="arc"
+ style="fill:none;stroke:#000000;stroke-width:1.41507304;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ id="path3635"
+ sodipodi:cx="116"
+ sodipodi:cy="739.36218"
+ sodipodi:rx="17"
+ sodipodi:ry="18"
+ d="m 133,739.36218 c 0,9.94113 -7.61116,18 -17,18 -9.38884,0 -17,-8.05887 -17,-18 0,-9.94112 7.61116,-18 17,-18 9.38884,0 17,8.05888 17,18 z"
+ transform="matrix(0.32722728,0,0,0.3090422,57.632964,458.24316)" />
+ <path
+ style="color:#000000;fill:#67615b;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.10785132;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="m 95.625,692.36218 0,-11.25"
+ id="path3637"
+ sodipodi:nodetypes="cc"
+ inkscape:connector-curvature="0" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path3639"
+ d="m 90,686.73718 11.25,0"
+ style="color:#000000;fill:#67615b;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.09;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.18224967;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;marker-end:url(#Arrow2Lend);visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="m 116.64314,926.46226 64.93789,0"
+ id="path2829"
+ sodipodi:nodetypes="cc"
+ inkscape:connector-curvature="0" />
+ <text
+ xml:space="preserve"
+ style="font-size:22px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Minion Pro;-inkscape-font-specification:Minion Pro"
+ x="912.26929"
+ y="-186.53189"
+ id="text4236"
+ sodipodi:linespacing="125%"
+ transform="matrix(0,1,-1,0,0,0)"><tspan
+ sodipodi:role="line"
+ x="912.26929"
+ y="-186.53189"
+ id="tspan4242">UP</tspan></text>
+ </g>
+</svg>
</revision>
</revhistory>
</bookinfo>
- <acknowledgements>
+ <dedication>
+ <title>Acknowledgements</title>
<para>
Thanks to John Lyngdal for suggesting that we build something like this.
</para>
NAR #88757, TRA #12200
</literallayout>
</para>
- </acknowledgements>
+ </dedication>
<chapter>
<title>Quick Start Guide</title>
<para>
<para>
Finish preparing the rocket for flight. After the
previous flight data have been reported, MicroPeak waits for
- 30 seconds before starting to check for launch. This gives
+ one minute before starting to check for launch. This gives
you time to finish assembling the rocket. As those
activities might cause pressure changes inside the airframe,
MicroPeak might accidentally detect boost. If you need to do
- anything to the airframe after the 30 second window passes,
+ anything to the airframe after the one minute window passes,
make sure to be careful not to disturb the altimeter. The
- LED will remain dark during the 30 second delay, but after
+ LED will remain dark during the one minute delay, but after
that, it will start blinking once every 3 seconds.
</para>
</listitem>
<listitem>
<para>
- Fly the rocket. Once the rocket passes about 10m in height
- (32 feet), the micro-controller will record the ground
+ Fly the rocket. Once the rocket passes about 30m in height
+ (100 feet), the micro-controller will record the ground
pressure and track the pressure seen during the flight. In
this mode, the LED flickers rapidly. When the rocket lands,
and the pressure stabilizes, the micro-controller will record
<section>
<title>Lithium Battery</title>
<para>
- The CR1025 battery used by MicroPeak holes 30mAh of power,
+ The CR1025 battery used by MicroPeak holds 30mAh of power,
which is sufficient to run for over 40 hours. Because
MicroPeak powers down on landing, run time includes only time
sitting on the launch pad or during flight.
</para>
<itemizedlist>
<listitem>
+<para>
Receive and log telemetry from a connected TeleDongle
device. All data received is saved to log files named with the
current date and the connected rocket serial and flight
numbers. There is no mode in which telemetry data will not be
saved.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Download logged data from TeleMetrum devices, either through a
direct USB connection or over the air through a TeleDongle
device.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Configure a TeleMetrum device, setting the radio channel,
callsign, apogee delay and main deploy height. This can be done
through either a USB connection or over a radio link via a
TeleDongle device.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Replay a flight in real-time. This takes a saved telemetry log
or eeprom download and replays it through the user interface so
you can relive your favorite rocket flights.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Reprogram Altus Metrum devices. Using an Altus Metrum device
connected via USB, another Altus Metrum device can be
reprogrammed using the supplied programming cable between the
two devices.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Export Flight data to a comma-separated-values file. This takes
either telemetry or on-board flight data and generates data
suitable for use in external applications. All data is exported
using standard units so that no device-specific knowledge is
needed to handle the data.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Speak to you during the flight. Instead of spending the flight
hunched over your laptop looking at the screen, enjoy the view
while the computer tells you what’s going on up there. During
range information to try and help you find your rocket in the
air. Once on the ground, the direction and distance are
reported.
- </listitem>
+ </para>
+</listitem>
</itemizedlist>
</article>
</para>
<itemizedlist>
<listitem>
+<para>
Post-flight graphing tool. This lets you explore the behaviour
of your rocket after flight with a scroll-able and zoom-able
chart showing the altitude, speed and acceleration of the
airframe along with events recorded by the flight computer. You
can export graphs to PNG files, or print them directly.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Real-time moving map which overlays the in-progress flight on
satellite imagery fetched from Google Maps. This lets you see in
pictures where your rocket has landed, allowing you to plan
recovery activities more accurately.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Wireless recovery system testing. Prep your rocket for flight
and test fire the deployment charges to make sure things work as
expected. All without threading wires through holes in your
airframe.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Optimized flight status displays. Each flight state now has it's
own custom 'tab' in the flight monitoring window so you can
focus on the most important details. Pre-flight, the system
they're all green and your rocket is ready for flight. There are
also tabs for ascent, descent and landing along with the
original tabular view of the data.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Monitor multiple flights simultaneously. If you have more than
one TeleDongle, you can monitor a flight with each one on the
same computer.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Automatic flight monitoring at startup. Plug TeleDongle into the
machine before starting AltosUI and it will automatically
connect to it and prepare to monitor a flight.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Exports Google Earth flight tracks. Using the Keyhole Markup
Language (.kml) file format, this provides a 3D view of your
rocket flight through the Google Earth program.
- </listitem>
+ </para>
+</listitem>
</itemizedlist>
</article>
</para>
<itemizedlist>
<listitem>
+<para>
Fix plotting problems due to missing file in the Mac OS install image.
+</para>
</listitem>
<listitem>
+<para>
Always read whole eeprom blocks, mark empty records invalid, display parsing errors to user.
+</para>
</listitem>
<listitem>
+ <para>
Add software version to Configure AltosUI dialog
+</para>
</listitem>
</itemizedlist>
</article>
</para>
<itemizedlist>
<listitem>
+ <para>
Support for TeleMetrum v1.1 hardware. Sources for the flash
memory part used in v1.0 dried up, so v1.1 uses a different part
which required a new driver and support for explicit flight log
erasing.
+</para>
</listitem>
<listitem>
+ <para>
Multiple flight log support. This stores more than one flight
log in the on-board flash memory. It also requires the user to
explicitly erase flights so that you won't lose flight logs just
because you fly the same board twice in one day.
+</para>
</listitem>
<listitem>
+ <para>
Telemetry support for devices with serial number >=
256. Previous versions used a telemetry packet format that
provided only 8 bits for the device serial number. This change
requires that both ends of the telemetry link be running the 0.9
firmware or they will not communicate.
+</para>
</listitem>
</itemizedlist>
</article>
AltOS Firmware Changes
<itemizedlist>
<listitem>
+<para>
Add TeleMini v1.0 support. Firmware images for TeleMini are
included in AltOS releases.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Change telemetry to be encoded in multiple 32-byte packets. This
enables support for TeleMini and other devices without requiring
further updates to the TeleDongle firmware.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Support operation of TeleMetrum with the antenna pointing
aft. Previous firmware versions required the antenna to be
pointing upwards, now there is a configuration option allowing
the antenna to point aft, to aid installation in some airframes.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Ability to disable telemetry. For airframes where an antenna
just isn't possible, or where radio transmissions might cause
trouble with other electronics, there's a configuration option
to disable all telemetry. Note that the board will still
enable the radio link in idle mode.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Arbitrary frequency selection. The radios in Altus Metrum
devices can be programmed to a wide range of frequencies, so
instead of limiting devices to 10 pre-selected 'channels', the
70cm band. Note that the RF matching circuit on the boards is
tuned for around 435MHz, so frequencies far from that may
reduce the available range.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Kalman-filter based flight-tracking. The model based sensor
fusion approach of a Kalman filter means that AltOS now
computes apogee much more accurately than before, generally
allows the baro-only TeleMini device to correctly identify
Mach transitions, avoiding the error-prone selection of a Mach
delay.
- </listitem>
+ </para>
+</listitem>
</itemizedlist>
</para>
<para>
AltosUI Changes
<itemizedlist>
<listitem>
+<para>
Wait for altimeter when using packet mode. Instead of quicly
timing out when trying to initialize a packet mode
configuration connection, AltosUI now waits indefinitely for
the remote device to appear, providing a cancel button should
the user get bored. This is necessary as the TeleMini can only
be placed in "Idle" mode if AltosUI is polling it.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Add main/apogee voltage graphs to the data plot. This provides
a visual indication if the igniters fail before being fired.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Scan for altimeter devices by watching the defined telemetry
frequencies. This avoids the problem of remembering what
frequency a device was configured to use, which is especially
important with TeleMini which does not include a USB connection.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Monitor altimeter state in "Idle" mode. This provides much of
the information presented in the "Pad" dialog from the Monitor
Flight command, monitoring the igniters, battery and GPS
status withing requiring the flight computer to be armed and
ready for flight.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Pre-load map images from home. For those launch sites which
don't provide free Wi-Fi, this allows you to download the
necessary satellite images given the location of the launch
you've got a launch site not on that list, please send the
name of it, latitude and longitude along with a link to the
web site of the controlling club to the altusmetrum mailing list.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Flight statistics are now displayed in the Graph data
window. These include max height/speed/accel, average descent
rates and a few other bits of information. The Graph Data
window can now be reached from the 'Landed' tab in the Monitor
Flight window so you can immediately see the results of a
flight.
- </listitem>
+ </para>
+</listitem>
</itemizedlist>
</para>
</article>
AltOS Firmware Changes
<itemizedlist>
<listitem>
+<para>
TeleMetrum v1.0 boards use the AT45DB081D flash memory part to
store flight data, which is different from later TeleMetrum
boards. The AltOS v1.1 driver for this chip couldn't erase
configuration values. This bug doesn't affect newer TeleMetrum
boards, and it doesn't affect the safety of rockets flying
version 1.1 firmware.
- </listitem>
+ </para>
+</listitem>
</itemizedlist>
</para>
<para>
AltosUI Changes
<itemizedlist>
<listitem>
+<para>
Creating a Google Earth file (KML) from on-board flight data
(EEPROM) would generate an empty file. The code responsible
for reading the EEPROM file wasn't ever setting the GPS valid
bits, and so the KML export code thought there was no GPS data
in the file.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
The “Landed” tab was displaying all values in metric units,
even when AltosUI was configured to display imperial
units. Somehow I just missed this tab when doing the units stuff.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
The “Descent” tab displays the range to the rocket, which is a
combination of the over-the-ground distance to the rockets
current latitude/longitude and the height of the rocket. As
eventually land. A new “Ground Distance” field has been added
which displays the distance to a spot right underneath the
rocket.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Sensor data wasn't being displayed for TeleMini flight
computers in Monitor Idle mode, including things like battery
voltage. The code that picked which kinds of data to fetch
from the flight computer was missing a check for TeleMini when
deciding whether to fetch the analog sensor data.
- </listitem>
+ </para>
+</listitem>
</itemizedlist>
</para>
</article>
AltOS Firmware Changes
<itemizedlist>
<listitem>
+<para>
Add apogee-lockout value. Overrides the apogee detection logic to
prevent incorrect apogee charge firing.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Fix a bug where the data reported in telemetry packets was
from 320ms ago.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Force the radio frequency to 434.550MHz when the debug clock
pin is connected to ground at boot time. This provides a way
to talk to a TeleMini which is configured to some unknown frequency.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Provide RSSI values for Monitor Idle mode. This makes it easy to check radio
range without needing to go to flight mode.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Fix a bug which caused the old received telemetry packets to
be retransmitted over the USB link when the radio was turned
off and back on.
- </listitem>
+ </para>
+</listitem>
</itemizedlist>
</para>
<para>
AltosUI Changes
<itemizedlist>
<listitem>
+<para>
Fix a bug that caused GPS ready to happen too quickly. The
software was using every telemetry packet to signal new GPS
data, which caused GPS ready to be signalled after 10 packets
instead of 10 GPS updates.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Fix Google Earth data export to work with recent versions. The
google earth file loading code got a lot pickier, requiring
some minor white space changes in the export code.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Make the look-n-feel configurable, providing a choice from
the available options.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Add an 'Age' element to mark how long since a telemetry packet
has been received. Useful to quickly gauge whether
communications with the rocket are still active.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Add 'Configure Ground Station' dialog to set the radio
frequency used by a particular TeleDongle without having to go
through the flight monitor UI.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Add configuration for the new apogee-lockout value. A menu provides a list of
reasonable values, or the value can be set by hand.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Changed how flight data are downloaded. Now there's an initial
dialog asking which flights to download, and after that
finishes, a second dialog comes up asking which flights to delete.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Re-compute time spent in each state for the flight graph; this
figures out the actual boost and landing times instead of
using the conservative values provide by the flight
electronics. This improves the accuracy of the boost
acceleration and main descent rate computations.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Make AltosUI run on Mac OS Lion. The default Java heap space
was dramatically reduced for this release causing much of the
UI to fail randomly. This most often affected the satellite
mapping download and displays.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Change how data are displayed in the 'table' tab of the flight
monitoring window. This eliminates entries duplicated from the
header and adds both current altitude and pad altitude, which
are useful in 'Monitor Idle' mode.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Add Imperial units mode to present data in feet instead of
meters.
- </listitem>
+ </para>
+</listitem>
</itemizedlist>
</para>
</article>
AltOS Firmware Changes
<itemizedlist>
<listitem>
+<para>
Add support for TeleBT
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
In TeleMini recovery mode (when booted with the outer two
debug pins connected together), the radio parameters are also
set back to defaults (434.550MHz, N0CALL, factory radio cal).
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Add support for reflashing the SkyTraq GPS chips. This
requires special host-side code which currently only exists
for Linux.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Correct Kalman filter model error covariance matrix. The
values used previously assumed continuous measurements instead
of discrete measurements.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Fix some bugs in the USB driver for TeleMetrum and TeleDongle
that affected Windows users.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Adjusted the automatic gain control parameters that affect
receive performance for TeleDongle. Field tests indicate that this
may improve receive performance somewhat.
- </listitem>
+ </para>
+</listitem>
</itemizedlist>
</para>
<para>
AltosUI Changes
<itemizedlist>
<listitem>
+<para>
Handle missing GPS lock in 'Descent' tab. Previously, if the
GPS position of the pad was unknown, an exception would be
raised, breaking the Descent tab contents.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Improve the graph, adding tool-tips to show values near the
cursor and making the displayed set of values configurable,
adding all of the flight data as options while leaving the
default settings alone so that the graph starts by showing
height, speed and acceleration.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Make the initial position of the AltosUI top level window
configurable. Along with this change, the other windows will
pop up at 'sensible' places now, instead of on top of one
another.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Add callsign to Monitor idle window and connecting
dialogs. This makes it clear which callsign is being used so
that the operator will be aware that it must match the flight
computer value or no communication will work.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
When downloading flight data, display the block number so that
the user has some sense of progress. Unfortunately, we don't
know how many blocks will need to be downloaded, but at least
it isn't just sitting there doing nothing for a long time.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Add GPS data and a map to the graph window. This lets you see
a complete summary of the flight without needing to 'replay'
the whole thing.
- </listitem>
+ </para>
+</listitem>
</itemizedlist>
</para>
</article>
AltOS Firmware Changes
<itemizedlist>
<listitem>
+<para>
Add MicroPeak support. This includes support for the ATtiny85
processor and adaptations to the core code to allow for
devices too small to run the multi-tasking scheduler.
- </listitem>
+ </para>
+</listitem>
</itemizedlist>
</para>
<para>
MicroPeak UI changes
<itemizedlist>
<listitem>
+<para>
Added this new application
- </listitem>
+ </para>
+</listitem>
</itemizedlist>
</para>
<para>
Distribution Changes
<itemizedlist>
<listitem>
+<para>
Distribute Mac OS X packages in disk image ('.dmg') format to
greatly simplify installation.
- </listitem>
+ </para>
+</listitem>
<listitem>
+<para>
Provide version numbers for the shared Java libraries to
ensure that upgrades work properly, and to allow for multiple
Altus Metrum software packages to be installed in the same
directory at the same time.
- </listitem>
+ </para>
+</listitem>
</itemizedlist>
</para>
</article>
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+"/usr/share/xml/docbook/schema/dtd/4.5/docbookx.dtd">
+
+<article>
+ <para>
+ Version 1.3 is a major release. It adds support for TeleMega,
+ TeleMetrum v2.0, TeleMini v2.0 and EasyMini.
+ </para>
+ <para>
+ AltOS Firmware Changes
+ <itemizedlist>
+ <listitem>
+ <para>
+ Add STM32L processor support. This includes enhancements to
+ the scheduler to support products with many threads.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Add NXP LPC11U14 processor support.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Support additional pyro channels. These are configurable
+ through the UI to handle air starts, staging, additional
+ recovery events and external devices such as cameras.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Add 3-axis gyro support for orientation tracking. This
+ integrates the gyros to compute the angle from vertical during
+ flight, allowing the additional pyro events to be controlled
+ by this value.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Many more device drivers, including u-Blox Max 7Q GPS,
+ Freescale MMA6555 digital single-axis accelerometer,
+ Invensense MPU6000 3-axis accelerometer + 3 axis gyro,
+ Honeywell HMC5883 3-axis magnetic sensor and the TI CC1120 and
+ CC115L digital FM transceivers
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ AltosUI changes
+ <itemizedlist>
+ <listitem>
+ <para>
+ Support TeleMega, TeleMetrum v2.0, TeleMini v2.0 and EasyMini telemetry and log formats.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Use preferred units for main deployment height configuration,
+ instead of always doing configuration in meters.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ MicroPeak UI changes
+ <itemizedlist>
+ <listitem>
+ <para>
+ Add 'Download' button to menu bar.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Save the last log directory and offer that as the default for new downloads
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+</article>
<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"/usr/share/xml/docbook/schema/dtd/4.5/docbookx.dtd">
<article>
</section>
<section>
<title>Packet Formats</title>
- This section first defines the packet header common to all packets
- and then the per-packet data layout.
+ <para>
+ This section first defines the packet header common to all packets
+ and then the per-packet data layout.
+ </para>
<section>
<title>Packet Header</title>
<table frame='all'>
resulting in the following signal parmeters:
</para>
<table>
+ <title>Modulation Scheme</title>
<tgroup cols='3'>
<colspec align="center" colwidth="*" colname="parameter"/>
- <colspec align="center" text-align="." colwidth="*" colname="value"/>
+ <colspec align="center" colwidth="*" colname="value"/>
<colspec align="center" colwidth="*" colname="description"/>
<thead>
<row>
</table>
</section>
<section>
+ <title>Error Correction</title>
<para>
The cc1111 provides forward error correction in hardware,
which AltOS uses to improve reception of weak signals. The
overall effect of this is to halve the available bandwidth for
data from 38 kBaud to 19 kBaud.
</para>
- <title>Error Correction</title>
<table>
+ <title>Error Correction</title>
<tgroup cols='3'>
<colspec align="center" colwidth="*" colname="parameter"/>
<colspec align="center" colwidth="*" colname="value"/>
<tbody>
<row>
<entry>Error Correction</entry>
- <entry>Convolutional coding FEC</entry>
- <entry>1/2 code, constraint length m=4</entry>
+ <entry>Convolutional coding</entry>
+ <entry>1/2 rate, constraint length m=4</entry>
</row>
<row>
<entry>Interleaving</entry>
validate that the line was transmitted without any errors.
</para>
<table>
+ <title>Packet Format</title>
<tgroup cols='4'>
<colspec align="center" colwidth="2*" colname="offset"/>
<colspec align="center" colwidth="*" colname="name"/>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ X.Org DocBook/XML customization
+
+ DocBook XSL Stylesheets FO Parameters
+ http://docbook.sourceforge.net/release/xsl/current/doc/fo/
+-->
+
+<xsl:stylesheet
+ version='1.0'
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:fo="http://www.w3.org/1999/XSL/Format"
+ >
+<xsl:import href="file:///usr/share/xml/docbook/stylesheet/docbook-xsl/fo/docbook.xsl"/>
+
+
+ <!-- Reference Pages HTML/FO Parameters -->
+
+
+ <xsl:param name="function.parens" select="1"/>
+
+ <!-- ANSI-style function synopses are generated for a funcsynopsis element -->
+ <xsl:param name="funcsynopsis.style" select="ansi"/>
+
+ <!-- Linking HTML/FO Parameters -->
+
+ <!-- open new PDF documents in new tab, don't replace doc in current window -->
+ <xsl:attribute-set name="olink.properties">
+ <xsl:attribute name="show-destination">new</xsl:attribute>
+ </xsl:attribute-set>
+
+ <!-- Miscellaneous HTML/FO Parameters-->
+
+ <!-- SVG will be considered an acceptable image format -->
+ <xsl:param name="use.svg" select="1"/>
+
+ <!-- ToC/LoT/Index Generation -->
+ <!-- put page breaks before and after the Table of Contents,
+ so that the ToC is on a page by itself
+ Reference: http://www.sagehill.net/docbookxsl/PrintToc.html
+ -->
+ <xsl:attribute-set name="toc.margin.properties">
+ <xsl:attribute name="break-before">page</xsl:attribute>
+ <xsl:attribute name="break-after">page</xsl:attribute>
+ </xsl:attribute-set>
+
+ <!-- Pagination and General Styles FO Parameters -->
+ <!--
+ Speed up ps & pdf creation by not creating pages with "draft" image,
+ thus not needing to wait for http fetch of draft.png from docbook website.
+ -->
+ <xsl:param name="draft.mode" select="no"/>
+
+ <!-- Processor Extensions FO Parameters-->
+
+ <!-- PDF bookmarks extensions for FOP version 0.90 and later will be used. -->
+ <xsl:param name="fop.extensions" select="0"></xsl:param>
+ <xsl:param name="fop1.extensions" select="1"></xsl:param>
+
+ <!-- Cross Refrences FO Parameters-->
+
+ <!-- Make links in pdf output blue so it's easier to tell they're internal
+ links
+ -->
+ <xsl:attribute-set name="xref.properties">
+ <xsl:attribute name="color">blue</xsl:attribute>
+ </xsl:attribute-set>
+
+ <!-- Make links in pdf output green so it's easier to tell they're external
+ links
+ -->
+ <xsl:attribute-set name="olink.properties">
+ <xsl:attribute name="color">green</xsl:attribute>
+ </xsl:attribute-set>
+
+ <!-- Linking to a target inside a pdf document.
+ This feature is only available as of docbook-xsl-1.76.1.
+ When set to zero, the link will point to the document -->
+ <xsl:param name="insert.olink.pdf.frag" select="0"></xsl:param>
+
+
+ <!-- Font Families FO Parameters -->
+
+ <!--
+ Since a number of documents, especially the credits section in the
+ ReleaseNotes, use characters not found in the fop default base-14
+ PostScript fonts, set the fonts for the fop generated documents to
+ use the free DejaVu and GNU Unifont fonts which cover a much wider
+ range of characters.
+
+ DejaVu is available from http://dejavu-fonts.org/
+ GNU Unifont is available from http://unifoundry.com/unifont.html
+
+ To set fop font paths to find them after installing, see
+ http://xmlgraphics.apache.org/fop/1.0/fonts.html#basics
+ -->
+ <xsl:param name="body.font.family">DejaVu Serif</xsl:param>
+ <xsl:param name="symbol.font.family">serif,Symbol,AR PL UMing CN,AR PL ShanHeiSun Uni,GNU Unifont</xsl:param>
+
+ <!-- Paragraph template bits -->
+
+ <!-- make it possible to turn off hyphenation when it's giving us probs -->
+ <xsl:template match="para[@hyphenate='false']">
+ <fo:block hyphenate="false" xsl:use-attribute-sets="normal.para.spacing">
+ <xsl:call-template name="anchor"/>
+ <xsl:apply-templates/>
+ </fo:block>
+ </xsl:template>
+
+ <!-- force line break -->
+ <xsl:template match="processing-instruction('linebreak')">
+ <fo:block/>
+ </xsl:template>
+
+ <xsl:attribute-set name="informalfigure.properties">
+ <xsl:attribute name="text-align">center</xsl:attribute>
+ </xsl:attribute-set>
+
+</xsl:stylesheet>
*.la
*.java
*.class
+*.dll
.libs/
classlibaltos.stamp
libaltos_wrap.c
JAVAC=javac
AM_CFLAGS=-DLINUX -DPOSIX_TTY -I$(JVM_INCLUDE)
-AM_JAVACFLAGS=-encoding UTF-8
+AM_JAVACFLAGS=-target 1.6 -encoding UTF-8 -Xlint:deprecation -source 6
altoslibdir=$(libdir)/altos
altos_putchar(file, c);
}
-main ()
+int
+main (int argc, char **argv)
{
struct altos_device device;
struct altos_list *list;
#ifdef DARWIN
+#include <unistd.h>
+
#undef USE_POLL
/* Mac OS X don't have strndup even if _GNU_SOURCE is defined */
if (!get_number (object, CFSTR(kUSBVendorID), &device->vendor) ||
!get_number (object, CFSTR(kUSBProductID), &device->product))
continue;
- if (list->ftdi) {
- if (device->vendor != 0x0403)
- continue;
- } else {
- if (device->vendor != 0xfffe)
- continue;
- if (device->product < 0x000a || 0x0013 < device->product)
- continue;
- }
if (get_string (object, CFSTR("IOCalloutDevice"), device->path, sizeof (device->path)) &&
get_string (object, CFSTR("USB Product Name"), device->name, sizeof (device->name)) &&
get_string (object, CFSTR("USB Serial Number"), serial_string, sizeof (serial_string))) {
JAVAROOT=classes
-AM_JAVACFLAGS=-encoding UTF-8 -Xlint:deprecation
+AM_JAVACFLAGS=-target 1.6 -encoding UTF-8 -Xlint:deprecation -source 6
+
+man_MANS=micropeak.1
altoslibdir=$(libdir)/altos
import java.lang.*;
import java.io.*;
import java.util.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
import org.altusmetrum.altosuilib_1.*;
class MicroIterator implements Iterator<MicroDataPoint> {
import java.io.*;
import java.util.concurrent.*;
import java.util.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
import org.altusmetrum.altosuilib_1.*;
public class MicroDownload extends AltosUIDialog implements Runnable, ActionListener {
import java.awt.*;
import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
import org.altusmetrum.altosuilib_1.*;
public class MicroExport extends JFileChooser {
import java.io.*;
import java.util.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
import org.altusmetrum.altosuilib_1.*;
public class MicroFile {
import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter;
import java.io.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
import org.altusmetrum.altosuilib_1.*;
public class MicroFileChooser extends JFileChooser {
import java.awt.*;
import javax.swing.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
import org.altusmetrum.altosuilib_1.*;
import org.jfree.ui.*;
import java.io.*;
import java.util.concurrent.*;
import java.util.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
import org.altusmetrum.altosuilib_1.*;
public class MicroPeak extends MicroFrame implements ActionListener, ItemListener {
fileMenu.add(exitAction);
exitAction.addActionListener(this);
+ JButton downloadButton = new JButton ("Download");
+ downloadButton.addActionListener(this);
+ menuBar.add(downloadButton);
+
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
addWindowListener(new WindowAdapter() {
@Override
import java.awt.*;
import java.io.*;
import javax.swing.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
import org.altusmetrum.altosuilib_1.*;
public class MicroRaw extends JTextArea {
import java.io.*;
import java.util.concurrent.*;
import java.util.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
import org.altusmetrum.altosuilib_1.*;
public class MicroSave extends JFileChooser {
package org.altusmetrum.micropeak;
import java.io.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
import org.altusmetrum.altosuilib_1.*;
public class MicroStats {
import java.awt.*;
import javax.swing.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
import org.altusmetrum.altosuilib_1.*;
public class MicroStatsTable extends JComponent implements AltosFontListener {
--- /dev/null
+.\"
+.\" Copyright © 2013 Keith Packard <keithp@keithp.com>
+.\"
+.\" This program is free software; you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation; either version 2 of the License, or
+.\" (at your option) any later version.
+.\"
+.\" This program is distributed in the hope that it will be useful, but
+.\" WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+.\" General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License along
+.\" with this program; if not, write to the Free Software Foundation, Inc.,
+.\" 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+.\"
+.\"
+.TH MICROPEAK 1 "micropeak" ""
+.SH NAME
+micropeak \- MicroPeak logging altimeter download and analysis
+.SH SYNOPSIS
+.B "micropeak"
+.SH DESCRIPTION
+.I micropeak
+connects to a MicroPeak USB adapter for MicroPeak data download.
+It provides a menu-oriented
+user interface to download and analyze data logged on a MicroPeak
+altimeter.
+.SH USAGE
+When connected to a MicroPeak USB adapter,
+.I micropeak
+can download data from a MicroPeak device, save it to a file and graph
+data from saved files.
+.P
+A number of other menu options exist, including the ability to export flight
+data in different formats.
+.SH FILES
+All data log files are recorded into a user-specified directory
+(default ~/AltusMetrum). Files are named using the current date and a
+unique flight number with a '.mpd' extension.
+.SH AUTHOR
+Keith Packard
--- /dev/null
+Subproject commit 8b1c9061fa3a8f1b30ee13b373afe5cc1ad9d382
+Makedefs
altitude.h
altitude-pa.h
ao_whiten.h
--- /dev/null
+ARM_CC=@ARM_CC@
+HAVE_ARM_M3_CC=@HAVE_ARM_M3_CC@
+HAVE_ARM_M0_CC=@HAVE_ARM_M0_CC@
+PDCLIB_INCLUDES=@PDCLIB_INCLUDES@
+PDCLIB_LIBS_M0=@PDCLIB_LIBS_M0@
+PDCLIB_LIBS_M3=@PDCLIB_LIBS_M3@
+PDCLIB_ROOT=@PDCLIB_ROOT@
+HAVE_PDCLIB=@HAVE_PDCLIB@
+
+SDCC=@SDCC@
+HAVE_SDCC=@HAVE_SDCC@
+
+AVR_CC=@AVR_CC@
+AVR_OBJCOPY=@AVR_OBJCOPY@
+HAVE_AVR_CC=@HAVE_AVR_CC@
vpath matrix.5c kalman
include Version
+TOPDIR=.
+include Makedefs
SDCCDIRS=\
telemetrum-v1.2 telemetrum-v1.1 telemetrum-v1.0 \
- teledongle-v0.2 teledongle-v0.1 \
- telemini-v1.0 telenano-v0.1 \
+ teledongle-v0.2 \
+ telemini-v1.0 \
telebt-v1.0 \
- telemetrum-v0.1-sky telemetrum-v0.1-sirf \
- telelaunch-v0.1 tidongle test \
teleterra-v0.2 teleshield-v0.1 \
- telefire-v0.1 \
- spiradio-v0.1
+ telefire-v0.1 telefire-v0.2 \
+ telemini-v2.0
-AVRDIRS=\
- telescience-v0.1 telescience-pwm telepyro-v0.1 micropeak
-
-ARMDIRS=\
+ARMM3DIRS=\
telemega-v0.1 telemega-v0.1/flash-loader \
- telemega-v0.3 telemega-v0.3/flash-loader \
+ telemega-v1.0 telemega-v1.0/flash-loader \
+ telemetrum-v2.0 telemetrum-v2.0/flash-loader \
megadongle-v0.1 megadongle-v0.1/flash-loader \
- telegps-v0.1 telegps-v0.1/flash-loader \
- stm-bringup stm-demo \
+ telegps-v0.3 telegps-v0.3/flash-loader \
telelco-v0.2 telelco-v0.2/flash-loader \
- telescience-v0.2
+ telescience-v0.2 telescience-v0.2/flash-loader
+
+ARMM0DIRS=\
+ easymini-v1.0 easymini-v1.0/flash-loader
+
+AVRDIRS=\
+ telescience-v0.1 telescience-pwm micropeak nanopeak-v0.1
+
+SUBDIRS=
-ifneq ($(shell which sdcc),)
- SUBDIRS += $(SDCCDIRS)
+ifeq ($(strip $(HAVE_PDCLIB)),yes)
+PDCLIB=pdclib
+CLEAN_PDCLIB=clean-pdclib
endif
-ifneq ($(shell which avr-gcc),)
- SUBDIRS += $(AVRDIRS)
+ifeq ($(strip $(HAVE_SDCC)),yes)
+SUBDIRS+=$(SDCCDIRS)
endif
-ifneq ($(shell which arm-none-eabi-gcc),)
- SUBDIRS += $(ARMDIRS)
+ifeq ($(strip $(HAVE_ARM_M3_CC)),yes)
+SUBDIRS+=$(ARMM3DIRS)
+foo=bar
endif
-ALLDIRS=$(SDCCDIRS) $(AVRDIRS) $(ARMDIRS)
+ifeq ($(strip $(HAVE_ARM_M0_CC)),yes)
+SUBDIRS+=$(ARMM0DIRS)
+baz=bletch
+endif
+
+ifeq ($(strip $(HAVE_AVR_CC)),yes)
+SUBDIRS += $(AVRDIRS)
+endif
+
+ALLDIRS=$(SDCCDIRS) $(ARMM3DIRS) $(ARMM0DIRS) $(AVRDIRS)
all: all-local all-recursive
all-recursive: all-local
-all-local: altitude.h altitude-pa.h ao_kalman.h ao_whiten.h
+all-local: altitude.h altitude-pa.h ao_kalman.h ao_whiten.h $(PDCLIB)
altitude.h: make-altitude
nickle $< > $@
ao_whiten.h: make-whiten
nickle $< > $@
-clean-local:
+clean-local: $(CLEAN_PDCLIB)
rm -f altitude.h ao_kalman.h
+
+pdclib:
+ mkdir -p $(PDCLIB_ROOT)/include $(PDCLIB_ROOT)/lib
+ cd ../pdclib && make && make prefix=`pwd`/../pdclib-root install
+
+clean-pdclib:
+ rm -rf $(PDCLIB_ROOT)
+ cd ../pdclib && make clean
xKeyAddition(block, block2, rp, BC);
}
+#if NOTUSED
+/* We don't actually need this in AltOS, so don't bother including it */
+
+/* Decryption of one block. */
static
void xrijndaelDecrypt(word32 block[], roundkey *rkk)
{
xKeyAddition(block, block, rp, BC);
}
+#endif
uint8_t ao_aes_mutex;
static uint8_t key[16];
*/
#define ao_spi_get_mask(reg,mask,bus,speed) do { \
- (reg) &= ~(mask); \
+ (reg) &= ~(mask); \
} while (0)
#define ao_spi_put_mask(reg,mask,bus) do { \
(reg) |= (mask); \
} while (0)
-#define ao_spi_get_bit(reg,bit,pin,bus,speed) do { \
- (pin) = 0; \
- } while (0)
-
-#define ao_spi_put_bit(reg,bit,pin,bus) do { \
- (pin) = 1; \
- } while (0)
+#define ao_spi_get_bit(reg,bit,pin,bus,speed) ao_spi_get_mask(reg,(1<<(bit)),bus,speed)
+#define ao_spi_put_bit(reg,bit,pin,bus) ao_spi_put_mask(reg,(1<<(bit)),bus)
#define ao_gpio_token_paster(x,y) x ## y
#define ao_gpio_token_evaluator(x,y) ao_gpio_token_paster(x,y)
PORTB &= ~(1 << bit); \
} while (0)
+#define ao_gpio_get(port, bit, pin) ((PORTB >> (bit)) & 1)
+
/*
* The SPI mutex must be held to call either of these
* functions -- this mutex covers the entire SPI operation,
--- /dev/null
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+#include <ao_async.h>
+
+#define AO_ASYNC_BAUD 38400l
+#define AO_ASYNC_DELAY (uint8_t) (1000000l / AO_ASYNC_BAUD)
+
+#define LED_PORT PORTB
+
+void
+ao_async_start(void)
+{
+ LED_PORT |= (1 << AO_LED_SERIAL);
+}
+
+void
+ao_async_stop(void)
+{
+ LED_PORT &= ~(1 << AO_LED_SERIAL);
+}
+
+void
+ao_async_byte(uint8_t byte)
+{
+ uint8_t b;
+ uint16_t w;
+
+ /* start data stop */
+ w = (0x000 << 0) | (byte << 1) | (0x001 << 9);
+
+ ao_arch_block_interrupts();
+ for (b = 0; b < 10; b++) {
+ uint8_t v = LED_PORT & ~(1 << AO_LED_SERIAL);
+ v |= (w & 1) << AO_LED_SERIAL;
+ LED_PORT = v;
+ w >>= 1;
+
+ /* Carefully timed to hit around 9600 baud */
+ asm volatile ("nop");
+ asm volatile ("nop");
+
+ asm volatile ("nop");
+ asm volatile ("nop");
+ asm volatile ("nop");
+ asm volatile ("nop");
+ asm volatile ("nop");
+
+ asm volatile ("nop");
+ asm volatile ("nop");
+ asm volatile ("nop");
+ asm volatile ("nop");
+ asm volatile ("nop");
+ }
+ ao_arch_release_interrupts();
+}
--- /dev/null
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_ASYNC_H_
+#define _AO_ASYNC_H_
+
+void
+ao_async_start(void);
+
+void
+ao_async_stop(void);
+
+void
+ao_async_byte(uint8_t byte);
+
+#endif /* _AO_ASYNC_H_ */
#define ao_exti_init()
#define AO_EXTI_MODE_RISING 1
+#define AO_EXTI_PIN_NOCONFIGURE 0
#endif /* _AO_EXTI_H_ */
vpath matrix.5c ../kalman
vpath ao-make-product.5c ../util
+include ../avr/Makefile.defs
+
MCU=atmega32u4
DUDECPUTYPE=m32u4
#PROGRAMMER=stk500v2 -P usb
-PROGRAMMER=usbtiny
-LOADCMD=avrdude
LOADARG=-p $(DUDECPUTYPE) -c $(PROGRAMMER) -e -U flash:w:
-CC=avr-gcc
-OBJCOPY=avr-objcopy
-
-ifndef VERSION
-include ../Version
-endif
INC = \
ao.h \
--- /dev/null
+ifndef TOPDIR
+TOPDIR=..
+endif
+
+ifndef VERSION
+include $(TOPDIR)/Version
+endif
+
+include $(TOPDIR)/Makedefs
+
+CC=$(AVR_CC)
+OBJCOPY=$(AVR_OBJCOPY)
+LDSCRIPTS=/usr/lib/avr/lib/ldscripts
+
+PROGRAMMER=usbtiny
+LOADCMD=avrdude
-CC=sdcc
+include ../Makedefs
+CC=$(SDCC)
CFLAGS=--model-small --debug --opt-code-speed -DCODESIZE=$(CODESIZE)
volatile __xdata struct ao_data ao_data_ring[AO_DATA_RING];
volatile __data uint8_t ao_data_head;
+#if (AO_DATA_ALL & ~(AO_DATA_ADC))
+volatile __data uint8_t ao_data_present;
+#endif
+
+#ifdef TELENANO_V_0_1
+# define AO_ADC_FIRST_PIN 1
+#endif
+
+#if HAS_ACCEL_REF
+# define AO_ADC_FIRST_PIN 2
+#endif
#ifndef AO_ADC_FIRST_PIN
-#define AO_ADC_FIRST_PIN 0
+# define AO_ADC_FIRST_PIN 0
#endif
void
ao_adc_poll(void)
{
-#if HAS_ACCEL_REF
- ADCCON3 = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 2;
-#else
-# ifdef TELENANO_V_0_1
- ADCCON3 = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 1;
-# else
ADCCON3 = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | AO_ADC_FIRST_PIN;
-# endif
-#endif
}
void
else
#endif
ADCCON3 = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | sequence;
+ return;
}
#endif
if (sequence) {
/* Start next conversion */
ADCCON3 = sequence;
+ return;
}
#endif /* telemini || telenano */
-#ifdef TELEFIRE_V_0_1
+#if defined(TELEFIRE_V_0_1) || defined(TELEFIRE_V_0_2)
a = (uint8_t __xdata *) (&ao_data_ring[ao_data_head].adc.sense[0] + sequence - AO_ADC_FIRST_PIN);
a[0] = ADCL;
a[1] = ADCH;
- if (sequence < 5)
+ if (sequence < 5) {
ADCCON3 = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | (sequence + 1);
+ return;
+ }
#define GOT_ADC
#endif /* TELEFIRE_V_0_1 */
a = (uint8_t __xdata *) (&ao_data_ring[ao_data_head].adc.batt);
a[0] = ADCL;
a[1] = ADCH;
- if (0)
- ;
#define GOT_ADC
#endif
+#ifdef FETCH_ADC
+ FETCH_ADC();
+#define GOT_ADC
+#endif
+
#ifndef GOT_ADC
#error No known ADC configuration set
#endif
- else {
- /* record this conversion series */
- ao_data_ring[ao_data_head].tick = ao_time();
- ao_data_head = ao_data_ring_next(ao_data_head);
- ao_wakeup(DATA_TO_XDATA(&ao_data_head));
- }
+ /* record this conversion series */
+ ao_data_ring[ao_data_head].tick = ao_time();
+ ao_data_head = ao_data_ring_next(ao_data_head);
+ ao_wakeup(DATA_TO_XDATA(&ao_data_head));
}
static void
ao_serial1_tx_isr(void) ao_arch_interrupt(14);
#endif
+#if HAS_EXTI_0
+void
+ao_p0_isr(void) __interrupt(13);
+#endif
+
#endif /* _AO_ARCH_H_ */
* ao_spi.c
*/
-extern __xdata uint8_t ao_spi_mutex;
+#if !HAS_SPI_0 && !HAS_SPI_1
+#define HAS_SPI_0 1
+#define SPI_0_ALT_2 1
+#endif
+
+#if HAS_SPI_0 && HAS_SPI_1
+#define MULTI_SPI 1
+#define N_SPI 2
+#else
+#define MULTI_SPI 0
+#define N_SPI 1
+#endif
+
+extern __xdata uint8_t ao_spi_mutex[N_SPI];
+
+#if MULTI_SPI
+#define ao_spi_get(bus) ao_mutex_get(&ao_spi_mutex[bus])
+#define ao_spi_put(bus) ao_mutex_put(&ao_spi_mutex[bus])
+#else
+#define ao_spi_get(bus) ao_mutex_get(&ao_spi_mutex[0])
+#define ao_spi_put(bus) ao_mutex_put(&ao_spi_mutex[0])
+#endif
#define AO_SPI_SPEED_FAST 17
#define AO_SPI_SPEED_200kHz 13
-#define ao_spi_set_speed(speed) (U0GCR = (UxGCR_CPOL_NEGATIVE | \
- UxGCR_CPHA_FIRST_EDGE | \
- UxGCR_ORDER_MSB | \
- ((speed) << UxGCR_BAUD_E_SHIFT)))
+#if MULTI_SPI
+#define ao_spi_set_speed(bus,speed) (*(bus ? &U1GCR : &U0GCR) =(UxGCR_CPOL_NEGATIVE | \
+ UxGCR_CPHA_FIRST_EDGE | \
+ UxGCR_ORDER_MSB | \
+ ((speed) << UxGCR_BAUD_E_SHIFT)))
+#else
+#define ao_spi_set_speed(bus,speed) (U0GCR = (UxGCR_CPOL_NEGATIVE | \
+ UxGCR_CPHA_FIRST_EDGE | \
+ UxGCR_ORDER_MSB | \
+ ((speed) << UxGCR_BAUD_E_SHIFT)))
+#endif
#define ao_spi_get_slave(bus) do { \
- ao_mutex_get(&ao_spi_mutex); \
- ao_spi_set_speed(AO_SPI_SPEED_FAST); \
+ ao_spi_get(bus); \
+ ao_spi_set_speed(bus,AO_SPI_SPEED_FAST); \
} while (0)
#define ao_spi_put_slave(bus) do { \
- ao_mutex_put(&ao_spi_mutex); \
+ ao_spi_put(bus); \
} while (0)
#define ao_spi_get_mask(reg,mask,bus,speed) do { \
- ao_mutex_get(&ao_spi_mutex); \
- ao_spi_set_speed(speed); \
+ ao_spi_get(bus); \
+ ao_spi_set_speed(bus,speed); \
(reg) &= ~(mask); \
} while (0)
#define ao_spi_put_mask(reg,mask,bus) do { \
(reg) |= (mask); \
- ao_mutex_put(&ao_spi_mutex); \
+ ao_spi_put(bus); \
} while (0)
#define ao_spi_get_bit(reg,bit,pin,bus,speed) do { \
- ao_mutex_get(&ao_spi_mutex); \
- ao_spi_set_speed(speed); \
- pin = 0; \
+ ao_spi_get(bus); \
+ ao_spi_set_speed(bus,speed); \
+ pin = 0; \
} while (0)
#define ao_spi_put_bit(reg,bit,pin,bus) do { \
pin = 1; \
- ao_mutex_put(&ao_spi_mutex); \
+ ao_spi_put(bus); \
} while (0)
* from chip select low to chip select high
*/
+#if MULTI_SPI
+void
+ao_spi_send(void __xdata *block, uint16_t len, uint8_t bus) __reentrant;
+
+void
+ao_spi_recv(void __xdata *block, uint16_t len, uint8_t bus) __reentrant;
+#else
void
ao_spi_send_bus(void __xdata *block, uint16_t len) __reentrant;
#define ao_spi_send(block, len, bus) ao_spi_send_bus(block, len)
#define ao_spi_recv(block, len, bus) ao_spi_recv_bus(block, len)
+#endif
#if AO_SPI_SLAVE
void
void
ao_spi_init(void);
-#define ao_spi_init_cs(port, mask) do { \
- SPI_CS_PORT |= mask; \
- SPI_CS_DIR |= mask; \
- SPI_CS_SEL &= ~mask; \
+#define token_paster(x,y) x ## y
+#define token_paster3(x,y,z) x ## y ## z
+#define token_evaluator(x,y) token_paster(x,y)
+#define token_evaluator3(x,y,z) token_paster3(x,y,z)
+
+#define ao_spi_init_cs(port, mask) do { \
+ port |= mask; \
+ token_evaluator(port,DIR) |= mask; \
+ token_evaluator(port,SEL) &= ~mask; \
} while (0)
#define cc1111_enable_output(port,dir,sel,pin,bit,v) do { \
#define disable_unreachable _Pragma("disable_warning 126")
-#define token_paster(x,y) x ## y
-#define token_evaluator(x,y) token_paster(x,y)
#define ao_enable_output(port,bit,pin,v) cc1111_enable_output(port,token_evaluator(port,DIR), token_evaluator(port,SEL), pin, bit, v)
#define ao_gpio_set(port, bit, pin, v) ((pin) = (v))
+#define ao_gpio_get(port, bit, pin) (pin)
+
--- /dev/null
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+#include <ao_exti.h>
+
+#if HAS_EXTI_0
+__xdata void (*ao_int_callback)(void);
+
+void
+ao_p0_isr(void) __interrupt(13)
+{
+ if (P0IF && (P0IFG & (AO_MS5607_MISO_MASK))) {
+ (*ao_int_callback)();
+ }
+ P0IFG = 0;
+ P0IF = 0;
+}
+#endif
--- /dev/null
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_EXTI_H_
+#define _AO_EXTI_H_
+
+#define AO_EXTI_MODE_RISING 1
+#define AO_EXTI_MODE_FALLING 2
+#define AO_EXTI_MODE_PULL_UP 4
+#define AO_EXTI_MODE_PULL_DOWN 8
+#define AO_EXTI_PRIORITY_LOW 16
+#define AO_EXTI_PRIORITY_MED 0
+#define AO_EXTI_PRIORITY_HIGH 32
+
+extern void (*ao_int_callback)(void);
+
+#define ao_exti_setup(gpio, pin, mode, callback) do { \
+ ao_int_callback = callback; \
+ } while (0)
+
+#define ao_exti_set_mode(gpio, pin, mode) do { \
+ } while (0)
+
+#define ao_exti_set_callback(port, pin, callback) do { \
+ ao_int_callback = callback; \
+ } while (0)
+
+#define ao_exti_init()
+
+#define ao_exti_enable(port, pin) do { \
+ P0IFG &= ~(1 << pin); \
+ P0IF = 0; \
+ PICTL |= PICTL_P0IENL; \
+ IEN1 |= IEN1_P0IE; \
+ } while (0)
+
+#define ao_exti_disable(port, pin) do { \
+ IEN1 &= ~IEN1_P0IE; \
+ PICTL &= ~PICTL_P0IENL; \
+ } while (0)
+
+#endif /* _AO_EXTI_H_ */
}
#if NEED_RADIO_RSSI
else
- ao_radio_rssi = AO_RSSI_FROM_RADIO(((uint8_t *)packet)[size - 1]);
+ ao_radio_rssi = AO_RSSI_FROM_RADIO(((uint8_t *)packet)[size - 2]);
#endif
ao_radio_put();
return ao_radio_dma_done;
#include "ao.h"
/* Default pin usage for existing Altus Metrum devices */
-#if !HAS_SPI_0 && !HAS_SPI_1
-#define HAS_SPI_0 1
-#define SPI_0_ALT_2 1
-#endif
#ifndef SPI_CONST
#define SPI_CONST 0xff
*/
#if HAS_SPI_0
-#define SPI_CSR U0CSR
-#define SPI_BUF U0DBUFXADDR
-#define SPI_BAUD U0BAUD
-#define SPI_GCR U0GCR
-#define SPI_CFG_MASK PERCFG_U0CFG_ALT_MASK
-#define SPI_DMA_TX DMA_CFG0_TRIGGER_UTX0
-#define SPI_DMA_RX DMA_CFG0_TRIGGER_URX0
+#define SPI_BUF_0 &U0DBUFXADDR
+#define SPI_CSR_0 U0CSR
+#define SPI_BAUD_0 U0BAUD
+#define SPI_GCR_0 U0GCR
+#define SPI_CFG_MASK_0 PERCFG_U0CFG_ALT_MASK
+#define SPI_DMA_TX_0 DMA_CFG0_TRIGGER_UTX0
+#define SPI_DMA_RX_0 DMA_CFG0_TRIGGER_URX0
#if SPI_0_ALT_1
-#define SPI_CFG PERCFG_U0CFG_ALT_1
-#define SPI_SEL P0SEL
-#define SPI_BITS (1 << 3) | (1 << 2) | (1 << 5)
-#define SPI_CSS_BIT (1 << 4)
+#define SPI_CFG_0 PERCFG_U0CFG_ALT_1
+#define SPI_SEL_0 P0SEL
+#define SPI_BITS_0 (1 << 3) | (1 << 2) | (1 << 5)
+#define SPI_CSS_BIT_0 (1 << 4)
#endif
#if SPI_0_ALT_2
-#define SPI_CFG PERCFG_U0CFG_ALT_2
-#define SPI_SEL P1SEL
-#define SPI_PRI P2SEL_PRI3P1_USART0
-#define SPI_BITS (1 << 5) | (1 << 4) | (1 << 3)
-#define SPI_CSS_BIT (1 << 2)
+#define SPI_CFG_0 PERCFG_U0CFG_ALT_2
+#define SPI_SEL_0 P1SEL
+#define SPI_PRI_0 P2SEL_PRI3P1_USART0
+#define SPI_BITS_0 (1 << 5) | (1 << 4) | (1 << 3)
+#define SPI_CSS_BIT_0 (1 << 2)
#endif
#endif
#if HAS_SPI_1
-#define SPI_CSR U1CSR
-#define SPI_BUF U1DBUFXADDR
-#define SPI_BAUD U1BAUD
-#define SPI_GCR U1GCR
-#define SPI_CFG_MASK PERCFG_U1CFG_ALT_MASK
-#define SPI_DMA_TX DMA_CFG0_TRIGGER_UTX1
-#define SPI_DMA_RX DMA_CFG0_TRIGGER_URX1
+#define SPI_BUF_1 &U1DBUFXADDR
+#define SPI_CSR_1 U1CSR
+#define SPI_BAUD_1 U1BAUD
+#define SPI_GCR_1 U1GCR
+#define SPI_CFG_MASK_1 PERCFG_U1CFG_ALT_MASK
+#define SPI_DMA_TX_1 DMA_CFG0_TRIGGER_UTX1
+#define SPI_DMA_RX_1 DMA_CFG0_TRIGGER_URX1
#if SPI_1_ALT_1
-#define SPI_CFG PERCFG_U1CFG_ALT_1
-#define SPI_SEL P0SEL
-#define SPI_BITS (1 << 4) | (1 << 5) | (1 << 3)
-#define SPI_CSS_BIT (1 << 2)
+#define SPI_CFG_1 PERCFG_U1CFG_ALT_1
+#define SPI_SEL_1 P0SEL
+#define SPI_BITS_1 (1 << 4) | (1 << 5) | (1 << 3)
+#define SPI_CSS_BIT_1 (1 << 2)
#endif
#if SPI_1_ALT_2
-#define SPI_CFG PERCFG_U1CFG_ALT_2
-#define SPI_SEL P1SEL
-#define SPI_PRI P2SEL_PRI3P1_USART1
-#define SPI_BITS (1 << 6) | (1 << 7) | (1 << 5)
-#define SPI_CSS_BIT (1 << 4)
+#define SPI_CFG_1 PERCFG_U1CFG_ALT_2
+#define SPI_SEL_1 P1SEL
+#define SPI_PRI_1 P2SEL_PRI3P1_USART1
+#define SPI_BITS_1 (1 << 6) | (1 << 7) | (1 << 5)
+#define SPI_CSS_BIT_1 (1 << 4)
#endif
#endif
+#if MULTI_SPI
+
+#define SPI_BUF(bus) ((bus) ? SPI_BUF_1 : SPI_BUF_0)
+#define SPI_CSR(bus) ((bus) ? SPI_CSR_1 : SPI_CSR_0)
+#define SPI_BAUD(bus) ((bus) ? SPI_BAUD_1 : SPI_BAUD_0)
+#define SPI_GCR(bus) ((bus) ? SPI_GCR_1 : SPI_GCR_0)
+#define SPI_CFG_MASK(bus) ((bus) ? SPI_CFG_MASK_1 : SPI_CFG_MASK_0)
+#define SPI_DMA_TX(bus) ((bus) ? SPI_DMA_TX_1 : SPI_DMA_TX_0)
+#define SPI_DMA_RX(bus) ((bus) ? SPI_DMA_RX_1 : SPI_DMA_RX_0)
+#define SPI_CFG(bus) ((bus) ? SPI_CFG_1 : SPI_CFG_0)
+#define SPI_SEL(bus) ((bus) ? SPI_SEL_1 : SPI_SEL_0)
+#define SPI_BITS(bus) ((bus) ? SPI_BITS_1 : SPI_BITS_0)
+#define SPI_CSS_BIT(bus) ((bus) ? SPI_CSS_BIT_1 : SPI_CSS_BIT_0)
+
+#else
+
+#if HAS_SPI_0
+#define SPI_BUF(bus) SPI_BUF_0
+#define SPI_CSR(bus) SPI_CSR_0
+#define SPI_BAUD(bus) SPI_BAUD_0
+#define SPI_GCR(bus) SPI_GCR_0
+#define SPI_CFG_MASK(bus) SPI_CFG_MASK_0
+#define SPI_DMA_TX(bus) SPI_DMA_TX_0
+#define SPI_DMA_RX(bus) SPI_DMA_RX_0
+#define SPI_CFG(bus) SPI_CFG_0
+#define SPI_SEL(bus) SPI_SEL_0
+#define SPI_BITS(bus) SPI_BITS_0
+#define SPI_CSS_BIT(bus) SPI_CSS_BIT_0
+#endif
+#if HAS_SPI_1
+#define SPI_BUF(bus) SPI_BUF_1
+#define SPI_CSR(bus) SPI_CSR_1
+#define SPI_BAUD(bus) SPI_BAUD_1
+#define SPI_GCR(bus) SPI_GCR_1
+#define SPI_CFG_MASK(bus) SPI_CFG_MASK_1
+#define SPI_DMA_TX(bus) SPI_DMA_TX_1
+#define SPI_DMA_RX(bus) SPI_DMA_RX_1
+#define SPI_CFG(bus) SPI_CFG_1
+#define SPI_SEL(bus) SPI_SEL_1
+#define SPI_BITS(bus) SPI_BITS_1
+#define SPI_CSS_BIT(bus) SPI_CSS_BIT_1
+#endif
+
+#endif /* MULTI_SPI */
+
#if AO_SPI_SLAVE
-#define CSS SPI_CSS_BIT
+#define CSS(bus) SPI_CSS_BIT(bus)
#define UxCSR_DIRECTION UxCSR_SLAVE
#else
-#define CSS 0
+#define CSS(bus) 0
#define UxCSR_DIRECTION UxCSR_MASTER
#endif
* operation, from CS low to CS high. This means that any SPI
* user must protect the SPI bus with this mutex
*/
-__xdata uint8_t ao_spi_mutex;
-__xdata uint8_t ao_spi_dma_in_done;
-__xdata uint8_t ao_spi_dma_out_done;
+__xdata uint8_t ao_spi_mutex[N_SPI];
+__xdata uint8_t ao_spi_dma_in_done[N_SPI];
+__xdata uint8_t ao_spi_dma_out_done[N_SPI];
-uint8_t ao_spi_dma_out_id;
-uint8_t ao_spi_dma_in_id;
+uint8_t ao_spi_dma_out_id[N_SPI];
+uint8_t ao_spi_dma_in_id[N_SPI];
static __xdata uint8_t ao_spi_const;
+
/* Send bytes over SPI.
*
* This sets up two DMA engines, one writing the data and another reading
* is complete, as the transmit register is double buffered and hence signals
* completion one byte before the transfer is actually complete
*/
+#if MULTI_SPI
+void
+ao_spi_send(void __xdata *block, uint16_t len, uint8_t bus) __reentrant
+#else
void
ao_spi_send_bus(void __xdata *block, uint16_t len) __reentrant
+#define bus 0
+#endif
{
- ao_dma_set_transfer(ao_spi_dma_in_id,
- &SPI_BUF,
+ ao_dma_set_transfer(ao_spi_dma_in_id[bus],
+ SPI_BUF(bus),
&ao_spi_const,
len,
DMA_CFG0_WORDSIZE_8 |
DMA_CFG0_TMODE_SINGLE |
- SPI_DMA_RX,
+ SPI_DMA_RX(bus),
DMA_CFG1_SRCINC_0 |
DMA_CFG1_DESTINC_0 |
DMA_CFG1_PRIORITY_NORMAL);
- ao_dma_set_transfer(ao_spi_dma_out_id,
+ ao_dma_set_transfer(ao_spi_dma_out_id[bus],
block,
- &SPI_BUF,
+ SPI_BUF(bus),
len,
DMA_CFG0_WORDSIZE_8 |
DMA_CFG0_TMODE_SINGLE |
- SPI_DMA_TX,
+ SPI_DMA_TX(bus),
DMA_CFG1_SRCINC_1 |
DMA_CFG1_DESTINC_0 |
DMA_CFG1_PRIORITY_NORMAL);
- ao_dma_start(ao_spi_dma_in_id);
- ao_dma_start(ao_spi_dma_out_id);
- ao_dma_trigger(ao_spi_dma_out_id);
+ ao_dma_start(ao_spi_dma_in_id[bus]);
+ ao_dma_start(ao_spi_dma_out_id[bus]);
+ ao_dma_trigger(ao_spi_dma_out_id[bus]);
#if !AO_SPI_SLAVE
- __critical while (!ao_spi_dma_in_done)
- ao_sleep(&ao_spi_dma_in_done);
+ __critical while (!ao_spi_dma_in_done[bus])
+ ao_sleep(&ao_spi_dma_in_done[bus]);
#endif
+#undef bus
}
#if AO_SPI_SLAVE
void
ao_spi_send_wait(void)
{
- __critical while (!ao_spi_dma_in_done)
- ao_sleep(&ao_spi_dma_in_done);
+ __critical while (!ao_spi_dma_in_done[0])
+ ao_sleep(&ao_spi_dma_in_done[0]);
}
#endif
* writing constant values to the SPI transmitter as that is what
* clocks the data coming in.
*/
+#if MULTI_SPI
+void
+ao_spi_recv(void __xdata *block, uint16_t len, uint8_t bus) __reentrant
+#else
void
ao_spi_recv_bus(void __xdata *block, uint16_t len) __reentrant
+#define bus 0
+#endif
{
- ao_dma_set_transfer(ao_spi_dma_in_id,
- &SPI_BUF,
+ ao_dma_set_transfer(ao_spi_dma_in_id[bus],
+ SPI_BUF(bus),
block,
len,
DMA_CFG0_WORDSIZE_8 |
DMA_CFG0_TMODE_SINGLE |
- SPI_DMA_RX,
+ SPI_DMA_RX(bus),
DMA_CFG1_SRCINC_0 |
DMA_CFG1_DESTINC_1 |
DMA_CFG1_PRIORITY_NORMAL);
ao_spi_const = SPI_CONST;
#if !AO_SPI_SLAVE
- ao_dma_set_transfer(ao_spi_dma_out_id,
+ ao_dma_set_transfer(ao_spi_dma_out_id[bus],
&ao_spi_const,
- &SPI_BUF,
+ SPI_BUF(bus),
len,
DMA_CFG0_WORDSIZE_8 |
DMA_CFG0_TMODE_SINGLE |
- SPI_DMA_TX,
+ SPI_DMA_TX(bus),
DMA_CFG1_SRCINC_0 |
DMA_CFG1_DESTINC_0 |
DMA_CFG1_PRIORITY_NORMAL);
#endif
- ao_dma_start(ao_spi_dma_in_id);
+ ao_dma_start(ao_spi_dma_in_id[bus]);
#if !AO_SPI_SLAVE
- ao_dma_start(ao_spi_dma_out_id);
- ao_dma_trigger(ao_spi_dma_out_id);
- __critical while (!ao_spi_dma_in_done)
- ao_sleep(&ao_spi_dma_in_done);
+ ao_dma_start(ao_spi_dma_out_id[bus]);
+ ao_dma_trigger(ao_spi_dma_out_id[bus]);
+ __critical while (!ao_spi_dma_in_done[bus])
+ ao_sleep(&ao_spi_dma_in_done[bus]);
#endif
}
void
ao_spi_recv_wait(void)
{
- __critical while (!ao_spi_dma_in_done)
- ao_sleep(&ao_spi_dma_in_done);
+ __critical while (!ao_spi_dma_in_done[0])
+ ao_sleep(&ao_spi_dma_in_done[0]);
}
#endif
+/* Set up the USART.
+ *
+ * SPI master/slave mode
+ */
+/* Set the baud rate and signal parameters
+ *
+ * The cc1111 is limited to a 24/8 MHz SPI clock.
+ * Every peripheral I've ever seen goes faster than that,
+ * so set the clock to 3MHz (BAUD_E 17, BAUD_M 0)
+ */
+#define SPI_INIT(bus,o) do { \
+ /* Set up the USART pin assignment */ \
+ PERCFG = (PERCFG & ~SPI_CFG_MASK(bus)) | SPI_CFG(bus); \
+ \
+ /* Make the SPI pins be controlled by the USART peripheral */ \
+ SPI_SEL(bus) |= SPI_BITS(bus) | CSS(bus); \
+ SPI_CSR(bus) = (UxCSR_MODE_SPI | UxCSR_RE | UxCSR_DIRECTION); \
+ SPI_BAUD(bus) = 0; \
+ SPI_GCR(bus) = (UxGCR_CPOL_NEGATIVE | \
+ UxGCR_CPHA_FIRST_EDGE | \
+ UxGCR_ORDER_MSB | \
+ (17 << UxGCR_BAUD_E_SHIFT)); \
+ /* Set up OUT DMA */ \
+ ao_spi_dma_out_id[o] = ao_dma_alloc(&ao_spi_dma_out_done[o]); \
+ \
+ /* Set up IN DMA */ \
+ ao_spi_dma_in_id[o] = ao_dma_alloc(&ao_spi_dma_in_done[o]); \
+ } while (0)
+
void
ao_spi_init(void)
{
- /* Set up the USART pin assignment */
- PERCFG = (PERCFG & ~SPI_CFG_MASK) | SPI_CFG;
-
/* Ensure that SPI USART takes precidence over the other USART
* for pins that they share
*/
P2SEL = (P2SEL & ~P2SEL_PRI3P1_MASK) | SPI_PRI;
#endif
- /* Make the SPI pins be controlled by the USART peripheral */
- SPI_SEL |= SPI_BITS | CSS;
-
- /* Set up OUT DMA */
- ao_spi_dma_out_id = ao_dma_alloc(&ao_spi_dma_out_done);
-
- /* Set up IN DMA */
- ao_spi_dma_in_id = ao_dma_alloc(&ao_spi_dma_in_done);
-
- /* Set up the USART.
- *
- * SPI master/slave mode
- */
- SPI_CSR = (UxCSR_MODE_SPI | UxCSR_RE | UxCSR_DIRECTION);
-
- /* Set the baud rate and signal parameters
- *
- * The cc1111 is limited to a 24/8 MHz SPI clock.
- * Every peripheral I've ever seen goes faster than that,
- * so set the clock to 3MHz (BAUD_E 17, BAUD_M 0)
- */
- SPI_BAUD = 0;
- SPI_GCR = (UxGCR_CPOL_NEGATIVE |
- UxGCR_CPHA_FIRST_EDGE |
- UxGCR_ORDER_MSB |
- (17 << UxGCR_BAUD_E_SHIFT));
+#if HAS_SPI_0
+ SPI_INIT(0, 0);
+#endif
+#if HAS_SPI_1
+ SPI_INIT(1, MULTI_SPI);
+#endif
}
if (++ao_adc_count == ao_adc_interval) {
ao_adc_count = 0;
ao_adc_poll();
+#if (AO_DATA_ALL & ~(AO_DATA_ADC))
+ ao_wakeup(DATA_TO_XDATA(&ao_adc_count));
+#endif
}
#endif
}
while (!(SLEEP & SLEEP_XOSC_STB))
;
+ /* Power down the unused HFRC oscillator */
+ SLEEP |= SLEEP_OSC_PD;
+
+ /* Wait for HFRC to power down */
+ while ((SLEEP & SLEEP_HFRC_STB) != 0)
+ ;
+
/* Crank up the timer tick and system clock speed */
CLKCON = ((CLKCON & ~(CLKCON_TICKSPD_MASK | CLKCON_CLKSPD_MASK)) |
(CLKCON_TICKSPD_1 | CLKCON_CLKSPD_1));
ao_usb_ep0_queue_byte(0);
break;
case AO_USB_REQ_SET_ADDRESS:
+#if USB_FORCE_FLIGHT_IDLE
+ /* Go to idle mode if USB is connected
+ */
+ ao_flight_force_idle = 1;
+#endif
ao_usb_set_address(ao_usb_setup.value);
break;
case AO_USB_REQ_GET_DESCRIPTOR:
#define HAS_TASK 1
#endif
+#ifndef AO_PORT_TYPE
+#define AO_PORT_TYPE uint8_t
+#endif
+
+typedef AO_PORT_TYPE ao_port_t;
+
#if HAS_TASK
#include <ao_task.h>
#else
#define AO_PANIC_SPI 13 /* SPI communication failure */
#define AO_PANIC_CRASH 14 /* Processor crashed */
#define AO_PANIC_BUFIO 15 /* Mis-using bufio API */
+#define AO_PANIC_EXTI 16 /* Mis-using exti API */
+#define AO_PANIC_FAST_TIMER 17 /* Mis-using fast timer API */
#define AO_PANIC_SELF_TEST_CC1120 0x40 | 1 /* Self test failure */
#define AO_PANIC_SELF_TEST_HMC5883 0x40 | 2 /* Self test failure */
#define AO_PANIC_SELF_TEST_MPU6000 0x40 | 3 /* Self test failure */
ao_cmd_hex(void);
void
-ao_cmd_decimal(void);
+ao_cmd_decimal(void) __reentrant;
/* Read a single hex nibble off stdin. */
uint8_t
#define AO_GPS_DATE_VALID (1 << 6)
#define AO_GPS_COURSE_VALID (1 << 7)
+#define AO_GPS_NEW_DATA 1
+#define AO_GPS_NEW_TRACKING 2
+
+extern __xdata uint8_t ao_gps_new;
extern __pdata uint16_t ao_gps_tick;
extern __xdata uint8_t ao_gps_mutex;
extern __xdata struct ao_telemetry_location ao_gps_data;
void
ao_gps_tracking_print(__xdata struct ao_gps_tracking_orig *gps_tracking_data);
+void
+ao_gps_show(void) __reentrant;
+
void
ao_gps_init(void);
uint8_t firing;
};
+extern __code char * __code ao_igniter_status_names[];
+
extern __xdata struct ao_ignition ao_ignition[2];
enum ao_igniter_status
#endif
#define AO_CONFIG_MAJOR 1
-#define AO_CONFIG_MINOR 14
+#define AO_CONFIG_MINOR 15
#define AO_AES_LEN 16
#if HAS_RADIO_AMP
uint8_t radio_amp; /* minor version 14 */
#endif
+#if HAS_GYRO
+ int16_t accel_zero_along; /* minor version 15 */
+ int16_t accel_zero_across; /* minor version 15 */
+ int16_t accel_zero_through; /* minor version 15 */
+#endif
};
#define AO_IGNITE_MODE_DUAL 0
void
ao_adc_sleep(void);
-/* Get a copy of the last complete sample set */
-void
-ao_data_get(__xdata struct ao_data *packet);
-
/* Initialize the A/D converter */
void
ao_adc_init(void);
}
void
-ao_cmd_decimal(void)
+ao_cmd_decimal(void) __reentrant
{
- __pdata uint8_t r = ao_cmd_lex_error;
+ uint8_t r = ao_cmd_lex_error;
ao_cmd_lex_u32 = 0;
ao_cmd_white();
, ao_log_format
#endif
);
-#if HAS_MS5607
- ao_ms5607_info();
-#endif
printf("software-version %s\n", ao_version);
}
#endif
#include "ao.h"
#include "ao_log.h"
-#include <ao_storage.h>
+#include <ao_config.h>
#if HAS_FLIGHT
#include <ao_sample.h>
#include <ao_data.h>
__pdata uint8_t ao_config_dirty;
__xdata uint8_t ao_config_mutex;
+#ifndef AO_CONFIG_DEFAULT_APRS_INTERVAL
+#define AO_CONFIG_DEFAULT_APRS_INTERVAL 0
+#endif
#define AO_CONFIG_DEFAULT_MAIN_DEPLOY 250
#define AO_CONFIG_DEFAULT_RADIO_CHANNEL 0
#define AO_CONFIG_DEFAULT_CALLSIGN "N0CALL"
#define AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX ((uint32_t) 192 * (uint32_t) 1024)
#endif
#endif
+#ifndef AO_CONFIG_DEFAULT_RADIO_POWER
#define AO_CONFIG_DEFAULT_RADIO_POWER 0x60
+#endif
#define AO_CONFIG_DEFAULT_RADIO_AMP 0
#if HAS_EEPROM
static void
_ao_config_put(void)
{
- ao_storage_setup();
- ao_storage_erase(ao_storage_config);
- ao_storage_write(ao_storage_config, &ao_config, sizeof (ao_config));
+ ao_config_setup();
+ ao_config_erase();
+ ao_config_write(0, &ao_config, sizeof (ao_config));
#if HAS_FLIGHT
ao_log_write_erase(0);
#endif
- ao_storage_flush();
+ ao_config_flush();
}
void
* but ao_storage_setup *also* sets ao_storage_config, which we
* need before calling ao_storage_read here
*/
- ao_storage_setup();
- ao_storage_read(ao_storage_config, &ao_config, sizeof (ao_config));
+ ao_config_setup();
+ ao_config_read(0, &ao_config, sizeof (ao_config));
#endif
if (ao_config.major != AO_CONFIG_MAJOR) {
ao_config.major = AO_CONFIG_MAJOR;
ao_config.radio_cal = ao_radio_cal;
#endif
/* Fixups for minor version 4 */
+#if HAS_FLIGHT
if (minor < 4)
ao_config.flight_log_max = AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX;
+#endif
/* Fixupes for minor version 5 */
if (minor < 5)
ao_config.ignite_mode = AO_CONFIG_DEFAULT_IGNITE_MODE;
memset(&ao_config.pyro, '\0', sizeof (ao_config.pyro));
#endif
if (minor < 13)
- ao_config.aprs_interval = 0;
+ ao_config.aprs_interval = AO_CONFIG_DEFAULT_APRS_INTERVAL;
#if HAS_RADIO_POWER
if (minor < 14)
ao_config.radio_power = AO_CONFIG_DEFAULT_RADIO_POWER;
#if HAS_RADIO_AMP
if (minor < 14)
ao_config.radio_amp = AO_CONFIG_DEFAULT_RADIO_AMP;
+#endif
+#if HAS_GYRO
+ if (minor < 15) {
+ ao_config.accel_zero_along = 0;
+ ao_config.accel_zero_across = 0;
+ ao_config.accel_zero_through = 0;
+
+ /* Reset the main accel offsets to force
+ * re-calibration
+ */
+ ao_config.accel_plus_g = 0;
+ ao_config.accel_minus_g = 0;
+ }
#endif
ao_config.minor = AO_CONFIG_MINOR;
ao_config_dirty = 1;
{
printf("Accel cal +1g: %d -1g: %d\n",
ao_config.accel_plus_g, ao_config.accel_minus_g);
+#if HAS_GYRO
+ printf ("IMU cal along %d across %d through %d\n",
+ ao_config.accel_zero_along,
+ ao_config.accel_zero_across,
+ ao_config.accel_zero_through);
+#endif
}
#define ACCEL_CALIBRATE_SAMPLES 1024
#define ACCEL_CALIBRATE_SHIFT 10
+#if HAS_GYRO
+static int16_t accel_cal_along;
+static int16_t accel_cal_across;
+static int16_t accel_cal_through;
+#endif
+
static int16_t
ao_config_accel_calibrate_auto(char *orientation) __reentrant
{
uint16_t i;
int32_t accel_total;
uint8_t cal_data_ring;
+#if HAS_GYRO
+ int32_t accel_along_total = 0;
+ int32_t accel_across_total = 0;
+ int32_t accel_through_total = 0;
+#endif
printf("Orient antenna %s and press a key...", orientation);
flush();
ao_sleep(DATA_TO_XDATA(&ao_sample_data));
while (i && cal_data_ring != ao_sample_data) {
accel_total += (int32_t) ao_data_accel(&ao_data_ring[cal_data_ring]);
+#if HAS_GYRO
+ accel_along_total += (int32_t) ao_data_along(&ao_data_ring[cal_data_ring]);
+ accel_across_total += (int32_t) ao_data_across(&ao_data_ring[cal_data_ring]);
+ accel_through_total += (int32_t) ao_data_through(&ao_data_ring[cal_data_ring]);
+#endif
cal_data_ring = ao_data_ring_next(cal_data_ring);
i--;
}
}
+#if HAS_GYRO
+ accel_cal_along = accel_along_total >> ACCEL_CALIBRATE_SHIFT;
+ accel_cal_across = accel_across_total >> ACCEL_CALIBRATE_SHIFT;
+ accel_cal_through = accel_through_total >> ACCEL_CALIBRATE_SHIFT;
+#endif
return accel_total >> ACCEL_CALIBRATE_SHIFT;
}
ao_config_accel_calibrate_set(void) __reentrant
{
int16_t up, down;
+#if HAS_GYRO
+ int16_t accel_along_up, accel_along_down;
+ int16_t accel_across_up, accel_across_down;
+ int16_t accel_through_up, accel_through_down;
+#endif
+
ao_cmd_decimal();
if (ao_cmd_status != ao_cmd_success)
return;
if (ao_cmd_lex_i == 0) {
up = ao_config_accel_calibrate_auto("up");
+#if HAS_GYRO
+ accel_along_up = accel_cal_along;
+ accel_across_up = accel_cal_across;
+ accel_through_up = accel_cal_through;
+#endif
down = ao_config_accel_calibrate_auto("down");
+#if HAS_GYRO
+ accel_along_down = accel_cal_along;
+ accel_across_down = accel_cal_across;
+ accel_through_down = accel_cal_through;
+#endif
} else {
up = ao_cmd_lex_i;
ao_cmd_decimal();
_ao_config_edit_start();
ao_config.accel_plus_g = up;
ao_config.accel_minus_g = down;
+#if HAS_GYRO
+ ao_config.accel_zero_along = (accel_along_up + accel_along_down) / 2;
+ ao_config.accel_zero_across = (accel_across_up + accel_across_down) / 2;
+ ao_config.accel_zero_through = (accel_through_up + accel_through_down) / 2;
+#endif
_ao_config_edit_finish();
}
#endif /* HAS_ACCEL */
ao_config_log_set(void) __reentrant
{
uint16_t block = (uint16_t) (ao_storage_block >> 10);
- uint16_t config = (uint16_t) (ao_storage_config >> 10);
+ uint16_t log_max = (uint16_t) (ao_storage_log_max >> 10);
ao_cmd_decimal();
if (ao_cmd_status != ao_cmd_success)
printf("Storage must be empty before changing log size\n");
else if (block > 1024 && (ao_cmd_lex_i & (block - 1)))
printf("Flight log size must be multiple of %d kB\n", block);
- else if (ao_cmd_lex_i > config)
- printf("Flight log max %d kB\n", config);
+ else if (ao_cmd_lex_i > log_max)
+ printf("Flight log max %d kB\n", log_max);
else {
_ao_config_edit_start();
ao_config.flight_log_max = (uint32_t) ao_cmd_lex_i << 10;
ao_config_show(void) __reentrant;
static void
-ao_config_write(void) __reentrant;
+ao_config_save(void) __reentrant;
__code struct ao_config_var ao_config_vars[] = {
#if HAS_FLIGHT
ao_config_show, 0 },
#if HAS_EEPROM
{ "w\0Write to eeprom",
- ao_config_write, 0 },
+ ao_config_save, 0 },
#endif
{ "?\0Help",
ao_config_help, 0 },
for (cmd = 0; ao_config_vars[cmd].str != NULL; cmd++)
if (ao_config_vars[cmd].show)
(*ao_config_vars[cmd].show)();
+#if HAS_MS5607
+ ao_ms5607_info();
+#endif
}
#if HAS_EEPROM
static void
-ao_config_write(void) __reentrant
+ao_config_save(void) __reentrant
{
uint8_t saved = 0;
ao_mutex_get(&ao_config_mutex);
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_CONFIG_H_
+#define _AO_CONFIG_H_
+
+#ifndef USE_STORAGE_CONFIG
+#define USE_STORAGE_CONFIG 1
+#endif
+
+#ifndef USE_EEPROM_CONFIG
+#define USE_EEPROM_CONFIG 0
+#endif
+
+#if USE_STORAGE_CONFIG
+
+#include <ao_storage.h>
+
+#define ao_config_setup() ao_storage_setup()
+#define ao_config_erase() ao_storage_erase(ao_storage_config)
+#define ao_config_write(pos,bytes, len) ao_storage_write(ao_storage_config+(pos), bytes, len)
+#define ao_config_read(pos,bytes, len) ao_storage_read(ao_storage_config+(pos), bytes, len)
+#define ao_config_flush() ao_storage_flush()
+
+#endif
+
+#if USE_EEPROM_CONFIG
+
+#include <ao_eeprom.h>
+
+#define ao_config_setup()
+#define ao_config_erase()
+#define ao_config_write(pos,bytes, len) ao_eeprom_write(pos, bytes, len)
+#define ao_config_read(pos,bytes, len) ao_eeprom_read(pos, bytes, len)
+#define ao_config_flush()
+
+#endif
+
+#endif /* _AO_CONFIG_H_ */
--- /dev/null
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+#include <ao_data.h>
+
+volatile __xdata struct ao_data ao_data_ring[AO_DATA_RING];
+volatile __data uint8_t ao_data_head;
+volatile __data uint8_t ao_data_present;
+
+#ifndef ao_data_count
+void
+ao_data_get(__xdata struct ao_data *packet)
+{
+#if HAS_FLIGHT
+ uint8_t i = ao_data_ring_prev(ao_sample_data);
+#else
+ uint8_t i = ao_data_ring_prev(ao_data_head);
+#endif
+ memcpy(packet, (void *) &ao_data_ring[i], sizeof (struct ao_data));
+}
+#endif
#ifndef _AO_DATA_H_
#define _AO_DATA_H_
+#define GRAVITY 9.80665
+
#if HAS_ADC
#define AO_DATA_ADC (1 << 0)
#else
#define ao_data_ring_next(n) (((n) + 1) & (AO_DATA_RING - 1))
#define ao_data_ring_prev(n) (((n) - 1) & (AO_DATA_RING - 1))
+/* Get a copy of the last complete sample set */
+void
+ao_data_get(__xdata struct ao_data *packet);
+
extern volatile __xdata struct ao_data ao_data_ring[AO_DATA_RING];
extern volatile __data uint8_t ao_data_head;
extern volatile __data uint8_t ao_data_present;
* signaled by the timer tick
*/
#define AO_DATA_WAIT() do { \
- ao_sleep((void *) &ao_data_count); \
+ ao_sleep(DATA_TO_XDATA ((void *) &ao_data_count)); \
} while (0)
#endif /* AO_DATA_RING */
/* MMA655X is hooked up so that positive values represent negative acceleration */
#define ao_data_accel(packet) ((packet)->mma655x)
+#if AO_MMA655X_INVERT
+#define ao_data_accel_cook(packet) (4095 - (packet)->mma655x)
+#else
#define ao_data_accel_cook(packet) ((packet)->mma655x)
+#endif
#define ao_data_set_accel(packet, accel) ((packet)->mma655x = (accel))
#define ao_data_accel_invert(accel) (4095 - (accel))
#define HAS_GYRO 1
-typedef int16_t gyro_t;
-typedef int32_t angle_t;
+typedef int16_t gyro_t; /* in raw sample units */
+typedef int16_t angle_t; /* in degrees */
/* Y axis is aligned with the direction of motion (along) */
/* X axis is aligned in the other board axis (across) */
#endif
+#if !HAS_MAG && HAS_HMC5883
+
+#define HAS_MAG 1
+
+typedef int16_t ao_mag_t; /* in raw sample units */
+
+#define ao_data_mag_along(packet) ((packet)->hmc5883.x)
+#define ao_data_mag_across(packet) ((packet)->hmc5883.y)
+#define ao_data_mag_through(packet) ((packet)->hmc5883.z)
+
+#endif
+
#endif /* _AO_DATA_H_ */
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+#include <ao_debounce.h>
+#include <ao_fast_timer.h>
+
+static uint8_t ao_debounce_initialized;
+static uint8_t ao_debounce_running;
+static struct ao_debounce *ao_debounce;
+
+static uint8_t values[64];
+static uint8_t n;
+
+#define d_step(n) (((n) + 1) & 63)
+
+static void
+_ao_debounce_set(struct ao_debounce *debounce, uint8_t value)
+{
+ if (value != debounce->value) {
+ values[n] = value;
+ n = (n + 1) & 63;
+ debounce->value = value;
+ debounce->_set(debounce, value);
+ }
+ _ao_debounce_stop(debounce);
+}
+
+void
+ao_debounce_dump(void)
+{
+ uint8_t s;
+
+ for (s = 0; s < n; s++) {
+ printf ("%d: %d\n",
+ s, values[s]);
+ }
+ n = 0;
+}
+
+/*
+ * Get the current value, set the result when we've
+ * reached the debounce count limit
+ */
+static void
+_ao_debounce_check(struct ao_debounce *debounce)
+{
+ uint8_t next = debounce->_get(debounce);
+
+ if (next == debounce->current) {
+ if (debounce->count < debounce->hold) {
+ if (++debounce->count == debounce->hold)
+ _ao_debounce_set(debounce, debounce->current);
+ }
+ } else {
+ debounce->count = 0;
+ debounce->current = next;
+ }
+}
+
+static void
+_ao_debounce_isr(void)
+{
+ struct ao_debounce *debounce, *next;
+
+ for (debounce = ao_debounce; debounce; debounce = next) {
+ next = debounce->next;
+ _ao_debounce_check(debounce);
+ }
+}
+
+static void
+ao_debounce_on(void)
+{
+ ao_fast_timer_on(_ao_debounce_isr);
+}
+
+static void
+ao_debounce_off(void)
+{
+ ao_fast_timer_off(_ao_debounce_isr);
+}
+
+/*
+ * Start monitoring one pin
+ */
+void
+_ao_debounce_start(struct ao_debounce *debounce)
+{
+ uint32_t m;
+
+ m = ao_arch_irqsave();
+ if (!debounce->running) {
+ debounce->running = 1;
+
+ /* Reset the counter */
+ debounce->count = 0;
+
+ /* Link into list */
+ debounce->next = ao_debounce;
+ ao_debounce = debounce;
+
+ /* Make sure the timer is running */
+ if (!ao_debounce_running++)
+ ao_debounce_on();
+
+ /* And go check the current value */
+ _ao_debounce_check(debounce);
+ }
+ ao_arch_irqrestore(m);
+}
+
+/*
+ * Stop monitoring one pin
+ */
+void
+_ao_debounce_stop(struct ao_debounce *debounce)
+{
+ struct ao_debounce **prev;
+ uint32_t m;
+
+ m = ao_arch_irqsave();
+ if (debounce->running) {
+ debounce->running = 0;
+
+ /* Unlink */
+ for (prev = &ao_debounce; (*prev); prev = &((*prev)->next)) {
+ if (*prev == debounce) {
+ *prev = debounce->next;
+ break;
+ }
+ }
+ debounce->next = NULL;
+
+ /* Turn off the timer if possible */
+ if (!--ao_debounce_running)
+ ao_debounce_off();
+ }
+ ao_arch_irqrestore(m);
+}
+
+void
+ao_debounce_init(void)
+{
+ if (ao_debounce_initialized)
+ return;
+ ao_debounce_initialized = 1;
+ ao_fast_timer_init();
+}
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_DEBOUNCE_H_
+#define _AO_DEBOUNCE_H_
+
+struct ao_debounce {
+ struct ao_debounce *next;
+
+ /* time that pin value must be stable before accepting */
+ uint8_t hold;
+
+ /* last value reported to app; don't report it twice */
+ uint8_t value;
+
+ /* current value received from pins */
+ uint8_t current;
+
+ /* current count of intervals pin value has been stable */
+ uint8_t count;
+
+ /* This pin is running */
+ uint8_t running;
+
+ /* Get the current pin value */
+ uint8_t (*_get)(struct ao_debounce *debounce);
+
+ /* The stable value has changed */
+ void (*_set)(struct ao_debounce *debounce, uint8_t value);
+};
+
+static inline void
+ao_debounce_config(struct ao_debounce *debounce,
+ uint8_t (*_get)(struct ao_debounce *debounce),
+ void (*_set)(struct ao_debounce *debounce, uint8_t value),
+ uint8_t hold)
+{
+ debounce->next = 0;
+ debounce->hold = hold;
+ debounce->value = 0xff;
+ debounce->current = 0xff;
+ debounce->count = 0;
+ debounce->running = 0;
+ debounce->_get = _get;
+ debounce->_set = _set;
+}
+
+void
+_ao_debounce_start(struct ao_debounce *debounce);
+
+void
+_ao_debounce_stop(struct ao_debounce *debounce);
+
+void
+ao_debounce_init(void);
+
+void
+ao_debounce_dump(void);
+
+#endif /* _AO_DEBOUNCE_H_ */
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_EEPROM_H_
+#define _AO_EEPROM_H_
+
+extern const ao_pos_t ao_eeprom_total;
+
+/*
+ * Write to eeprom
+ */
+
+uint8_t
+ao_eeprom_write(ao_pos_t pos32, __xdata void *v, uint16_t len);
+
+/*
+ * Read from eeprom
+ */
+uint8_t
+ao_eeprom_read(ao_pos_t pos, __xdata void *v, uint16_t len);
+
+/*
+ * Initialize eeprom
+ */
+
+void
+ao_eeprom_init(void);
+
+#endif /* _AO_EEPROM_H_ */
#include <ao_log.h>
#endif
+#if HAS_MPU6000
+#include <ao_quaternion.h>
+#endif
+
#ifndef HAS_ACCEL
#error Please define HAS_ACCEL
#endif
__pdata uint16_t ao_boost_tick; /* time of launch detect */
__pdata uint16_t ao_motor_number; /* number of motors burned so far */
+#if HAS_IMU
+/* Any sensor can set this to mark the flight computer as 'broken' */
+__xdata uint8_t ao_sensor_errors;
+#endif
+
/*
* track min/max data over a long interval to detect
* resting
ao_config.accel_minus_g == 0 ||
ao_ground_accel < ao_config.accel_plus_g - ACCEL_NOSE_UP ||
ao_ground_accel > ao_config.accel_minus_g + ACCEL_NOSE_UP ||
+#if HAS_IMU
+ ao_sensor_errors ||
+#endif
ao_ground_height < -1000 ||
ao_ground_height > 7000)
{
{
/* Set pad mode - we can fly! */
ao_flight_state = ao_flight_pad;
-#if HAS_USB && HAS_RADIO && !HAS_FLIGHT_DEBUG && !HAS_SAMPLE_PROFILE
+#if HAS_USB && !HAS_FLIGHT_DEBUG && !HAS_SAMPLE_PROFILE
/* Disable the USB controller in flight mode
* to save power
*/
ao_usb_disable();
#endif
-#if !HAS_ACCEL
+#if !HAS_ACCEL && PACKET_HAS_SLAVE
/* Disable packet mode in pad state on TeleMini */
ao_packet_slave_stop();
#endif
ao_rdf_set(1);
ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_PAD);
#endif
+#if HAS_LED
/* signal successful initialization by turning off the LED */
ao_led_off(AO_LED_RED);
+#endif
} else {
/* Set idle mode */
ao_flight_state = ao_flight_idle;
ao_packet_slave_start();
#endif
+#if HAS_LED
/* signal successful initialization by turning off the LED */
ao_led_off(AO_LED_RED);
+#endif
}
/* wakeup threads due to state change */
ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
#if HAS_GPS
/* Record current GPS position by waking up GPS log tasks */
- ao_wakeup(&ao_gps_data);
- ao_wakeup(&ao_gps_tracking_data);
+ ao_gps_new = AO_GPS_NEW_DATA | AO_GPS_NEW_TRACKING;
+ ao_wakeup(&ao_gps_new);
#endif
ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
ao_interval_end = ao_sample_tick + AO_INTERVAL_TICKS;
}
break;
+#if HAS_FLIGHT_DEBUG
+ case ao_flight_test:
+#if HAS_GYRO
+ printf ("angle %4d pitch %7d yaw %7d roll %7d\n",
+ ao_sample_orient,
+ ((ao_sample_pitch << 9) - ao_ground_pitch) >> 9,
+ ((ao_sample_yaw << 9) - ao_ground_yaw) >> 9,
+ ((ao_sample_roll << 9) - ao_ground_roll) >> 9);
+#endif
+ flush();
+ break;
+#endif /* HAS_FLIGHT_DEBUG */
default:
break;
}
printf (" error_avg %d\n", ao_error_h_sq_avg);
}
+static void
+ao_gyro_test(void)
+{
+ ao_flight_state = ao_flight_test;
+ ao_getchar();
+ ao_flight_state = ao_flight_idle;
+}
+
__code struct ao_cmds ao_flight_cmds[] = {
{ ao_flight_dump, "F\0Dump flight status" },
+ { ao_gyro_test, "G\0Test gyro code" },
{ 0, NULL },
};
#endif
ao_flight_drogue = 6,
ao_flight_main = 7,
ao_flight_landed = 8,
- ao_flight_invalid = 9
+ ao_flight_invalid = 9,
+ ao_flight_test = 10
};
extern __pdata enum ao_flight_state ao_flight_state;
extern __pdata uint16_t ao_boost_tick;
extern __pdata uint16_t ao_motor_number;
+#if HAS_IMU
+extern __xdata uint8_t ao_sensor_errors;
+#endif
+
extern __pdata uint16_t ao_launch_time;
extern __pdata uint8_t ao_flight_force_idle;
{
static __xdata struct ao_log_record gps_log;
static __xdata struct ao_telemetry_location gps_data;
+ static __xdata struct ao_telemetry_satellite gps_tracking_data;
uint8_t date_reported = 0;
+ uint8_t new;
for (;;) {
- ao_sleep(&ao_gps_data);
+ while ((new = ao_gps_new) == 0)
+ ao_sleep(&ao_gps_new);
ao_mutex_get(&ao_gps_mutex);
- ao_xmemcpy(&gps_data, &ao_gps_data, sizeof (ao_gps_data));
+ if (new & AO_GPS_NEW_DATA)
+ ao_xmemcpy(&gps_data, &ao_gps_data, sizeof (ao_gps_data));
+ if (new & AO_GPS_NEW_TRACKING)
+ ao_xmemcpy(&gps_tracking_data, &ao_gps_tracking_data, sizeof (ao_gps_tracking_data));
+ ao_gps_new = 0;
ao_mutex_put(&ao_gps_mutex);
- if (!(gps_data.flags & AO_GPS_VALID))
- continue;
-
- gps_log.tick = ao_gps_tick;
- gps_log.type = AO_LOG_GPS_TIME;
- gps_log.u.gps_time.hour = gps_data.hour;
- gps_log.u.gps_time.minute = gps_data.minute;
- gps_log.u.gps_time.second = gps_data.second;
- gps_log.u.gps_time.flags = gps_data.flags;
- ao_log_data(&gps_log);
- gps_log.type = AO_LOG_GPS_LAT;
- gps_log.u.gps_latitude = gps_data.latitude;
- ao_log_data(&gps_log);
- gps_log.type = AO_LOG_GPS_LON;
- gps_log.u.gps_longitude = gps_data.longitude;
- ao_log_data(&gps_log);
- gps_log.type = AO_LOG_GPS_ALT;
- gps_log.u.gps_altitude.altitude = gps_data.altitude;
- gps_log.u.gps_altitude.unused = 0xffff;
- ao_log_data(&gps_log);
- if (!date_reported && (gps_data.flags & AO_GPS_DATE_VALID)) {
- gps_log.type = AO_LOG_GPS_DATE;
- gps_log.u.gps_date.year = gps_data.year;
- gps_log.u.gps_date.month = gps_data.month;
- gps_log.u.gps_date.day = gps_data.day;
- gps_log.u.gps_date.extra = 0;
- date_reported = ao_log_data(&gps_log);
+ if ((new & AO_GPS_NEW_DATA) && (gps_data.flags & AO_GPS_VALID)) {
+ gps_log.tick = ao_gps_tick;
+ gps_log.type = AO_LOG_GPS_TIME;
+ gps_log.u.gps_time.hour = gps_data.hour;
+ gps_log.u.gps_time.minute = gps_data.minute;
+ gps_log.u.gps_time.second = gps_data.second;
+ gps_log.u.gps_time.flags = gps_data.flags;
+ ao_log_data(&gps_log);
+ gps_log.type = AO_LOG_GPS_LAT;
+ gps_log.u.gps_latitude = gps_data.latitude;
+ ao_log_data(&gps_log);
+ gps_log.type = AO_LOG_GPS_LON;
+ gps_log.u.gps_longitude = gps_data.longitude;
+ ao_log_data(&gps_log);
+ gps_log.type = AO_LOG_GPS_ALT;
+ gps_log.u.gps_altitude.altitude = gps_data.altitude;
+ gps_log.u.gps_altitude.unused = 0xffff;
+ ao_log_data(&gps_log);
+ if (!date_reported && (gps_data.flags & AO_GPS_DATE_VALID)) {
+ gps_log.type = AO_LOG_GPS_DATE;
+ gps_log.u.gps_date.year = gps_data.year;
+ gps_log.u.gps_date.month = gps_data.month;
+ gps_log.u.gps_date.day = gps_data.day;
+ gps_log.u.gps_date.extra = 0;
+ date_reported = ao_log_data(&gps_log);
+ }
}
- }
-}
-
-void
-ao_gps_tracking_report(void)
-{
- static __xdata struct ao_log_record gps_log;
- static __xdata struct ao_telemetry_satellite gps_tracking_data;
- uint8_t c, n;
-
- for (;;) {
- ao_sleep(&ao_gps_tracking_data);
- ao_mutex_get(&ao_gps_mutex);
- gps_log.tick = ao_gps_tick;
- ao_xmemcpy(&gps_tracking_data, &ao_gps_tracking_data, sizeof (ao_gps_tracking_data));
- ao_mutex_put(&ao_gps_mutex);
+ if (new & AO_GPS_NEW_TRACKING) {
+ uint8_t c, n;
- if (!(n = gps_tracking_data.channels))
- continue;
-
- gps_log.type = AO_LOG_GPS_SAT;
- for (c = 0; c < n; c++)
- if ((gps_log.u.gps_sat.svid = gps_tracking_data.sats[c].svid))
- {
- gps_log.u.gps_sat.c_n = gps_tracking_data.sats[c].c_n_1;
- ao_log_data(&gps_log);
+ if ((n = gps_tracking_data.channels) != 0) {
+ gps_log.type = AO_LOG_GPS_SAT;
+ for (c = 0; c < n; c++)
+ if ((gps_log.u.gps_sat.svid = gps_tracking_data.sats[c].svid))
+ {
+ gps_log.u.gps_sat.c_n = gps_tracking_data.sats[c].c_n_1;
+ ao_log_data(&gps_log);
+ }
}
+ }
}
}
__xdata struct ao_task ao_gps_report_task;
-__xdata struct ao_task ao_gps_tracking_report_task;
void
ao_gps_report_init(void)
{
ao_add_task(&ao_gps_report_task, ao_gps_report, "gps_report");
- ao_add_task(&ao_gps_tracking_report_task, ao_gps_tracking_report, "gps_tracking_report");
}
{
static __xdata struct ao_log_mega gps_log;
static __xdata struct ao_telemetry_location gps_data;
- uint8_t date_reported = 0;
-
- for (;;) {
- ao_sleep(&ao_gps_data);
- ao_mutex_get(&ao_gps_mutex);
- ao_xmemcpy(&gps_data, &ao_gps_data, sizeof (ao_gps_data));
- ao_mutex_put(&ao_gps_mutex);
-
- if (!(gps_data.flags & AO_GPS_VALID))
- continue;
-
- gps_log.tick = ao_gps_tick;
- gps_log.type = AO_LOG_GPS_TIME;
- gps_log.u.gps.latitude = gps_data.latitude;
- gps_log.u.gps.longitude = gps_data.longitude;
- gps_log.u.gps.altitude = gps_data.altitude;
-
- gps_log.u.gps.hour = gps_data.hour;
- gps_log.u.gps.minute = gps_data.minute;
- gps_log.u.gps.second = gps_data.second;
- gps_log.u.gps.flags = gps_data.flags;
- gps_log.u.gps.year = gps_data.year;
- gps_log.u.gps.month = gps_data.month;
- gps_log.u.gps.day = gps_data.day;
- ao_log_mega(&gps_log);
- }
-}
-
-void
-ao_gps_tracking_report_mega(void)
-{
- static __xdata struct ao_log_mega gps_log;
static __xdata struct ao_telemetry_satellite gps_tracking_data;
+ uint8_t date_reported = 0;
+ uint8_t new;
uint8_t c, n, i;
for (;;) {
- ao_sleep(&ao_gps_tracking_data);
+ while (!(new = ao_gps_new))
+ ao_sleep(&ao_gps_new);
ao_mutex_get(&ao_gps_mutex);
- ao_xmemcpy(&gps_tracking_data, &ao_gps_tracking_data, sizeof (ao_gps_tracking_data));
+ if (new & AO_GPS_NEW_DATA)
+ ao_xmemcpy(&gps_data, &ao_gps_data, sizeof (ao_gps_data));
+ if (new & AO_GPS_NEW_TRACKING)
+ ao_xmemcpy(&gps_tracking_data, &ao_gps_tracking_data, sizeof (ao_gps_tracking_data));
+ ao_gps_new = 0;
ao_mutex_put(&ao_gps_mutex);
- if (!(n = gps_tracking_data.channels))
- continue;
+ if ((new & AO_GPS_NEW_DATA) && (gps_data.flags & AO_GPS_VALID)) {
+ gps_log.tick = ao_gps_tick;
+ gps_log.type = AO_LOG_GPS_TIME;
+ gps_log.u.gps.latitude = gps_data.latitude;
+ gps_log.u.gps.longitude = gps_data.longitude;
+ gps_log.u.gps.altitude = gps_data.altitude;
- gps_log.type = AO_LOG_GPS_SAT;
- gps_log.tick = ao_gps_tick;
- i = 0;
- for (c = 0; c < n; c++)
- if ((gps_log.u.gps_sat.sats[i].svid = gps_tracking_data.sats[c].svid))
- {
- gps_log.u.gps_sat.sats[i].c_n = gps_tracking_data.sats[c].c_n_1;
- i++;
- }
- gps_log.u.gps_sat.channels = i;
- ao_log_mega(&gps_log);
+ gps_log.u.gps.hour = gps_data.hour;
+ gps_log.u.gps.minute = gps_data.minute;
+ gps_log.u.gps.second = gps_data.second;
+ gps_log.u.gps.flags = gps_data.flags;
+ gps_log.u.gps.year = gps_data.year;
+ gps_log.u.gps.month = gps_data.month;
+ gps_log.u.gps.day = gps_data.day;
+ gps_log.u.gps.course = gps_data.course;
+ gps_log.u.gps.ground_speed = gps_data.ground_speed;
+ gps_log.u.gps.climb_rate = gps_data.climb_rate;
+ gps_log.u.gps.pdop = gps_data.pdop;
+ gps_log.u.gps.hdop = gps_data.hdop;
+ gps_log.u.gps.vdop = gps_data.vdop;
+ gps_log.u.gps.mode = gps_data.mode;
+ ao_log_mega(&gps_log);
+ }
+ if ((new & AO_GPS_NEW_TRACKING) && (n = gps_tracking_data.channels) != 0) {
+ gps_log.tick = ao_gps_tick;
+ gps_log.type = AO_LOG_GPS_SAT;
+ i = 0;
+ for (c = 0; c < n; c++)
+ if ((gps_log.u.gps_sat.sats[i].svid = gps_tracking_data.sats[c].svid))
+ {
+ gps_log.u.gps_sat.sats[i].c_n = gps_tracking_data.sats[c].c_n_1;
+ i++;
+ }
+ gps_log.u.gps_sat.channels = i;
+ ao_log_mega(&gps_log);
+ }
}
}
__xdata struct ao_task ao_gps_report_mega_task;
-__xdata struct ao_task ao_gps_tracking_report_mega_task;
void
ao_gps_report_mega_init(void)
ao_add_task(&ao_gps_report_mega_task,
ao_gps_report_mega,
"gps_report");
- ao_add_task(&ao_gps_tracking_report_mega_task,
- ao_gps_tracking_report_mega,
- "gps_tracking_report");
}
--- /dev/null
+/*
+ * Copyright © 2009 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.
+ */
+
+#include "ao.h"
+#include "ao_log.h"
+
+void
+ao_gps_report_metrum(void)
+{
+ static __xdata struct ao_log_metrum gps_log;
+ static __xdata struct ao_telemetry_location gps_data;
+ static __xdata struct ao_telemetry_satellite gps_tracking_data;
+ uint8_t c, n, i, p, valid, packets;
+ uint8_t svid;
+ uint8_t date_reported = 0;
+ uint8_t new;
+
+ for (;;) {
+ while (!(new = ao_gps_new))
+ ao_sleep(&ao_gps_new);
+ ao_mutex_get(&ao_gps_mutex);
+ if (new & AO_GPS_NEW_DATA)
+ ao_xmemcpy(&gps_data, &ao_gps_data, sizeof (ao_gps_data));
+ if (new & AO_GPS_NEW_TRACKING)
+ ao_xmemcpy(&gps_tracking_data, &ao_gps_tracking_data, sizeof (ao_gps_tracking_data));
+ ao_gps_new = 0;
+ ao_mutex_put(&ao_gps_mutex);
+
+ if ((new & AO_GPS_NEW_DATA) && (gps_data.flags & AO_GPS_VALID)) {
+ gps_log.tick = ao_gps_tick;
+ gps_log.type = AO_LOG_GPS_POS;
+ gps_log.u.gps.latitude = gps_data.latitude;
+ gps_log.u.gps.longitude = gps_data.longitude;
+ gps_log.u.gps.altitude = gps_data.altitude;
+ ao_log_metrum(&gps_log);
+
+ gps_log.type = AO_LOG_GPS_TIME;
+ gps_log.u.gps_time.hour = gps_data.hour;
+ gps_log.u.gps_time.minute = gps_data.minute;
+ gps_log.u.gps_time.second = gps_data.second;
+ gps_log.u.gps_time.flags = gps_data.flags;
+ gps_log.u.gps_time.year = gps_data.year;
+ gps_log.u.gps_time.month = gps_data.month;
+ gps_log.u.gps_time.day = gps_data.day;
+ ao_log_metrum(&gps_log);
+ }
+
+ if ((new & AO_GPS_NEW_TRACKING) && (n = gps_tracking_data.channels)) {
+ gps_log.type = AO_LOG_GPS_SAT;
+ gps_log.tick = ao_gps_tick;
+ i = 0;
+ for (c = 0; c < n; c++) {
+ svid = gps_tracking_data.sats[c].svid;
+ if (svid != 0) {
+ if (i == 4) {
+ gps_log.u.gps_sat.channels = i;
+ gps_log.u.gps_sat.more = 1;
+ ao_log_metrum(&gps_log);
+ i = 0;
+ }
+ gps_log.u.gps_sat.sats[i].svid = svid;
+ gps_log.u.gps_sat.sats[i].c_n = gps_tracking_data.sats[c].c_n_1;
+ i++;
+ }
+ }
+ if (i) {
+ gps_log.u.gps_sat.channels = i;
+ gps_log.u.gps_sat.more = 0;
+ ao_log_metrum(&gps_log);
+ }
+ }
+ }
+}
+
+__xdata struct ao_task ao_gps_report_metrum_task;
+
+void
+ao_gps_report_metrum_init(void)
+{
+ ao_add_task(&ao_gps_report_metrum_task,
+ ao_gps_report_metrum,
+ "gps_report");
+}
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef AO_GPS_TEST
+#include <ao.h>
+#endif
+
+void
+ao_gps_show(void) __reentrant
+{
+ uint8_t i;
+ ao_mutex_get(&ao_gps_mutex);
+ printf ("Date: %02d/%02d/%02d\n", ao_gps_data.year, ao_gps_data.month, ao_gps_data.day);
+ printf ("Time: %02d:%02d:%02d\n", ao_gps_data.hour, ao_gps_data.minute, ao_gps_data.second);
+ printf ("Lat/Lon: %ld %ld\n", (long) ao_gps_data.latitude, (long) ao_gps_data.longitude);
+ printf ("Alt: %d\n", ao_gps_data.altitude);
+ printf ("Flags: 0x%x\n", ao_gps_data.flags);
+ printf ("Sats: %d", ao_gps_tracking_data.channels);
+ for (i = 0; i < ao_gps_tracking_data.channels; i++)
+ printf (" %d %d",
+ ao_gps_tracking_data.sats[i].svid,
+ ao_gps_tracking_data.sats[i].c_n_1);
+ printf ("\ndone\n");
+ ao_mutex_put(&ao_gps_mutex);
+}
#include "ao.h"
#include <ao_data.h>
+#if AO_PYRO_NUM
+#include <ao_pyro.h>
+#endif
+#if HAS_IGNITE
__xdata struct ao_ignition ao_ignition[2];
void
}
}
+#endif
+
void
ao_ignite_manual(void)
{
if (!ao_match_word("DoIt"))
return;
ao_cmd_white();
- if (ao_cmd_lex_c == 'm') {
- if(ao_match_word("main"))
- ao_igniter_fire(ao_igniter_main);
- } else {
- if(ao_match_word("drogue"))
- ao_igniter_fire(ao_igniter_drogue);
+#if HAS_IGNITE
+ if (ao_cmd_lex_c == 'm' && ao_match_word("main")) {
+ ao_igniter_fire(ao_igniter_main);
+ return;
+ }
+ if (ao_cmd_lex_c == 'd' && ao_match_word("drogue")) {
+ ao_igniter_fire(ao_igniter_drogue);
+ return;
+ }
+#endif
+#if AO_PYRO_NUM
+ if ('0' <= ao_cmd_lex_c && ao_cmd_lex_c <= '9') {
+ ao_pyro_manual(ao_cmd_lex_c - '0');
+ return;
}
+#endif
+ ao_cmd_status = ao_cmd_syntax_error;
}
-static __code char * __code igniter_status_names[] = {
+__code char * __code ao_igniter_status_names[] = {
"unknown", "ready", "active", "open"
};
+#if HAS_IGNITE
void
ao_ignite_print_status(enum ao_igniter igniter, __code char *name) __reentrant
{
enum ao_igniter_status status = ao_igniter_status(igniter);
printf("Igniter: %6s Status: %s\n",
name,
- igniter_status_names[status]);
+ ao_igniter_status_names[status]);
}
+#endif
void
ao_ignite_test(void)
{
+#if HAS_IGNITE
ao_ignite_print_status(ao_igniter_drogue, "drogue");
ao_ignite_print_status(ao_igniter_main, "main");
+#endif
+#if AO_PYRO_NUM
+ ao_pyro_print_status();
+#endif
}
__code struct ao_cmds ao_ignite_cmds[] = {
{ 0, NULL },
};
+#if HAS_IGNITE
__xdata struct ao_task ao_igniter_task;
void
ao_enable_output(AO_IGNITER_DROGUE_PORT, AO_IGNITER_DROGUE_PIN, AO_IGNITER_DROGUE, 0);
ao_enable_output(AO_IGNITER_MAIN_PORT, AO_IGNITER_MAIN_PIN, AO_IGNITER_MAIN, 0);
}
+#endif
void
ao_igniter_init(void)
{
+#if HAS_IGNITE
ao_ignite_set_pins();
- ao_cmd_register(&ao_ignite_cmds[0]);
ao_add_task(&ao_igniter_task, ao_igniter, "igniter");
+#endif
+ ao_cmd_register(&ao_ignite_cmds[0]);
}
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao_int64.h>
+
+__pdata ao_int64_t *__data ao_64r, *__data ao_64a, *__data ao_64b;
+
+void ao_plus64(__pdata ao_int64_t *r, __pdata ao_int64_t *a, __pdata ao_int64_t *b) __FATTR {
+ __LOCAL uint32_t t;
+
+ r->high = a->high + b->high;
+ t = a->low + b->low;
+ if (t < a->low)
+ r->high++;
+ r->low = t;
+}
+
+void ao_minus64(__pdata ao_int64_t *r, __pdata ao_int64_t *a, __pdata ao_int64_t *b) __FATTR {
+ __LOCAL uint32_t t;
+
+ r->high = a->high - b->high;
+ t = a->low - b->low;
+ if (t > a->low)
+ r->high--;
+ r->low = t;
+}
+
+void ao_rshift64(__pdata ao_int64_t *r, __pdata ao_int64_t *a, uint8_t d) __FATTR {
+ if (d < 32) {
+ r->low = a->low >> d;
+ if (d)
+ r->low |= a->high << (32 - d);
+ r->high = (int32_t) a->high >> d;
+ } else {
+ d &= 0x1f;
+ r->low = (int32_t) a->high >> d;
+ r->high = 0;
+ }
+}
+
+void ao_lshift64(__pdata ao_int64_t *r, __pdata ao_int64_t *a, uint8_t d) __FATTR {
+ if (d < 32) {
+ r->high = a->high << d;
+ if (d)
+ r->high |= a->low >> (32 - d);
+ r->low = a->low << d;
+ } else {
+ d &= 0x1f;
+ r->high = a->low << d;
+ r->low = 0;
+ }
+}
+
+static void ao_umul64_32_32(__ARG ao_int64_t *r, uint32_t a, uint32_t b) __reentrant {
+ __LOCAL uint32_t s;
+ __LOCAL ao_int64_t t;
+ r->low = (uint32_t) (uint16_t) a * (uint16_t) b;
+ r->high = (uint32_t) (uint16_t) (a >> 16) * (uint16_t) (b >> 16);
+
+ s = (uint32_t) (uint16_t) (a >> 16) * (uint16_t) b;
+
+ t.high = s >> 16;
+ t.low = s << 16;
+ ao_plus64(r, r, &t);
+
+ s = (uint32_t) (uint16_t) a * (uint16_t) (b >> 16);
+
+ t.high = s >> 16;
+ t.low = s << 16;
+ ao_plus64(r, r, &t);
+}
+
+void ao_neg64(__pdata ao_int64_t *r, __pdata ao_int64_t *a) __FATTR {
+ r->high = ~a->high;
+ if (!(r->low = ~a->low + 1))
+ r->high++;
+}
+
+void ao_mul64_32_32(__ARG ao_int64_t *r, int32_t a, int32_t b) __FATTR {
+ uint8_t negative = 0;
+
+ if (a < 0) {
+ a = -a;
+ ++negative;
+ }
+ if (b < 0) {
+ b = -b;
+ --negative;
+ }
+ ao_umul64_32_32(r, a, b);
+ if (negative)
+ ao_neg64(r, r);
+}
+
+static void ao_umul64(__ARG ao_int64_t *r, __ARG ao_int64_t *a, __ARG ao_int64_t *b) __reentrant {
+ __LOCAL ao_int64_t r2, r3;
+
+ ao_umul64_32_32(&r2, a->high, b->low);
+ ao_umul64_32_32(&r3, a->low, b->high);
+ ao_umul64_32_32(r, a->low, b->low);
+
+ r->high += r2.low + r3.low;
+}
+
+static __ARG ao_int64_t ap, bp;
+
+void ao_mul64(__ARG ao_int64_t *r, __ARG ao_int64_t *a, __ARG ao_int64_t *b) __FATTR {
+ uint8_t negative = 0;
+
+ if (ao_int64_negativep(a)) {
+ ao_neg64(&ap, a);
+ a = ≈
+ ++negative;
+ }
+ if (ao_int64_negativep(b)) {
+ ao_neg64(&bp, b);
+ b = &bp;
+ --negative;
+ }
+ ao_umul64(r, a, b);
+ if (negative)
+ ao_neg64(r, r);
+}
+
+static void ao_umul64_64_16(__ARG ao_int64_t *r, __ARG ao_int64_t *a, uint16_t b) __reentrant {
+ __LOCAL uint32_t h;
+
+ h = a->high * b;
+ ao_umul64_32_32(r, a->low, b);
+ r->high += h;
+}
+
+void ao_mul64_64_16(__ARG ao_int64_t *r, __ARG ao_int64_t *a, __ARG uint16_t b) __FATTR {
+ uint8_t negative = 0;
+
+ if ((int32_t) a->high < 0) {
+ ao_neg64(&ap, a);
+ a = ≈
+ negative++;
+ } else
+ ao_umul64_64_16(r, a, b);
+ if (negative)
+ ao_neg64(r, r);
+}
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_INT64_H_
+#define _AO_INT64_H_
+
+#include <stdint.h>
+
+typedef struct {
+ uint32_t high;
+ uint32_t low;
+} ao_int64_t;
+
+#define __FATTR
+#define __ARG __pdata
+#define __LOCAL static __pdata
+
+void ao_plus64(__pdata ao_int64_t *ao_64r, __pdata ao_int64_t *ao_64a, __pdata ao_int64_t *ao_64b) __FATTR;
+void ao_minus64(__pdata ao_int64_t *ao_64r, __pdata ao_int64_t *ao_64a, __pdata ao_int64_t *ao_64b) __FATTR;
+void ao_neg64(__pdata ao_int64_t *ao_64r, __pdata ao_int64_t *ao_64a) __FATTR;
+void ao_rshift64(__pdata ao_int64_t *ao_64r, __pdata ao_int64_t *ao_64a, uint8_t d) __FATTR;
+void ao_lshift64(__pdata ao_int64_t *ao_64r, __pdata ao_int64_t *ao_64a, uint8_t d) __FATTR;
+void ao_mul64_32_32(__ARG ao_int64_t *r, __ARG int32_t a, __ARG int32_t b) __FATTR;
+void ao_mul64_64_16(__ARG ao_int64_t *r, __ARG ao_int64_t *a, __ARG uint16_t b) __FATTR;
+void ao_mul64(__ARG ao_int64_t * __ARG r, __ARG ao_int64_t * __ARG a, __ARG ao_int64_t *__ARG b) __FATTR;
+
+#define ao_int64_init32(r, a) (((r)->high = 0), (r)->low = (a))
+#define ao_int64_init64(r, a, b) (((r)->high = (a)), (r)->low = (b))
+
+#define ao_cast64(a) (((int64_t) (a)->high << 32) | (a)->low)
+
+#define ao_int64_negativep(a) (((int32_t) (a)->high) < 0)
+
+#endif /* _AO_INT64_H_ */
__pdata int16_t ao_height;
__pdata int16_t ao_speed;
__pdata int16_t ao_accel;
-__pdata int16_t ao_max_height;
+__xdata int16_t ao_max_height;
static __pdata int32_t ao_avg_height_scaled;
-__pdata int16_t ao_avg_height;
+__xdata int16_t ao_avg_height;
__pdata int16_t ao_error_h;
__pdata int16_t ao_error_h_sq_avg;
else
#endif
ao_avg_height = (ao_avg_height_scaled + 63) >> 7;
-#ifdef AO_FLIGHT_TEST
- ao_sample_prev_tick = ao_sample_tick;
-#endif
}
#include "ao.h"
#include <ao_log.h>
+#include <ao_config.h>
__pdata uint32_t ao_log_current_pos;
__pdata uint32_t ao_log_end_pos;
static uint32_t
ao_log_erase_pos(uint8_t i)
{
- return i * sizeof (struct ao_log_erase) + AO_STORAGE_ERASE_LOG;
+ return i * sizeof (struct ao_log_erase) + AO_CONFIG_MAX_SIZE;
}
void
{
erase.unused = 0x00;
erase.flight = ao_flight_number;
- ao_storage_write(ao_log_erase_pos(pos), &erase, sizeof (erase));
- ao_storage_flush();
+ ao_config_write(ao_log_erase_pos(pos), &erase, sizeof (erase));
+ ao_config_flush();
}
static void
ao_log_read_erase(uint8_t pos)
{
- ao_storage_read(ao_log_erase_pos(pos), &erase, sizeof (erase));
+ ao_config_read(ao_log_erase_pos(pos), &erase, sizeof (erase));
}
static uint8_t
ao_log_slots()
{
- return (uint8_t) (ao_storage_config / ao_config.flight_log_max);
+ return (uint8_t) (ao_storage_log_max / ao_config.flight_log_max);
}
uint32_t
ao_cmd_register(&ao_log_cmds[0]);
+#ifndef HAS_ADC
+#error Define HAS_ADC for ao_log.c
+#endif
+#if HAS_ADC
/* Create a task to log events to eeprom */
ao_add_task(&ao_log_task, ao_log, "log");
+#endif
}
#define AO_LOG_FORMAT_TELEMETRY 3 /* 32 byte ao_telemetry records */
#define AO_LOG_FORMAT_TELESCIENCE 4 /* 32 byte typed telescience records */
#define AO_LOG_FORMAT_TELEMEGA 5 /* 32 byte typed telemega records */
+#define AO_LOG_FORMAT_EASYMINI 6 /* 16-byte MS5607 baro only, 3.0V supply */
+#define AO_LOG_FORMAT_TELEMETRUM 7 /* 16-byte typed telemetrum records */
+#define AO_LOG_FORMAT_TELEMINI 8 /* 16-byte MS5607 baro only, 3.3V supply */
#define AO_LOG_FORMAT_NONE 127 /* No log at all */
extern __code uint8_t ao_log_format;
#define AO_LOG_GPS_ALT 'H'
#define AO_LOG_GPS_SAT 'V'
#define AO_LOG_GPS_DATE 'Y'
+#define AO_LOG_GPS_POS 'P'
#define AO_LOG_POS_NONE (~0UL)
int16_t v_pbatt; /* 6 */
int16_t n_sense; /* 8 */
int16_t sense[10]; /* 10 */
- } volt; /* 30 */
+ uint16_t pyro; /* 30 */
+ } volt; /* 32 */
/* AO_LOG_GPS_TIME */
struct {
int32_t latitude; /* 4 */
uint8_t year; /* 18 */
uint8_t month; /* 19 */
uint8_t day; /* 20 */
- uint8_t pad; /* 21 */
- } gps; /* 22 */
+ uint8_t course; /* 21 */
+ uint16_t ground_speed; /* 22 */
+ int16_t climb_rate; /* 24 */
+ uint8_t pdop; /* 26 */
+ uint8_t hdop; /* 27 */
+ uint8_t vdop; /* 28 */
+ uint8_t mode; /* 29 */
+ } gps; /* 30 */
/* AO_LOG_GPS_SAT */
struct {
uint16_t channels; /* 4 */
} u;
};
+struct ao_log_metrum {
+ char type; /* 0 */
+ uint8_t csum; /* 1 */
+ uint16_t tick; /* 2 */
+ union { /* 4 */
+ /* AO_LOG_FLIGHT */
+ struct {
+ uint16_t flight; /* 4 */
+ int16_t ground_accel; /* 6 */
+ uint32_t ground_pres; /* 8 */
+ uint32_t ground_temp; /* 12 */
+ } flight; /* 16 */
+ /* AO_LOG_STATE */
+ struct {
+ uint16_t state; /* 4 */
+ uint16_t reason; /* 6 */
+ } state; /* 8 */
+ /* AO_LOG_SENSOR */
+ struct {
+ uint32_t pres; /* 4 */
+ uint32_t temp; /* 8 */
+ int16_t accel; /* 12 */
+ } sensor; /* 14 */
+ /* AO_LOG_TEMP_VOLT */
+ struct {
+ int16_t v_batt; /* 4 */
+ int16_t sense_a; /* 6 */
+ int16_t sense_m; /* 8 */
+ } volt; /* 10 */
+ /* AO_LOG_GPS_POS */
+ struct {
+ int32_t latitude; /* 4 */
+ int32_t longitude; /* 8 */
+ int16_t altitude; /* 12 */
+ } gps; /* 14 */
+ /* AO_LOG_GPS_TIME */
+ struct {
+ uint8_t hour; /* 4 */
+ uint8_t minute; /* 5 */
+ uint8_t second; /* 6 */
+ uint8_t flags; /* 7 */
+ uint8_t year; /* 8 */
+ uint8_t month; /* 9 */
+ uint8_t day; /* 10 */
+ uint8_t pad; /* 11 */
+ } gps_time; /* 12 */
+ /* AO_LOG_GPS_SAT (up to three packets) */
+ struct {
+ uint8_t channels; /* 4 */
+ uint8_t more; /* 5 */
+ struct {
+ uint8_t svid;
+ uint8_t c_n;
+ } sats[4]; /* 6 */
+ } gps_sat; /* 14 */
+ uint8_t raw[12]; /* 4 */
+ } u; /* 16 */
+};
+
+struct ao_log_mini {
+ char type; /* 0 */
+ uint8_t csum; /* 1 */
+ uint16_t tick; /* 2 */
+ union { /* 4 */
+ /* AO_LOG_FLIGHT */
+ struct {
+ uint16_t flight; /* 4 */
+ uint16_t r6;
+ uint32_t ground_pres; /* 8 */
+ } flight;
+ /* AO_LOG_STATE */
+ struct {
+ uint16_t state; /* 4 */
+ uint16_t reason; /* 6 */
+ } state;
+ /* AO_LOG_SENSOR */
+ struct {
+ uint8_t pres[3]; /* 4 */
+ uint8_t temp[3]; /* 7 */
+ int16_t sense_a; /* 10 */
+ int16_t sense_m; /* 12 */
+ int16_t v_batt; /* 14 */
+ } sensor; /* 16 */
+ } u; /* 16 */
+}; /* 16 */
+
+#define ao_log_pack24(dst,value) do { \
+ (dst)[0] = (value); \
+ (dst)[1] = (value) >> 8; \
+ (dst)[2] = (value) >> 16; \
+ } while (0)
+
/* Write a record to the eeprom log */
uint8_t
ao_log_data(__xdata struct ao_log_record *log) __reentrant;
uint8_t
ao_log_mega(__xdata struct ao_log_mega *log) __reentrant;
+uint8_t
+ao_log_metrum(__xdata struct ao_log_metrum *log) __reentrant;
+
+uint8_t
+ao_log_mini(__xdata struct ao_log_mini *log) __reentrant;
+
void
ao_log_flush(void);
+void
+ao_gps_report_metrum_init(void);
+
#endif /* _AO_LOG_H_ */
return 1;
}
+#if HAS_ADC
static __data uint8_t ao_log_data_pos;
/* a hack to make sure that ao_log_megas fill the eeprom block in even units */
log.u.volt.n_sense = AO_ADC_NUM_SENSE;
for (i = 0; i < AO_ADC_NUM_SENSE; i++)
log.u.volt.sense[i] = ao_data_ring[ao_log_data_pos].adc.sense[i];
+ log.u.volt.pyro = ao_pyro_fired;
ao_log_mega(&log);
next_other = log.tick + AO_OTHER_INTERVAL;
}
ao_sleep(&ao_log_running);
}
}
+#endif
uint16_t
ao_log_flight(uint8_t slot)
--- /dev/null
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+#include <ao_log.h>
+#include <ao_data.h>
+#include <ao_flight.h>
+
+static __xdata uint8_t ao_log_mutex;
+static __xdata struct ao_log_metrum log;
+
+__code uint8_t ao_log_format = AO_LOG_FORMAT_TELEMETRUM;
+
+static uint8_t
+ao_log_csum(__xdata uint8_t *b) __reentrant
+{
+ uint8_t sum = 0x5a;
+ uint8_t i;
+
+ for (i = 0; i < sizeof (struct ao_log_metrum); i++)
+ sum += *b++;
+ return -sum;
+}
+
+uint8_t
+ao_log_metrum(__xdata struct ao_log_metrum *log) __reentrant
+{
+ uint8_t wrote = 0;
+ /* set checksum */
+ log->csum = 0;
+ log->csum = ao_log_csum((__xdata uint8_t *) log);
+ ao_mutex_get(&ao_log_mutex); {
+ if (ao_log_current_pos >= ao_log_end_pos && ao_log_running)
+ ao_log_stop();
+ if (ao_log_running) {
+ wrote = 1;
+ ao_storage_write(ao_log_current_pos,
+ log,
+ sizeof (struct ao_log_metrum));
+ ao_log_current_pos += sizeof (struct ao_log_metrum);
+ }
+ } ao_mutex_put(&ao_log_mutex);
+ return wrote;
+}
+
+static uint8_t
+ao_log_dump_check_data(void)
+{
+ if (ao_log_csum((uint8_t *) &log) != 0)
+ return 0;
+ return 1;
+}
+
+#if HAS_ADC
+static __data uint8_t ao_log_data_pos;
+
+/* a hack to make sure that ao_log_metrums fill the eeprom block in even units */
+typedef uint8_t check_log_size[1-(256 % sizeof(struct ao_log_metrum))] ;
+
+#ifndef AO_SENSOR_INTERVAL_ASCENT
+#define AO_SENSOR_INTERVAL_ASCENT 1
+#define AO_SENSOR_INTERVAL_DESCENT 10
+#define AO_OTHER_INTERVAL 32
+#endif
+
+void
+ao_log(void)
+{
+ __pdata uint16_t next_sensor, next_other;
+ uint8_t i;
+
+ ao_storage_setup();
+
+ ao_log_scan();
+
+ while (!ao_log_running)
+ ao_sleep(&ao_log_running);
+
+#if HAS_FLIGHT
+ log.type = AO_LOG_FLIGHT;
+ log.tick = ao_sample_tick;
+#if HAS_ACCEL
+ log.u.flight.ground_accel = ao_ground_accel;
+#endif
+ log.u.flight.ground_pres = ao_ground_pres;
+ log.u.flight.flight = ao_flight_number;
+ ao_log_metrum(&log);
+#endif
+
+ /* Write the whole contents of the ring to the log
+ * when starting up.
+ */
+ ao_log_data_pos = ao_data_ring_next(ao_data_head);
+ next_other = next_sensor = ao_data_ring[ao_log_data_pos].tick;
+ ao_log_state = ao_flight_startup;
+ for (;;) {
+ /* Write samples to EEPROM */
+ while (ao_log_data_pos != ao_data_head) {
+ log.tick = ao_data_ring[ao_log_data_pos].tick;
+ if ((int16_t) (log.tick - next_sensor) >= 0) {
+ log.type = AO_LOG_SENSOR;
+#if HAS_MS5607
+ log.u.sensor.pres = ao_data_ring[ao_log_data_pos].ms5607_raw.pres;
+ log.u.sensor.temp = ao_data_ring[ao_log_data_pos].ms5607_raw.temp;
+#endif
+ log.u.sensor.accel = ao_data_accel(&ao_data_ring[ao_log_data_pos]);
+ ao_log_metrum(&log);
+ if (ao_log_state <= ao_flight_coast)
+ next_sensor = log.tick + AO_SENSOR_INTERVAL_ASCENT;
+ else
+ next_sensor = log.tick + AO_SENSOR_INTERVAL_DESCENT;
+ }
+ if ((int16_t) (log.tick - next_other) >= 0) {
+ log.type = AO_LOG_TEMP_VOLT;
+ log.u.volt.v_batt = ao_data_ring[ao_log_data_pos].adc.v_batt;
+ log.u.volt.sense_a = ao_data_ring[ao_log_data_pos].adc.sense_a;
+ log.u.volt.sense_m = ao_data_ring[ao_log_data_pos].adc.sense_m;
+ ao_log_metrum(&log);
+ next_other = log.tick + AO_OTHER_INTERVAL;
+ }
+ ao_log_data_pos = ao_data_ring_next(ao_log_data_pos);
+ }
+#if HAS_FLIGHT
+ /* Write state change to EEPROM */
+ if (ao_flight_state != ao_log_state) {
+ ao_log_state = ao_flight_state;
+ log.type = AO_LOG_STATE;
+ log.tick = ao_time();
+ log.u.state.state = ao_log_state;
+ log.u.state.reason = 0;
+ ao_log_metrum(&log);
+
+ if (ao_log_state == ao_flight_landed)
+ ao_log_stop();
+ }
+#endif
+
+ ao_log_flush();
+
+ /* Wait for a while */
+ ao_delay(AO_MS_TO_TICKS(100));
+
+ /* Stop logging when told to */
+ while (!ao_log_running)
+ ao_sleep(&ao_log_running);
+ }
+}
+#endif
+
+uint16_t
+ao_log_flight(uint8_t slot)
+{
+ if (!ao_storage_read(ao_log_pos(slot),
+ &log,
+ sizeof (struct ao_log_metrum)))
+ return 0;
+
+ if (ao_log_dump_check_data() && log.type == AO_LOG_FLIGHT)
+ return log.u.flight.flight;
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+#include <ao_micropeak.h>
+#include <ao_log_micro.h>
+#include <ao_async.h>
+
+static uint16_t ao_log_offset = STARTING_LOG_OFFSET;
+
+void
+ao_log_micro_save(void)
+{
+ uint16_t n_samples = (ao_log_offset - STARTING_LOG_OFFSET) / sizeof (uint16_t);
+ ao_eeprom_write(PA_GROUND_OFFSET, &pa_ground, sizeof (pa_ground));
+ ao_eeprom_write(PA_MIN_OFFSET, &pa_min, sizeof (pa_min));
+ ao_eeprom_write(N_SAMPLES_OFFSET, &n_samples, sizeof (n_samples));
+}
+
+void
+ao_log_micro_restore(void)
+{
+ ao_eeprom_read(PA_GROUND_OFFSET, &pa_ground, sizeof (pa_ground));
+ ao_eeprom_read(PA_MIN_OFFSET, &pa_min, sizeof (pa_min));
+}
+
+void
+ao_log_micro_data(void)
+{
+ uint16_t low_bits = pa;
+
+ if (ao_log_offset < MAX_LOG_OFFSET) {
+ ao_eeprom_write(ao_log_offset, &low_bits, sizeof (low_bits));
+ ao_log_offset += sizeof (low_bits);
+ }
+}
+
+#define POLY 0x8408
+
+static uint16_t
+ao_log_micro_crc(uint16_t crc, uint8_t byte)
+{
+ uint8_t i;
+
+ for (i = 0; i < 8; i++) {
+ if ((crc & 0x0001) ^ (byte & 0x0001))
+ crc = (crc >> 1) ^ POLY;
+ else
+ crc = crc >> 1;
+ byte >>= 1;
+ }
+ return crc;
+}
+
+static void
+ao_log_hex_nibble(uint8_t b)
+{
+ if (b < 10)
+ ao_async_byte('0' + b);
+ else
+ ao_async_byte('a' - 10 + b);
+}
+
+static void
+ao_log_hex(uint8_t b)
+{
+ ao_log_hex_nibble(b>>4);
+ ao_log_hex_nibble(b&0xf);
+}
+
+static void
+ao_log_newline(void)
+{
+ ao_async_byte('\r');
+ ao_async_byte('\n');
+}
+
+void
+ao_log_micro_dump(void)
+{
+ uint16_t n_samples;
+ uint16_t nbytes;
+ uint8_t byte;
+ uint16_t b;
+ uint16_t crc = 0xffff;
+
+ ao_eeprom_read(N_SAMPLES_OFFSET, &n_samples, sizeof (n_samples));
+ if (n_samples == 0xffff)
+ n_samples = 0;
+ nbytes = STARTING_LOG_OFFSET + sizeof (uint16_t) * n_samples;
+ ao_async_start();
+ ao_async_byte('M');
+ ao_async_byte('P');
+ for (b = 0; b < nbytes; b++) {
+ if ((b & 0xf) == 0)
+ ao_log_newline();
+ ao_eeprom_read(b, &byte, 1);
+ ao_log_hex(byte);
+ crc = ao_log_micro_crc(crc, byte);
+ }
+ ao_log_newline();
+ crc = ~crc;
+ ao_log_hex(crc >> 8);
+ ao_log_hex(crc);
+ ao_log_newline();
+ ao_async_stop();
+}
--- /dev/null
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_LOG_MICRO_H_
+#define _AO_LOG_MICRO_H_
+
+#define PA_GROUND_OFFSET 0
+#define PA_MIN_OFFSET 4
+#define N_SAMPLES_OFFSET 8
+#define STARTING_LOG_OFFSET 10
+#define MAX_LOG_OFFSET 512
+
+void
+ao_log_micro_save(void);
+
+void
+ao_log_micro_restore(void);
+
+void
+ao_log_micro_data(void);
+
+void
+ao_log_micro_dump(void);
+
+#endif /* _AO_LOG_MICRO_H_ */
--- /dev/null
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+#include <ao_log.h>
+#include <ao_data.h>
+#include <ao_flight.h>
+
+static __xdata uint8_t ao_log_mutex;
+static __xdata struct ao_log_mini log;
+
+__code uint8_t ao_log_format = AO_LOG_FORMAT;
+
+static uint8_t
+ao_log_csum(__xdata uint8_t *b) __reentrant
+{
+ uint8_t sum = 0x5a;
+ uint8_t i;
+
+ for (i = 0; i < sizeof (struct ao_log_mini); i++)
+ sum += *b++;
+ return -sum;
+}
+
+uint8_t
+ao_log_mini(__xdata struct ao_log_mini *log) __reentrant
+{
+ uint8_t wrote = 0;
+ /* set checksum */
+ log->csum = 0;
+ log->csum = ao_log_csum((__xdata uint8_t *) log);
+ ao_mutex_get(&ao_log_mutex); {
+ if (ao_log_current_pos >= ao_log_end_pos && ao_log_running)
+ ao_log_stop();
+ if (ao_log_running) {
+ wrote = 1;
+ ao_storage_write(ao_log_current_pos,
+ log,
+ sizeof (struct ao_log_mini));
+ ao_log_current_pos += sizeof (struct ao_log_mini);
+ }
+ } ao_mutex_put(&ao_log_mutex);
+ return wrote;
+}
+
+static uint8_t
+ao_log_dump_check_data(void)
+{
+ if (ao_log_csum((uint8_t *) &log) != 0)
+ return 0;
+ return 1;
+}
+
+static __data uint8_t ao_log_data_pos;
+
+/* a hack to make sure that ao_log_minis fill the eeprom block in even units */
+typedef uint8_t check_log_size[1-(256 % sizeof(struct ao_log_mini))] ;
+
+#ifndef AO_SENSOR_INTERVAL_ASCENT
+#define AO_SENSOR_INTERVAL_ASCENT 1
+#define AO_SENSOR_INTERVAL_DESCENT 10
+#endif
+
+void
+ao_log(void)
+{
+ __pdata uint16_t next_sensor, next_other;
+
+ ao_storage_setup();
+
+ ao_log_scan();
+
+ while (!ao_log_running)
+ ao_sleep(&ao_log_running);
+
+#if HAS_FLIGHT
+ log.type = AO_LOG_FLIGHT;
+ log.tick = ao_sample_tick;
+ log.u.flight.flight = ao_flight_number;
+ log.u.flight.ground_pres = ao_ground_pres;
+ ao_log_mini(&log);
+#endif
+
+ /* Write the whole contents of the ring to the log
+ * when starting up.
+ */
+ ao_log_data_pos = ao_data_ring_next(ao_data_head);
+ next_other = next_sensor = ao_data_ring[ao_log_data_pos].tick;
+ ao_log_state = ao_flight_startup;
+ for (;;) {
+ /* Write samples to EEPROM */
+ while (ao_log_data_pos != ao_data_head) {
+ log.tick = ao_data_ring[ao_log_data_pos].tick;
+ if ((int16_t) (log.tick - next_sensor) >= 0) {
+ log.type = AO_LOG_SENSOR;
+ ao_log_pack24(log.u.sensor.pres,
+ ao_data_ring[ao_log_data_pos].ms5607_raw.pres);
+ ao_log_pack24(log.u.sensor.temp,
+ ao_data_ring[ao_log_data_pos].ms5607_raw.temp);
+ log.u.sensor.sense_a = ao_data_ring[ao_log_data_pos].adc.sense_a;
+ log.u.sensor.sense_m = ao_data_ring[ao_log_data_pos].adc.sense_m;
+ log.u.sensor.v_batt = ao_data_ring[ao_log_data_pos].adc.v_batt;
+ ao_log_mini(&log);
+ if (ao_log_state <= ao_flight_coast)
+ next_sensor = log.tick + AO_SENSOR_INTERVAL_ASCENT;
+ else
+ next_sensor = log.tick + AO_SENSOR_INTERVAL_DESCENT;
+ }
+ ao_log_data_pos = ao_data_ring_next(ao_log_data_pos);
+ }
+#if HAS_FLIGHT
+ /* Write state change to EEPROM */
+ if (ao_flight_state != ao_log_state) {
+ ao_log_state = ao_flight_state;
+ log.type = AO_LOG_STATE;
+ log.tick = ao_time();
+ log.u.state.state = ao_log_state;
+ log.u.state.reason = 0;
+ ao_log_mini(&log);
+
+ if (ao_log_state == ao_flight_landed)
+ ao_log_stop();
+ }
+#endif
+
+ ao_log_flush();
+
+ /* Wait for a while */
+ ao_delay(AO_MS_TO_TICKS(100));
+
+ /* Stop logging when told to */
+ while (!ao_log_running)
+ ao_sleep(&ao_log_running);
+ }
+}
+
+uint16_t
+ao_log_flight(uint8_t slot)
+{
+ if (!ao_storage_read(ao_log_pos(slot),
+ &log,
+ sizeof (struct ao_log_mini)))
+ return 0;
+
+ if (ao_log_dump_check_data() && log.type == AO_LOG_FLIGHT)
+ return log.u.flight.flight;
+ return 0;
+}
static __data uint8_t ao_log_monitor_pos;
__pdata enum ao_flight_state ao_flight_state;
-__pdata int16_t ao_max_height; /* max of ao_height */
+__xdata int16_t ao_max_height; /* max of ao_height */
__pdata int16_t sense_d, sense_m;
__pdata uint8_t ao_igniter_present;
*/
ao_sleep(DATA_TO_XDATA(&ao_sample_data));
while (ao_log_data != ao_sample_data) {
- sum += ao_data_ring[ao_log_data].adc.pres;
+ sum += ao_data_pres(&ao_data_ring[ao_log_data]);
count++;
ao_log_data = ao_data_ring_next(ao_log_data);
}
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef AO_FLIGHT_TEST
+#include <ao.h>
+#endif
+#include <ao_micropeak.h>
+#include <ao_log_micro.h>
+
+uint32_t pa;
+uint32_t pa_ground;
+uint32_t pa_min;
+
+static void
+ao_microsample(void)
+{
+ ao_pa_get();
+ ao_microkalman_predict();
+ ao_microkalman_correct();
+}
+
+#define NUM_PA_HIST (GROUND_AVG)
+
+#define SKIP_PA_HIST(i,j) (((i) + (j)) & (NUM_PA_HIST - 1))
+
+static uint32_t pa_hist[NUM_PA_HIST];
+
+void
+ao_microflight(void)
+{
+ int16_t sample_count;
+ uint16_t time;
+ uint32_t pa_interval_min, pa_interval_max;
+ int32_t pa_diff;
+ uint8_t h, i;
+ uint8_t accel_lock = 0;
+ uint32_t pa_sum = 0;
+
+ /* Wait for motion, averaging values to get ground pressure */
+
+ time = ao_time();
+ ao_pa_get();
+ ao_microkalman_init();
+ pa_ground = pa;
+ sample_count = 0;
+ h = 0;
+ for (;;) {
+ time += SAMPLE_SLEEP;
+ if ((sample_count & 0x1f) == 0)
+ ao_led_on(AO_LED_REPORT);
+ ao_delay_until(time);
+ ao_microsample();
+ if ((sample_count & 0x1f) == 0)
+ ao_led_off(AO_LED_REPORT);
+ pa_hist[h] = pa;
+ h = SKIP_PA_HIST(h,1);
+ pa_diff = pa_ground - ao_pa;
+
+ /* Check for a significant pressure change */
+ if (pa_diff > BOOST_DETECT)
+ break;
+
+ if (sample_count < GROUND_AVG * 2) {
+ if (sample_count < GROUND_AVG)
+ pa_sum += pa;
+ ++sample_count;
+ } else {
+ pa_ground = pa_sum >> GROUND_AVG_SHIFT;
+ pa_sum = 0;
+ sample_count = 0;
+ }
+ }
+
+ /* Go back and find the last sample close to the ground */
+ pa_min = pa_ground - LAND_DETECT;
+ for (i = SKIP_PA_HIST(h,-2); i != SKIP_PA_HIST(h,2); i = SKIP_PA_HIST(i,-2)) {
+ if (pa_hist[i] >= pa_min)
+ break;
+ }
+
+ /* Log the remaining samples so we get a complete history since leaving the ground */
+ for (; i != h; i = SKIP_PA_HIST(i,2)) {
+ pa = pa_hist[i];
+ ao_log_micro_data();
+ }
+
+ /* Now sit around until the pressure is stable again and record the max */
+
+ sample_count = 0;
+ pa_min = ao_pa;
+ pa_interval_min = ao_pa;
+ pa_interval_max = ao_pa;
+ for (;;) {
+ time += SAMPLE_SLEEP;
+ ao_delay_until(time);
+ if ((sample_count & 3) == 0)
+ ao_led_on(AO_LED_REPORT);
+ ao_microsample();
+ if ((sample_count & 3) == 0)
+ ao_led_off(AO_LED_REPORT);
+ if (sample_count & 1)
+ ao_log_micro_data();
+
+ /* If accelerating upwards, don't look for min pressure */
+ if (ao_pa_accel < ACCEL_LOCK_PA)
+ accel_lock = ACCEL_LOCK_TIME;
+ else if (accel_lock)
+ --accel_lock;
+ else if (ao_pa < pa_min)
+ pa_min = ao_pa;
+
+ if (sample_count == (GROUND_AVG - 1)) {
+ pa_diff = pa_interval_max - pa_interval_min;
+
+ /* Check to see if the pressure is now stable */
+ if (pa_diff < LAND_DETECT)
+ break;
+ sample_count = 0;
+ pa_interval_min = ao_pa;
+ pa_interval_max = ao_pa;
+ } else {
+ if (ao_pa < pa_interval_min)
+ pa_interval_min = ao_pa;
+ if (ao_pa > pa_interval_max)
+ pa_interval_max = ao_pa;
+ ++sample_count;
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef AO_FLIGHT_TEST
+#include <ao.h>
+#endif
+#include <ao_micropeak.h>
+
+#define FIX_BITS 16
+
+#define to_fix16(x) ((int16_t) ((x) * 65536.0 + 0.5))
+#define to_fix32(x) ((int32_t) ((x) * 65536.0 + 0.5))
+#define from_fix8(x) ((x) >> 8)
+#define from_fix(x) ((x) >> 16)
+#define fix8_to_fix16(x) ((x) << 8)
+#define fix16_to_fix8(x) ((x) >> 8)
+
+#include <ao_kalman.h>
+
+/* Basic time step (96ms) */
+#define AO_MK_STEP to_fix16(0.096)
+/* step ** 2 / 2 */
+#define AO_MK_STEP_2_2 to_fix16(0.004608)
+
+uint32_t ao_k_pa; /* 24.8 fixed point */
+int32_t ao_k_pa_speed; /* 16.16 fixed point */
+int32_t ao_k_pa_accel; /* 16.16 fixed point */
+
+uint32_t ao_pa; /* integer portion */
+int16_t ao_pa_speed; /* integer portion */
+int16_t ao_pa_accel; /* integer portion */
+
+void
+ao_microkalman_init(void)
+{
+ ao_pa = pa;
+ ao_k_pa = pa << 8;
+}
+
+void
+ao_microkalman_predict(void)
+{
+ ao_k_pa += fix16_to_fix8((int32_t) ao_pa_speed * AO_MK_STEP + (int32_t) ao_pa_accel * AO_MK_STEP_2_2);
+ ao_k_pa_speed += (int32_t) ao_pa_accel * AO_MK_STEP;
+}
+
+void
+ao_microkalman_correct(void)
+{
+ int16_t e; /* Height error in Pa */
+
+ e = pa - from_fix8(ao_k_pa);
+
+ ao_k_pa += fix16_to_fix8((int32_t) e * AO_MK_BARO_K0_10);
+ ao_k_pa_speed += (int32_t) e * AO_MK_BARO_K1_10;
+ ao_k_pa_accel += (int32_t) e * AO_MK_BARO_K2_10;
+ ao_pa = from_fix8(ao_k_pa);
+ ao_pa_speed = from_fix(ao_k_pa_speed);
+ ao_pa_accel = from_fix(ao_k_pa_accel);
+}
#define LE_WORD(x) ((x)&0xFF),((uint8_t) (((uint16_t) (x))>>8))
#if HAS_USB
+
+/* Maximum power in mA */
+#ifndef AO_USB_MAX_POWER
+#define AO_USB_MAX_POWER 100
+#endif
+
#include "ao_usb.h"
/* USB descriptors in one giant block of bytes */
AO_ROMCONFIG_SYMBOL(0x00aa) uint8_t ao_usb_descriptors [] =
0x01, /* bConfigurationValue */
0x00, /* iConfiguration */
0xC0, /* bmAttributes */
- 0x32, /* bMaxPower */
+ AO_USB_MAX_POWER >> 1, /* bMaxPower, 2mA units */
/* Control class interface */
0x09,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
+#ifndef AO_FLIGHT_TEST
#include <ao.h>
-#include <ao_pyro.h>
#include <ao_sample.h>
#include <ao_flight.h>
+#endif
+#include <ao_pyro.h>
#if IS_COMPANION
#include <ao_companion.h>
#define ao_lowbit(x) ((x) & (-x))
+#ifndef AO_FLIGHT_TEST
+enum ao_igniter_status
+ao_pyro_status(uint8_t p)
+{
+ __xdata struct ao_data packet;
+ __pdata int16_t value;
+
+ ao_arch_critical(
+ ao_data_get(&packet);
+ );
+
+ value = (AO_IGNITER_CLOSED>>1);
+ value = AO_SENSE_PYRO(&packet, p);
+ if (value < AO_IGNITER_OPEN)
+ return ao_igniter_open;
+ else if (value > AO_IGNITER_CLOSED)
+ return ao_igniter_ready;
+ else
+ return ao_igniter_unknown;
+}
+
+void
+ao_pyro_print_status(void)
+{
+ uint8_t p;
+
+ for(p = 0; p < AO_PYRO_NUM; p++) {
+ enum ao_igniter_status status = ao_pyro_status(p);
+ printf("Igniter: %d Status: %s\n",
+ p, ao_igniter_status_names[status]);
+ }
+}
+#endif
+
+uint16_t ao_pyro_fired;
+
/*
* Given a pyro structure, figure out
* if the current flight state satisfies all
continue;
break;
-#if HAS_ORIENT
+#if HAS_GYRO
case ao_pyro_orient_less:
- if (ao_orient <= pyro->orient_less)
+ if (ao_sample_orient <= pyro->orient_less)
continue;
break;
case ao_pyro_orient_greater:
- if (ao_orient >= pyro->orient_greater)
+ if (ao_sample_orient >= pyro->orient_greater)
continue;
break;
#endif
return TRUE;
}
-#define ao_pyro_fire_port(port, bit, pin) do { \
- ao_gpio_set(port, bit, pin, 1); \
- ao_delay(AO_MS_TO_TICKS(50)); \
- ao_gpio_set(port, bit, pin, 0); \
- } while (0)
-
-
+#ifndef AO_FLIGHT_TEST
static void
-ao_pyro_fire(uint8_t p)
+ao_pyro_pin_set(uint8_t p, uint8_t v)
{
switch (p) {
#if AO_PYRO_NUM > 0
- case 0: ao_pyro_fire_port(AO_PYRO_PORT_0, AO_PYRO_PIN_0, AO_PYRO_0); break;
+ case 0: ao_gpio_set(AO_PYRO_PORT_0, AO_PYRO_PIN_0, AO_PYRO_0, v); break;
#endif
#if AO_PYRO_NUM > 1
- case 1: ao_pyro_fire_port(AO_PYRO_PORT_1, AO_PYRO_PIN_1, AO_PYRO_1); break;
+ case 1: ao_gpio_set(AO_PYRO_PORT_1, AO_PYRO_PIN_1, AO_PYRO_1, v); break;
#endif
#if AO_PYRO_NUM > 2
- case 2: ao_pyro_fire_port(AO_PYRO_PORT_2, AO_PYRO_PIN_2, AO_PYRO_2); break;
+ case 2: ao_gpio_set(AO_PYRO_PORT_2, AO_PYRO_PIN_2, AO_PYRO_2, v); break;
#endif
#if AO_PYRO_NUM > 3
- case 3: ao_pyro_fire_port(AO_PYRO_PORT_3, AO_PYRO_PIN_3, AO_PYRO_3); break;
+ case 3: ao_gpio_set(AO_PYRO_PORT_3, AO_PYRO_PIN_3, AO_PYRO_3, v); break;
#endif
#if AO_PYRO_NUM > 4
- case 4: ao_pyro_fire_port(AO_PYRO_PORT_4, AO_PYRO_PIN_4, AO_PYRO_4); break;
+ case 4: ao_gpio_set(AO_PYRO_PORT_4, AO_PYRO_PIN_4, AO_PYRO_4, v); break;
#endif
#if AO_PYRO_NUM > 5
- case 5: ao_pyro_fire_port(AO_PYRO_PORT_5, AO_PYRO_PIN_5, AO_PYRO_5); break;
+ case 5: ao_gpio_set(AO_PYRO_PORT_5, AO_PYRO_PIN_5, AO_PYRO_5, v); break;
#endif
#if AO_PYRO_NUM > 6
- case 6: ao_pyro_fire_port(AO_PYRO_PORT_6, AO_PYRO_PIN_6, AO_PYRO_6); break;
+ case 6: ao_gpio_set(AO_PYRO_PORT_6, AO_PYRO_PIN_6, AO_PYRO_6, v); break;
#endif
#if AO_PYRO_NUM > 7
- case 7: ao_pyro_fire_port(AO_PYRO_PORT_7, AO_PYRO_PIN_7, AO_PYRO_7); break;
+ case 7: ao_gpio_set(AO_PYRO_PORT_7, AO_PYRO_PIN_7, AO_PYRO_7, v); break;
#endif
default: break;
}
- ao_delay(AO_MS_TO_TICKS(50));
}
+#endif
uint8_t ao_pyro_wakeup;
static void
-ao_pyro(void)
+ao_pyro_pins_fire(uint16_t fire)
{
- uint8_t p, any_waiting;
- struct ao_pyro *pyro;
+ uint8_t p;
- ao_config_get();
- while (ao_flight_state < ao_flight_boost)
- ao_sleep(&ao_flight_state);
+ for (p = 0; p < AO_PYRO_NUM; p++) {
+ if (fire & (1 << p))
+ ao_pyro_pin_set(p, 1);
+ }
+ ao_delay(AO_MS_TO_TICKS(50));
+ for (p = 0; p < AO_PYRO_NUM; p++) {
+ if (fire & (1 << p)) {
+ ao_pyro_pin_set(p, 0);
+ ao_config.pyro[p].fired = 1;
+ ao_pyro_fired |= (1 << p);
+ }
+ }
+ ao_delay(AO_MS_TO_TICKS(50));
+}
- for (;;) {
- ao_alarm(AO_MS_TO_TICKS(100));
- ao_sleep(&ao_pyro_wakeup);
- ao_clear_alarm();
- any_waiting = 0;
- for (p = 0; p < AO_PYRO_NUM; p++) {
- pyro = &ao_config.pyro[p];
+static uint8_t
+ao_pyro_check(void)
+{
+ struct ao_pyro *pyro;
+ uint8_t p, any_waiting;
+ uint16_t fire = 0;
+
+ any_waiting = 0;
+ for (p = 0; p < AO_PYRO_NUM; p++) {
+ pyro = &ao_config.pyro[p];
- /* Ignore igniters which have already fired
- */
- if (pyro->fired)
- continue;
+ /* Ignore igniters which have already fired
+ */
+ if (pyro->fired)
+ continue;
- /* Ignore disabled igniters
- */
- if (!pyro->flags)
- continue;
+ /* Ignore disabled igniters
+ */
+ if (!pyro->flags)
+ continue;
- any_waiting = 1;
- /* Check pyro state to see if it shoule fire
- */
- if (!pyro->delay_done) {
- if (!ao_pyro_ready(pyro))
- continue;
-
- /* If there's a delay set, then remember when
- * it expires
- */
- if (pyro->flags & ao_pyro_delay)
- pyro->delay_done = ao_time() + pyro->delay;
- }
+ any_waiting = 1;
+ /* Check pyro state to see if it should fire
+ */
+ if (!pyro->delay_done) {
+ if (!ao_pyro_ready(pyro))
+ continue;
- /* Check to see if we're just waiting for
- * the delay to expire
+ /* If there's a delay set, then remember when
+ * it expires
*/
- if (pyro->delay_done) {
- if ((int16_t) (ao_time() - pyro->delay_done) < 0)
- continue;
+ if (pyro->flags & ao_pyro_delay) {
+ pyro->delay_done = ao_time() + pyro->delay;
+ if (!pyro->delay_done)
+ pyro->delay_done = 1;
}
+ }
- ao_pyro_fire(p);
+ /* Check to see if we're just waiting for
+ * the delay to expire
+ */
+ if (pyro->delay_done) {
+ if ((int16_t) (ao_time() - pyro->delay_done) < 0)
+ continue;
}
- if (!any_waiting)
- break;
+
+ fire |= (1 << p);
}
- ao_exit();
-}
-__xdata struct ao_task ao_pyro_task;
+ if (fire)
+ ao_pyro_pins_fire(fire);
+
+ return any_waiting;
+}
#define NO_VALUE 0xff
{ "h<", ao_pyro_height_less, offsetof(struct ao_pyro, height_less), HELP("height less (m)") },
{ "h>", ao_pyro_height_greater, offsetof(struct ao_pyro, height_greater), HELP("height greater (m)") },
-#if HAS_ORIENT
+#if HAS_GYRO
{ "o<", ao_pyro_orient_less, offsetof(struct ao_pyro, orient_less), HELP("orient less (deg)") },
{ "o>", ao_pyro_orient_greater, offsetof(struct ao_pyro, orient_greater), HELP("orient greater (deg)") },
#endif
{ "", ao_pyro_none, NO_VALUE, HELP(NULL) },
};
+#define NUM_PYRO_VALUES (sizeof ao_pyro_values / sizeof ao_pyro_values[0])
+
+#ifndef AO_FLIGHT_TEST
+static void
+ao_pyro(void)
+{
+ uint8_t any_waiting;
+
+ ao_config_get();
+ while (ao_flight_state < ao_flight_boost)
+ ao_sleep(&ao_flight_state);
+
+ for (;;) {
+ ao_alarm(AO_MS_TO_TICKS(100));
+ ao_sleep(&ao_pyro_wakeup);
+ ao_clear_alarm();
+ if (ao_flight_state >= ao_flight_landed)
+ break;
+ any_waiting = ao_pyro_check();
+ if (!any_waiting)
+ break;
+ }
+ ao_exit();
+}
+
+__xdata struct ao_task ao_pyro_task;
+
+
static void
ao_pyro_print_name(uint8_t v)
{
_ao_config_edit_finish();
}
-static void
-ao_pyro_manual(void)
+void
+ao_pyro_manual(uint8_t p)
{
- ao_cmd_white();
- if (!ao_match_word("DoIt"))
- return;
- ao_cmd_white();
- ao_cmd_decimal();
- if (ao_cmd_lex_i < 0 || AO_PYRO_NUM <= ao_cmd_lex_i)
+ printf ("ao_pyro_manual %d\n", p);
+ if (p >= AO_PYRO_NUM) {
+ ao_cmd_status = ao_cmd_syntax_error;
return;
- ao_pyro_fire(ao_cmd_lex_i);
-
+ }
+ ao_pyro_pins_fire(1 << p);
}
-const struct ao_cmds ao_pyro_cmds[] = {
- { ao_pyro_manual, "P DoIt <n>\0Fire igniter" },
- { 0, NULL }
-};
-
void
ao_pyro_init(void)
{
#if AO_PYRO_NUM > 7
ao_enable_output(AO_PYRO_PORT_7, AO_PYRO_PIN_7, AO_PYRO_7, 0);
#endif
- ao_cmd_register(&ao_pyro_cmds[0]);
ao_add_task(&ao_pyro_task, ao_pyro, "pyro");
}
+#endif
extern uint8_t ao_pyro_wakeup;
+extern uint16_t ao_pyro_fired;
+
void
ao_pyro_set(void);
void
ao_pyro_init(void);
+void
+ao_pyro_manual(uint8_t p);
+
+void
+ao_pyro_print_status(void);
+
#endif
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_QUATERNION_H_
+#define _AO_QUATERNION_H_
+
+#include <math.h>
+
+struct ao_quaternion {
+ float r; /* real bit */
+ float x, y, z; /* imaginary bits */
+};
+
+static inline void ao_quaternion_multiply(struct ao_quaternion *r,
+ const struct ao_quaternion *a,
+ const struct ao_quaternion *b)
+{
+ struct ao_quaternion t;
+#define T(_a,_b) (((a)->_a) * ((b)->_b))
+
+/*
+ * Quaternions
+ *
+ * ii = jj = kk = ijk = -1;
+ *
+ * kji = 1;
+ *
+ * ij = k; ji = -k;
+ * kj = -i; jk = i;
+ * ik = -j; ki = j;
+ *
+ * Multiplication p * q:
+ *
+ * (pr + ipx + jpy + kpz) (qr + iqx + jqy + kqz) =
+ *
+ * ( pr * qr + pr * iqx + pr * jqy + pr * kqz) +
+ * (ipx * qr + ipx * iqx + ipx * jqy + ipx * kqz) +
+ * (jpy * qr + jpy * iqx + jpy * jqy + jpy * kqz) +
+ * (kpz * qr + kpz * iqx + kpz * jqy + kpz * kqz) =
+ *
+ *
+ * (pr * qr) + i(pr * qx) + j(pr * qy) + k(pr * qz) +
+ * i(px * qr) - (px * qx) + k(px * qy) - j(px * qz) +
+ * j(py * qr) - k(py * qx) - (py * qy) + i(py * qz) +
+ * k(pz * qr) + j(pz * qx) - i(pz * qy) - (pz * qz) =
+ *
+ * 1 * ( (pr * qr) - (px * qx) - (py * qy) - (pz * qz) ) +
+ * i * ( (pr * qx) + (px * qr) + (py * qz) - (pz * qy) ) +
+ * j * ( (pr * qy) - (px * qz) + (py * qr) + (pz * qx) ) +
+ * k * ( (pr * qz) + (px * qy) - (py * qx) + (pz * qr);
+ */
+
+ t.r = T(r,r) - T(x,x) - T(y,y) - T(z,z);
+ t.x = T(r,x) + T(x,r) + T(y,z) - T(z,y);
+ t.y = T(r,y) - T(x,z) + T(y,r) + T(z,x);
+ t.z = T(r,z) + T(x,y) - T(y,x) + T(z,r);
+#undef T
+ *r = t;
+}
+
+static inline void ao_quaternion_conjugate(struct ao_quaternion *r,
+ const struct ao_quaternion *a)
+{
+ r->r = a->r;
+ r->x = -a->x;
+ r->y = -a->y;
+ r->z = -a->z;
+}
+
+static inline float ao_quaternion_normal(const struct ao_quaternion *a)
+{
+#define S(_a) (((a)->_a) * ((a)->_a))
+ return S(r) + S(x) + S(y) + S(z);
+#undef S
+}
+
+static inline void ao_quaternion_scale(struct ao_quaternion *r,
+ const struct ao_quaternion *a,
+ float b)
+{
+ r->r = a->r * b;
+ r->x = a->x * b;
+ r->y = a->y * b;
+ r->z = a->z * b;
+}
+
+static inline void ao_quaternion_normalize(struct ao_quaternion *r,
+ const struct ao_quaternion *a)
+{
+ float n = ao_quaternion_normal(a);
+
+ if (n > 0)
+ ao_quaternion_scale(r, a, 1/sqrtf(n));
+ else
+ *r = *a;
+}
+
+static inline float ao_quaternion_dot(const struct ao_quaternion *a,
+ const struct ao_quaternion *b)
+{
+#define T(_a) (((a)->_a) * ((b)->_a))
+ return T(r) + T(x) + T(y) + T(z);
+#undef T
+}
+
+
+static inline void ao_quaternion_rotate(struct ao_quaternion *r,
+ const struct ao_quaternion *a,
+ const struct ao_quaternion *b)
+{
+ struct ao_quaternion c;
+ struct ao_quaternion t;
+
+ ao_quaternion_multiply(&t, b, a);
+ ao_quaternion_conjugate(&c, b);
+ ao_quaternion_multiply(r, &t, &c);
+}
+
+/*
+ * Compute a rotation quaternion between two vectors
+ *
+ * cos(θ) + u * sin(θ)
+ *
+ * where θ is the angle between the two vectors and u
+ * is a unit vector axis of rotation
+ */
+
+static inline void ao_quaternion_vectors_to_rotation(struct ao_quaternion *r,
+ const struct ao_quaternion *a,
+ const struct ao_quaternion *b)
+{
+ /*
+ * The cross product will point orthogonally to the two
+ * vectors, forming our rotation axis. The length will be
+ * sin(θ), so these values are already multiplied by that.
+ */
+
+ float x = a->y * b->z - a->z * b->y;
+ float y = a->z * b->x - a->x * b->z;
+ float z = a->x * b->y - a->y * b->x;
+
+ float s_2 = x*x + y*y + z*z;
+ float s = sqrtf(s_2);
+
+ /* cos(θ) = a · b / (|a| |b|).
+ *
+ * a and b are both unit vectors, so the divisor is one
+ */
+ float c = a->x*b->x + a->y*b->y + a->z*b->z;
+
+ float c_half = sqrtf ((1 + c) / 2);
+ float s_half = sqrtf ((1 - c) / 2);
+
+ /*
+ * Divide out the sine factor from the
+ * cross product, then multiply in the
+ * half sine factor needed for the quaternion
+ */
+ float s_scale = s_half / s;
+
+ r->x = x * s_scale;
+ r->y = y * s_scale;
+ r->z = z * s_scale;
+
+ r->r = c_half;
+
+ ao_quaternion_normalize(r, r);
+}
+
+static inline void ao_quaternion_init_vector(struct ao_quaternion *r,
+ float x, float y, float z)
+{
+ r->r = 0;
+ r->x = x;
+ r->y = y;
+ r->z = z;
+}
+
+static inline void ao_quaternion_init_rotation(struct ao_quaternion *r,
+ float x, float y, float z,
+ float s, float c)
+{
+ r->r = c;
+ r->x = s * x;
+ r->y = s * y;
+ r->z = s * z;
+}
+
+static inline void ao_quaternion_init_zero_rotation(struct ao_quaternion *r)
+{
+ r->r = 1;
+ r->x = r->y = r->z = 0;
+}
+
+/*
+ * The sincosf from newlib just calls sinf and cosf. This is a bit
+ * faster, if slightly less precise
+ */
+
+static inline void
+ao_sincosf(float a, float *s, float *c) {
+ float _s = sinf(a);
+ *s = _s;
+ *c = sqrtf(1 - _s*_s);
+}
+
+/*
+ * Initialize a quaternion from 1/2 euler rotation angles (in radians).
+ *
+ * Yes, it would be nicer if there were a faster way, but because we
+ * sample the gyros at only 100Hz, we end up getting angles too large
+ * to take advantage of sin(x) ≃ x.
+ *
+ * We might be able to use just a couple of elements of the sin taylor
+ * series though, instead of the whole sin function?
+ */
+
+static inline void ao_quaternion_init_half_euler(struct ao_quaternion *r,
+ float x, float y, float z)
+{
+ float s_x, c_x;
+ float s_y, c_y;
+ float s_z, c_z;
+
+ ao_sincosf(x, &s_x, &c_x);
+ ao_sincosf(y, &s_y, &c_y);
+ ao_sincosf(z, &s_z, &c_z);
+
+ r->r = c_x * c_y * c_z + s_x * s_y * s_z;
+ r->x = s_x * c_y * c_z - c_x * s_y * s_z;
+ r->y = c_x * s_y * c_z + s_x * c_y * s_z;
+ r->z = c_x * c_y * s_z - s_x * s_y * c_z;
+}
+
+#endif /* _AO_QUATERNION_H_ */
--- /dev/null
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+
+#define mid(time) ao_led_for(AO_LED_REPORT, time)
+#define pause(time) ao_delay(time)
+
+static void
+ao_report_digit(uint8_t digit) __reentrant
+{
+ if (!digit) {
+ mid(AO_MS_TO_TICKS(1000));
+ pause(AO_MS_TO_TICKS(300));
+ } else {
+ while (digit--) {
+ mid(AO_MS_TO_TICKS(300));
+ pause(AO_MS_TO_TICKS(300));
+ }
+ }
+ pause(AO_MS_TO_TICKS(1000));
+}
+
+void
+ao_report_altitude(void)
+{
+ __pdata alt_t agl = ao_max_height;
+ static __xdata uint8_t digits[11];
+ __pdata uint8_t ndigits, i;
+
+ if (agl < 0)
+ agl = 0;
+ ndigits = 0;
+ do {
+ digits[ndigits++] = agl % 10;
+ agl /= 10;
+ } while (agl);
+
+ i = ndigits;
+ do
+ ao_report_digit(digits[--i]);
+ while (i != 0);
+}
#include <ao_data.h>
#endif
+#if HAS_GYRO
+#include <ao_quaternion.h>
+#endif
+
/*
* Current sensor values
*/
__pdata gyro_t ao_sample_roll;
__pdata gyro_t ao_sample_pitch;
__pdata gyro_t ao_sample_yaw;
-__pdata angle_t ao_sample_angle;
-__pdata angle_t ao_sample_roll_angle;
+__pdata angle_t ao_sample_orient;
#endif
__data uint8_t ao_sample_data;
__pdata accel_t ao_ground_accel_along;
__pdata accel_t ao_ground_accel_across;
__pdata accel_t ao_ground_accel_through;
-__pdata gyro_t ao_ground_pitch;
-__pdata gyro_t ao_ground_yaw;
-__pdata gyro_t ao_ground_roll;
+__pdata int32_t ao_ground_pitch;
+__pdata int32_t ao_ground_yaw;
+__pdata int32_t ao_ground_roll;
#endif
static __pdata uint8_t ao_preflight; /* in preflight mode */
__pdata int32_t ao_sample_pitch_sum;
__pdata int32_t ao_sample_yaw_sum;
__pdata int32_t ao_sample_roll_sum;
+static struct ao_quaternion ao_rotation;
#endif
static void
ao_ground_accel_along = ao_sample_accel_along_sum >> 9;
ao_ground_accel_across = ao_sample_accel_across_sum >> 9;
ao_ground_accel_through = ao_sample_accel_through_sum >> 9;
- ao_ground_pitch = ao_sample_pitch_sum >> 9;
- ao_ground_yaw = ao_sample_yaw_sum >> 9;
- ao_ground_roll = ao_sample_roll_sum >> 9;
+ ao_ground_pitch = ao_sample_pitch_sum;
+ ao_ground_yaw = ao_sample_yaw_sum;
+ ao_ground_roll = ao_sample_roll_sum;
ao_sample_accel_along_sum = 0;
ao_sample_accel_across_sum = 0;
ao_sample_accel_through_sum = 0;
ao_sample_pitch_sum = 0;
ao_sample_yaw_sum = 0;
ao_sample_roll_sum = 0;
- ao_sample_angle = 0;
+ ao_sample_orient = 0;
+
+ struct ao_quaternion orient;
+
+ /* Take the pad IMU acceleration values and compute our current direction
+ */
+
+ ao_quaternion_init_vector(&orient,
+ (ao_ground_accel_across - ao_config.accel_zero_across),
+ (ao_ground_accel_through - ao_config.accel_zero_through),
+ (ao_ground_accel_along - ao_config.accel_zero_along));
+
+ ao_quaternion_normalize(&orient,
+ &orient);
+
+ /* Here's up */
+
+ struct ao_quaternion up = { .r = 0, .x = 0, .y = 0, .z = 1 };
+
+ if (ao_config.pad_orientation != AO_PAD_ORIENTATION_ANTENNA_UP)
+ up.z = -1;
+
+ /* Compute rotation to get from up to our current orientation, set
+ * that as the current rotation vector
+ */
+ ao_quaternion_vectors_to_rotation(&ao_rotation, &up, &orient);
#endif
nsamples = 0;
}
+#if HAS_GYRO
+
+#define TIME_DIV 200.0f
+
+static void
+ao_sample_rotate(void)
+{
+#ifdef AO_FLIGHT_TEST
+ float dt = (ao_sample_tick - ao_sample_prev_tick) / TIME_DIV;
+#else
+ static const float dt = 1/TIME_DIV;
+#endif
+ float x = ao_mpu6000_gyro((float) ((ao_sample_pitch << 9) - ao_ground_pitch) / 512.0f) * dt;
+ float y = ao_mpu6000_gyro((float) ((ao_sample_yaw << 9) - ao_ground_yaw) / 512.0f) * dt;
+ float z = ao_mpu6000_gyro((float) ((ao_sample_roll << 9) - ao_ground_roll) / 512.0f) * dt;
+ struct ao_quaternion rot;
+
+ ao_quaternion_init_half_euler(&rot, x, y, z);
+ ao_quaternion_multiply(&ao_rotation, &rot, &ao_rotation);
+
+ /* And normalize to make sure it remains a unit vector */
+ ao_quaternion_normalize(&ao_rotation, &ao_rotation);
+
+ /* Compute pitch angle from vertical by taking the pad
+ * orientation vector and rotating it by the current total
+ * rotation value. That will be a unit vector pointing along
+ * the airframe axis. The Z value will be the cosine of the
+ * change in the angle from vertical since boost.
+ *
+ * rot = ao_rotation * vertical * ao_rotation°
+ * rot = ao_rotation * (0,0,0,1) * ao_rotation°
+ * = ((a.z, a.y, -a.x, a.r) * (a.r, -a.x, -a.y, -a.z)) .z
+ *
+ * = (-a.z * -a.z) + (a.y * -a.y) - (-a.x * -a.x) + (a.r * a.r)
+ * = a.z² - a.y² - a.x² + a.r²
+ *
+ * rot = ao_rotation * (0, 0, 0, -1) * ao_rotation°
+ * = ((-a.z, -a.y, a.x, -a.r) * (a.r, -a.x, -a.y, -a.z)) .z
+ *
+ * = (a.z * -a.z) + (-a.y * -a.y) - (a.x * -a.x) + (-a.r * a.r)
+ * = -a.z² + a.y² + a.x² - a.r²
+ */
+
+ float rotz;
+ rotz = ao_rotation.z * ao_rotation.z - ao_rotation.y * ao_rotation.y - ao_rotation.x * ao_rotation.x + ao_rotation.r * ao_rotation.r;
+
+ ao_sample_orient = acosf(rotz) * (float) (180.0/M_PI);
+}
+#endif
+
static void
ao_sample_preflight(void)
{
ao_sample_preflight_update();
ao_kalman();
#if HAS_GYRO
- /* do quaternion stuff here... */
+ ao_sample_rotate();
#endif
}
+#ifdef AO_FLIGHT_TEST
+ ao_sample_prev_tick = ao_sample_tick;
+#endif
ao_sample_data = ao_data_ring_next(ao_sample_data);
}
return !ao_preflight;
ao_sample_pitch = 0;
ao_sample_yaw = 0;
ao_sample_roll = 0;
- ao_sample_angle = 0;
+ ao_sample_orient = 0;
#endif
ao_sample_data = ao_data_head;
ao_preflight = TRUE;
* for all further flight computations
*/
-#define GRAVITY 9.80665
-
/*
* Above this height, the baro sensor doesn't work
*/
extern __pdata accel_t ao_ground_accel_along;
extern __pdata accel_t ao_ground_accel_across;
extern __pdata accel_t ao_ground_accel_through;
-extern __pdata gyro_t ao_ground_pitch;
-extern __pdata gyro_t ao_ground_yaw;
-extern __pdata gyro_t ao_ground_roll;
+extern __pdata int32_t ao_ground_pitch; /* * 512 */
+extern __pdata int32_t ao_ground_yaw; /* * 512 */
+extern __pdata int32_t ao_ground_roll; /* * 512 */
+extern __pdata accel_t ao_sample_accel_along;
+extern __pdata accel_t ao_sample_accel_across;
+extern __pdata accel_t ao_sample_accel_through;
+extern __pdata gyro_t ao_sample_roll;
+extern __pdata gyro_t ao_sample_pitch;
+extern __pdata gyro_t ao_sample_yaw;
+extern __pdata angle_t ao_sample_orient;
#endif
void ao_sample_init(void);
extern __pdata int16_t ao_height; /* meters */
extern __pdata int16_t ao_speed; /* m/s * 16 */
extern __pdata int16_t ao_accel; /* m/s² * 16 */
-extern __pdata int16_t ao_max_height; /* max of ao_height */
-extern __pdata int16_t ao_avg_height; /* running average of height */
+extern __xdata int16_t ao_max_height; /* max of ao_height */
+extern __xdata int16_t ao_avg_height; /* running average of height */
extern __pdata int16_t ao_error_h;
extern __pdata int16_t ao_error_h_sq_avg;
#include <ao_task.h>
#ifndef AO_SAMPLE_PROFILE_LOW_PC
-#define AO_SAMPLE_PROFILE_LOW_PC 0x08000000
+#define AO_SAMPLE_PROFILE_LOW_PC 0x08002000
#endif
#ifndef AO_SAMPLE_PROFILE_HIGH_PC
-#define AO_SAMPLE_PROFILE_HIGH_PC (AO_SAMPLE_PROFILE_LOW_PC + 44 * 1024)
+#define AO_SAMPLE_PROFILE_HIGH_PC 0x0800f000
#endif
#ifndef AO_SAMPLE_PROFILE_SHIFT
ao_cmd_white();
if (!ao_match_word("DoIt"))
return;
- for (pos = 0; pos < ao_storage_config; pos += ao_storage_block)
+ for (pos = 0; pos < ao_storage_log_max; pos += ao_storage_block)
ao_storage_erase(pos);
}
/* Block size - device is erased in these units. At least 256 bytes */
extern __pdata ao_pos_t ao_storage_block;
+#ifndef USE_STORAGE_CONFIG
+#define USE_STORAGE_CONFIG 1
+#endif
+
+#if USE_STORAGE_CONFIG
/* Byte offset of config block. Will be ao_storage_block bytes long */
extern __pdata ao_pos_t ao_storage_config;
+#define ao_storage_log_max ao_storage_config
+#else
+#define ao_storage_log_max ao_storage_total
+#endif
+
/* Storage unit size - device reads and writes must be within blocks of this size. Usually 256 bytes. */
extern __pdata uint16_t ao_storage_unit;
-#define AO_STORAGE_ERASE_LOG (ao_storage_config + AO_CONFIG_MAX_SIZE)
-
/* Initialize above values. Can only be called once the OS is running */
void
ao_storage_setup(void) __reentrant;
ao_panic(3);
}
}
+ if (ao_task_alarm_tick != ao_list_first_entry(&alarm_queue, struct ao_task, alarm_queue)->alarm)
+ ao_panic(4);
}
#else
#define ao_task_validate_alarm_queue()
ao_list_for_each_entry(alarm, &alarm_queue, struct ao_task, alarm_queue) {
if ((int16_t) (alarm->alarm - task->alarm) >= 0) {
ao_list_insert(&task->alarm_queue, alarm->alarm_queue.prev);
+ ao_task_alarm_tick = ao_list_first_entry(&alarm_queue, struct ao_task, alarm_queue)->alarm;
ao_task_validate_alarm_queue();
return;
}
}
void
-ao_wakeup(__xdata void *wchan)
+ao_wakeup(__xdata void *wchan) __reentrant
{
#if HAS_TASK_QUEUE
struct ao_task *sleep, *next;
#endif
};
+#ifndef AO_NUM_TASKS
#define AO_NUM_TASKS 16 /* maximum number of tasks */
+#endif
+
#define AO_NO_TASK 0 /* no task id */
extern __xdata struct ao_task * __xdata ao_tasks[AO_NUM_TASKS];
/* Wake all tasks sleeping on wchan */
void
-ao_wakeup(__xdata void *wchan);
+ao_wakeup(__xdata void *wchan) __reentrant;
/* set an alarm to go off in 'delay' ticks */
void
#include "ao_log.h"
#include "ao_product.h"
+#ifndef HAS_RDF
+#define HAS_RDF 1
+#endif
+
static __pdata uint16_t ao_telemetry_interval;
static __pdata uint8_t ao_rdf = 0;
+
+#if HAS_RDF
static __pdata uint16_t ao_rdf_time;
+#endif
#if HAS_APRS
static __pdata uint16_t ao_aprs_time;
#define AO_SEND_MEGA 1
#endif
+#if defined (TELEMETRUM_V_2_0)
+#define AO_SEND_METRUM 1
+#endif
+
#if defined(TELEMETRUM_V_0_1) || defined(TELEMETRUM_V_0_2) || defined(TELEMETRUM_V_1_0) || defined(TELEMETRUM_V_1_1) || defined(TELEBALLOON_V_1_1) || defined(TELEMETRUM_V_1_2)
#define AO_TELEMETRY_SENSOR AO_TELEMETRY_SENSOR_TELEMETRUM
#endif
telemetry.generic.tick = packet->tick;
telemetry.generic.type = AO_TELEMETRY_MEGA_SENSOR;
+ telemetry.mega_sensor.orient = ao_sample_orient;
telemetry.mega_sensor.accel = ao_data_accel(packet);
telemetry.mega_sensor.pres = ao_data_pres(packet);
telemetry.mega_sensor.temp = ao_data_temp(packet);
}
#endif /* AO_SEND_MEGA */
+#ifdef AO_SEND_METRUM
+/* Send telemetrum sensor packet */
+static void
+ao_send_metrum_sensor(void)
+{
+ __xdata struct ao_data *packet = (__xdata struct ao_data *) &ao_data_ring[ao_data_ring_prev(ao_sample_data)];
+
+ telemetry.generic.tick = packet->tick;
+ telemetry.generic.type = AO_TELEMETRY_METRUM_SENSOR;
+
+ telemetry.metrum_sensor.state = ao_flight_state;
+ telemetry.metrum_sensor.accel = ao_data_accel(packet);
+ telemetry.metrum_sensor.pres = ao_data_pres(packet);
+ telemetry.metrum_sensor.temp = ao_data_temp(packet);
+
+ telemetry.metrum_sensor.acceleration = ao_accel;
+ telemetry.metrum_sensor.speed = ao_speed;
+ telemetry.metrum_sensor.height = ao_height;
+
+ telemetry.metrum_sensor.v_batt = packet->adc.v_batt;
+ telemetry.metrum_sensor.sense_a = packet->adc.sense_a;
+ telemetry.metrum_sensor.sense_m = packet->adc.sense_m;
+
+ ao_radio_send(&telemetry, sizeof (telemetry));
+}
+
+static __pdata int8_t ao_telemetry_metrum_data_max;
+static __pdata int8_t ao_telemetry_metrum_data_cur;
+
+/* Send telemetrum data packet */
+static void
+ao_send_metrum_data(void)
+{
+ if (--ao_telemetry_metrum_data_cur <= 0) {
+ __xdata struct ao_data *packet = (__xdata struct ao_data *) &ao_data_ring[ao_data_ring_prev(ao_sample_data)];
+ uint8_t i;
+
+ telemetry.generic.tick = packet->tick;
+ telemetry.generic.type = AO_TELEMETRY_METRUM_DATA;
+
+ telemetry.metrum_data.ground_pres = ao_ground_pres;
+ telemetry.metrum_data.ground_accel = ao_ground_accel;
+ telemetry.metrum_data.accel_plus_g = ao_config.accel_plus_g;
+ telemetry.metrum_data.accel_minus_g = ao_config.accel_minus_g;
+
+ ao_radio_send(&telemetry, sizeof (telemetry));
+ ao_telemetry_metrum_data_cur = ao_telemetry_metrum_data_max;
+ }
+}
+#endif /* AO_SEND_METRUM */
+
+#ifdef AO_SEND_MINI
+
+static void
+ao_send_mini(void)
+{
+ __xdata struct ao_data *packet = (__xdata struct ao_data *) &ao_data_ring[ao_data_ring_prev(ao_sample_data)];
+
+ telemetry.generic.tick = packet->tick;
+ telemetry.generic.type = AO_TELEMETRY_MINI;
+
+ telemetry.mini.state = ao_flight_state;
+
+ telemetry.mini.v_batt = packet->adc.v_batt;
+ telemetry.mini.sense_a = packet->adc.sense_a;
+ telemetry.mini.sense_m = packet->adc.sense_m;
+
+ telemetry.mini.pres = ao_data_pres(packet);
+ telemetry.mini.temp = ao_data_temp(packet);
+
+ telemetry.mini.acceleration = ao_accel;
+ telemetry.mini.speed = ao_speed;
+ telemetry.mini.height = ao_height;
+
+ telemetry.mini.ground_pres = ao_ground_pres;
+
+ ao_radio_send(&telemetry, sizeof (telemetry));
+}
+
+#endif /* AO_SEND_MINI */
+
#ifdef AO_SEND_ALL_BARO
static uint8_t ao_baro_sample;
{
telemetry.generic.type = AO_TELEMETRY_CONFIGURATION;
telemetry.configuration.device = AO_idProduct_NUMBER;
+#if HAS_LOG
telemetry.configuration.flight = ao_log_full() ? 0 : ao_flight_number;
+#else
+ telemetry.configuration.flight = ao_flight_number;
+#endif
telemetry.configuration.config_major = AO_CONFIG_MAJOR;
telemetry.configuration.config_minor = AO_CONFIG_MINOR;
telemetry.configuration.apogee_delay = ao_config.apogee_delay;
for (;;) {
while (ao_telemetry_interval == 0)
ao_sleep(&telemetry);
- time = ao_rdf_time = ao_time();
+ time = ao_time();
+#if HAS_RDF
+ ao_rdf_time = time;
+#endif
#if HAS_APRS
ao_aprs_time = time;
#endif
while (ao_telemetry_interval) {
-
#if HAS_APRS
if (!(ao_config.radio_enable & AO_RADIO_DISABLE_TELEMETRY))
#endif
#ifdef AO_SEND_ALL_BARO
ao_send_baro();
#endif
+
#if HAS_FLIGHT
-#ifdef AO_SEND_MEGA
+# ifdef AO_SEND_MEGA
ao_send_mega_sensor();
ao_send_mega_data();
-#else
+# endif
+# ifdef AO_SEND_METRUM
+ ao_send_metrum_sensor();
+ ao_send_metrum_data();
+# endif
+# ifdef AO_SEND_MINI
+ ao_send_mini();
+# endif
+# ifdef AO_TELEMETRY_SENSOR
ao_send_sensor();
-#endif
-#endif
+# endif
+#endif /* HAS_FLIGHT */
#if HAS_COMPANION
if (ao_companion_running)
#endif
}
#ifndef AO_SEND_ALL_BARO
+#if HAS_RDF
if (ao_rdf &&
#if HAS_APRS
!(ao_config.radio_enable & AO_RADIO_DISABLE_RDF) &&
-#endif
+#endif /* HAS_APRS */
(int16_t) (ao_time() - ao_rdf_time) >= 0)
{
#if HAS_IGNITE_REPORT
uint8_t c;
-#endif
+#endif /* HAS_IGNITE_REPORT */
ao_rdf_time = ao_time() + AO_RDF_INTERVAL_TICKS;
#if HAS_IGNITE_REPORT
if (ao_flight_state == ao_flight_pad && (c = ao_report_igniter()))
ao_radio_continuity(c);
else
-#endif
+#endif /* HAS_IGNITE_REPORT*/
ao_radio_rdf();
}
+#endif /* HAS_RDF */
#if HAS_APRS
if (ao_config.aprs_interval != 0 &&
(int16_t) (ao_time() - ao_aprs_time) >= 0)
ao_aprs_time = ao_time() + AO_SEC_TO_TICKS(ao_config.aprs_interval);
ao_aprs_send();
}
-#endif
-#endif
+#endif /* HAS_APRS */
+#endif /* !AO_SEND_ALL_BARO */
time += ao_telemetry_interval;
delay = time - ao_time();
if (delay > 0) {
cur++;
ao_telemetry_mega_data_cur = cur;
#endif
+#if AO_SEND_METRUM
+ ao_telemetry_metrum_data_max = AO_SEC_TO_TICKS(1) / interval;
+ if (ao_telemetry_metrum_data_max > cur)
+ cur++;
+ ao_telemetry_metrum_data_cur = cur;
+#endif
#if HAS_COMPANION
if (!ao_companion_setup.update_period)
ao_wakeup(&telemetry);
}
+#if HAS_RDF
void
ao_rdf_set(uint8_t rdf)
{
ao_rdf_time = ao_time() + AO_RDF_INTERVAL_TICKS;
}
}
+#endif
__xdata struct ao_task ao_telemetry_task;
uint16_t tick; /* 2 */
uint8_t type; /* 4 */
- uint8_t pad5; /* 5 */
+ uint8_t orient; /* 5 angle from vertical */
int16_t accel; /* 6 Z axis */
int32_t pres; /* 8 Pa * 10 */
};
+#define AO_TELEMETRY_METRUM_SENSOR 0x0A
+
+struct ao_telemetry_metrum_sensor {
+ uint16_t serial; /* 0 */
+ uint16_t tick; /* 2 */
+ uint8_t type; /* 4 */
+
+ uint8_t state; /* 5 flight state */
+ int16_t accel; /* 6 Z axis */
+
+ int32_t pres; /* 8 Pa * 10 */
+ int16_t temp; /* 12 °C * 100 */
+
+ int16_t acceleration; /* 14 m/s² * 16 */
+ int16_t speed; /* 16 m/s * 16 */
+ int16_t height; /* 18 m */
+
+ int16_t v_batt; /* 20 battery voltage */
+ int16_t sense_a; /* 22 apogee continuity sense */
+ int16_t sense_m; /* 24 main continuity sense */
+
+ uint8_t pad[6]; /* 26 */
+ /* 32 */
+};
+
+#define AO_TELEMETRY_METRUM_DATA 0x0B
+
+struct ao_telemetry_metrum_data {
+ uint16_t serial; /* 0 */
+ uint16_t tick; /* 2 */
+ uint8_t type; /* 4 */
+
+ int32_t ground_pres; /* 8 average pres on pad */
+ int16_t ground_accel; /* 12 average accel on pad */
+ int16_t accel_plus_g; /* 14 accel calibration at +1g */
+ int16_t accel_minus_g; /* 16 accel calibration at -1g */
+
+ uint8_t pad[14]; /* 18 */
+ /* 32 */
+};
+
+#define AO_TELEMETRY_MINI 0x10
+
+struct ao_telemetry_mini {
+ uint16_t serial; /* 0 */
+ uint16_t tick; /* 2 */
+ uint8_t type; /* 4 */
+
+ uint8_t state; /* 5 flight state */
+ int16_t v_batt; /* 6 battery voltage */
+ int16_t sense_a; /* 8 apogee continuity */
+ int16_t sense_m; /* 10 main continuity */
+
+ int32_t pres; /* 12 Pa * 10 */
+ int16_t temp; /* 16 °C * 100 */
+
+ int16_t acceleration; /* 18 m/s² * 16 */
+ int16_t speed; /* 20 m/s * 16 */
+ int16_t height; /* 22 m */
+
+ int32_t ground_pres; /* 24 average pres on pad */
+
+ int32_t pad28; /* 28 */
+ /* 32 */
+};
+
/* #define AO_SEND_ALL_BARO */
#define AO_TELEMETRY_BARO 0x80
struct ao_telemetry_companion companion;
struct ao_telemetry_mega_sensor mega_sensor;
struct ao_telemetry_mega_data mega_data;
+ struct ao_telemetry_metrum_sensor metrum_sensor;
+ struct ao_telemetry_metrum_data metrum_data;
+ struct ao_telemetry_mini mini;
struct ao_telemetry_baro baro;
};
#define AO_USB_INT_EP 1
#define AO_USB_INT_SIZE 8
+#ifndef AO_USB_OUT_EP
#define AO_USB_OUT_EP 4
#define AO_USB_IN_EP 5
+#endif
+
/*
* USB bulk packets can only come in 8, 16, 32 and 64
* byte sizes, so we'll use 64 for everything
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+/*
+ * 74HC165 driver.
+ * Reads a single byte from the shift register
+ */
+
+#include <ao.h>
+#include <ao_74hc165.h>
+
+uint8_t
+ao_74hc165_read(void)
+{
+ static __xdata state;
+ ao_spi_get(AO_74HC165_SPI_BUS);
+ ao_spi_set_speed(AO_74HC165_SPI_BUS, AO_SPI_SPEED_FAST);
+ AO_74HC165_CS = 1;
+ ao_spi_recv(&state, 1, AO_74HC165_SPI_BUS);
+ AO_74HC165_CS = 0;
+ ao_spi_put(AO_74HC165_SPI_BUS);
+ return state;
+}
+
+static void
+ao_74hc165_cmd(void)
+{
+ uint8_t v;
+
+ v = ao_74hc165_read();
+ printf ("Switches: 0x%02x\n", v);
+}
+
+static const struct ao_cmds ao_74hc165_cmds[] = {
+ { ao_74hc165_cmd, "L\0Show 74hc165" },
+ { 0, NULL }
+};
+
+void
+ao_74hc165_init(void)
+{
+ ao_enable_output(AO_74HC165_CS_PORT, AO_74HC165_CS_PIN, AO_74HC165_CS, 0);
+ ao_cmd_register(&ao_74hc165_cmds[0]);
+}
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_74HC165_H_
+#define _AO_74HC165_H_
+
+uint8_t
+ao_74hc165_read(void);
+
+void
+ao_74hc165_init(void);
+
+#endif /* _AO_74HC165_H_ */
#include <ao.h>
#include <ao_button.h>
#include <ao_exti.h>
+#include <ao_debounce.h>
#if AO_EVENT
#include <ao_event.h>
#define ao_button_queue(b,v) ao_event_put_isr(AO_EVENT_BUTTON, b, v)
#define ao_button_queue(b,v)
#endif
-static uint8_t ao_button[AO_BUTTON_COUNT];
-static AO_TICK_TYPE ao_button_time[AO_BUTTON_COUNT];
+#define AO_BUTTON_DEBOUNCE_HOLD 10
-#define AO_DEBOUNCE AO_MS_TO_TICKS(20)
+static struct ao_debounce ao_button_debounce[AO_BUTTON_COUNT];
#define port(q) AO_BUTTON_ ## q ## _PORT
#define bit(q) AO_BUTTON_ ## q
#define pin(q) AO_BUTTON_ ## q ## _PIN
-static void
-ao_button_do(uint8_t b, uint8_t v)
-{
- /* Debounce */
- if ((AO_TICK_SIGNED) (ao_tick_count - ao_button_time[b]) < AO_DEBOUNCE)
- return;
-
- /* pins are inverted */
- v = !v;
- if (ao_button[b] != v) {
- ao_button[b] = v;
- ao_button_time[b] = ao_tick_count;
- ao_button_queue(b, v);
- ao_wakeup(&ao_button[b]);
- }
-}
+/* pins are inverted */
+#define ao_button_value(b) !ao_gpio_get(port(b), bit(b), pin(b))
-#define ao_button_update(b) ao_button_do(b, ao_gpio_get(port(b), bit(b), pin(b)))
-
-static void
-ao_button_isr(void)
+static uint8_t
+_ao_button_get(struct ao_debounce *debounce)
{
+ uint8_t b = debounce - ao_button_debounce;
+
+ switch (b) {
#if AO_BUTTON_COUNT > 0
- ao_button_update(0);
+ case 0: return ao_button_value(0);
#endif
#if AO_BUTTON_COUNT > 1
- ao_button_update(1);
+ case 1: return ao_button_value(1);
#endif
#if AO_BUTTON_COUNT > 2
- ao_button_update(2);
+ case 2: return ao_button_value(2);
#endif
#if AO_BUTTON_COUNT > 3
- ao_button_update(3);
+ case 3: return ao_button_value(3);
#endif
#if AO_BUTTON_COUNT > 4
- ao_button_update(4);
+ case 4: return ao_button_value(4);
#endif
+ }
+}
+
+static void
+_ao_button_set(struct ao_debounce *debounce, uint8_t value)
+{
+ uint8_t b = debounce - ao_button_debounce;
+
+ ao_button_queue(b, value);
+}
+
+
+#define ao_button_update(b) ao_button_do(b, ao_gpio_get(port(b), bit(b), pin(b)))
+
+static void
+ao_button_debounce_init(struct ao_debounce *debounce) {
+ ao_debounce_config(debounce,
+ _ao_button_get,
+ _ao_button_set,
+ AO_BUTTON_DEBOUNCE_HOLD);
+}
+
+static void
+ao_button_isr(void)
+{
+ uint8_t b;
+
+ for (b = 0; b < AO_BUTTON_COUNT; b++)
+ _ao_debounce_start(&ao_button_debounce[b]);
}
#define init(b) do { \
+ ao_button_debounce_init(&ao_button_debounce[b]); \
ao_enable_port(port(b)); \
\
ao_exti_setup(port(b), bit(b), \
#if AO_BUTTON_COUNT > 1
init(1);
#endif
+#if AO_BUTTON_COUNT > 2
+ init(2);
+#endif
+#if AO_BUTTON_COUNT > 3
+ init(3);
+#endif
+#if AO_BUTTON_COUNT > 4
+ init(4);
+#endif
+ ao_debounce_init();
}
(0 << CC1120_PKT_CFG0_PKG_BIT_LEN) |
(0 << CC1120_PKT_CFG0_UART_MODE_EN) |
(0 << CC1120_PKT_CFG0_UART_SWAP_EN)),
+ CC1120_PREAMBLE_CFG1, ((CC1120_PREAMBLE_CFG1_NUM_PREAMBLE_4_BYTES << CC1120_PREAMBLE_CFG1_NUM_PREAMBLE) |
+ (CC1120_PREAMBLE_CFG1_PREAMBLE_WORD_AA << CC1120_PREAMBLE_CFG1_PREAMBLE_WORD)),
AO_CC1120_MARC_GPIO_IOCFG, CC1120_IOCFG_GPIO_CFG_MARC_MCU_WAKEUP,
};
(0 << CC1120_PKT_CFG0_PKG_BIT_LEN) |
(0 << CC1120_PKT_CFG0_UART_MODE_EN) |
(0 << CC1120_PKT_CFG0_UART_SWAP_EN)),
+ CC1120_PREAMBLE_CFG1, ((CC1120_PREAMBLE_CFG1_NUM_PREAMBLE_NONE << CC1120_PREAMBLE_CFG1_NUM_PREAMBLE) |
+ (CC1120_PREAMBLE_CFG1_PREAMBLE_WORD_AA << CC1120_PREAMBLE_CFG1_PREAMBLE_WORD)),
};
/*
(CC1120_PKT_CFG1_ADDR_CHECK_CFG_NONE << CC1120_PKT_CFG1_ADDR_CHECK_CFG) |
(CC1120_PKT_CFG1_CRC_CFG_DISABLED << CC1120_PKT_CFG1_CRC_CFG) |
(0 << CC1120_PKT_CFG1_APPEND_STATUS)),
+ CC1120_PREAMBLE_CFG1, ((CC1120_PREAMBLE_CFG1_NUM_PREAMBLE_NONE << CC1120_PREAMBLE_CFG1_NUM_PREAMBLE) |
+ (CC1120_PREAMBLE_CFG1_PREAMBLE_WORD_AA << CC1120_PREAMBLE_CFG1_PREAMBLE_WORD)),
+};
+
+/*
+ * For Test mode, we want an unmodulated carrier. To do that, we
+ * set the deviation to zero and enable a preamble so that the radio
+ * turns on before we send any data
+ */
+
+static const uint16_t test_setup[] = {
+ CC1120_DEVIATION_M, 0,
+ CC1120_MODCFG_DEV_E, ((CC1120_MODCFG_DEV_E_MODEM_MODE_NORMAL << CC1120_MODCFG_DEV_E_MODEM_MODE) |
+ (CC1120_MODCFG_DEV_E_MOD_FORMAT_2_GFSK << CC1120_MODCFG_DEV_E_MOD_FORMAT) |
+ (0 << CC1120_MODCFG_DEV_E_DEV_E)),
+ CC1120_DRATE2, ((APRS_DRATE_E << CC1120_DRATE2_DATARATE_E) |
+ (((APRS_DRATE_M >> 16) & CC1120_DRATE2_DATARATE_M_19_16_MASK) << CC1120_DRATE2_DATARATE_M_19_16)),
+ CC1120_DRATE1, ((APRS_DRATE_M >> 8) & 0xff),
+ CC1120_DRATE0, ((APRS_DRATE_M >> 0) & 0xff),
+ CC1120_PKT_CFG2, ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
+ (CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)),
+ CC1120_PKT_CFG1, ((0 << CC1120_PKT_CFG1_WHITE_DATA) |
+ (CC1120_PKT_CFG1_ADDR_CHECK_CFG_NONE << CC1120_PKT_CFG1_ADDR_CHECK_CFG) |
+ (CC1120_PKT_CFG1_CRC_CFG_DISABLED << CC1120_PKT_CFG1_CRC_CFG) |
+ (0 << CC1120_PKT_CFG1_APPEND_STATUS)),
+ CC1120_PREAMBLE_CFG1, ((CC1120_PREAMBLE_CFG1_NUM_PREAMBLE_4_BYTES << CC1120_PREAMBLE_CFG1_NUM_PREAMBLE) |
+ (CC1120_PREAMBLE_CFG1_PREAMBLE_WORD_AA << CC1120_PREAMBLE_CFG1_PREAMBLE_WORD)),
};
#define AO_PKT_CFG0_INFINITE ((0 << CC1120_PKT_CFG0_RESERVED7) | \
#define AO_RADIO_MODE_BITS_PACKET_RX 16
#define AO_RADIO_MODE_BITS_RDF 32
#define AO_RADIO_MODE_BITS_APRS 64
-#define AO_RADIO_MODE_BITS_INFINITE 128
-#define AO_RADIO_MODE_BITS_FIXED 256
+#define AO_RADIO_MODE_BITS_TEST 128
+#define AO_RADIO_MODE_BITS_INFINITE 256
+#define AO_RADIO_MODE_BITS_FIXED 512
#define AO_RADIO_MODE_NONE 0
#define AO_RADIO_MODE_PACKET_TX_BUF (AO_RADIO_MODE_BITS_PACKET | AO_RADIO_MODE_BITS_PACKET_TX | AO_RADIO_MODE_BITS_TX_BUF)
#define AO_RADIO_MODE_APRS_BUF (AO_RADIO_MODE_BITS_APRS | AO_RADIO_MODE_BITS_INFINITE | AO_RADIO_MODE_BITS_TX_BUF)
#define AO_RADIO_MODE_APRS_LAST_BUF (AO_RADIO_MODE_BITS_APRS | AO_RADIO_MODE_BITS_FIXED | AO_RADIO_MODE_BITS_TX_BUF)
#define AO_RADIO_MODE_APRS_FINISH (AO_RADIO_MODE_BITS_APRS | AO_RADIO_MODE_BITS_FIXED | AO_RADIO_MODE_BITS_TX_FINISH)
+#define AO_RADIO_MODE_TEST (AO_RADIO_MODE_BITS_TEST | AO_RADIO_MODE_BITS_INFINITE | AO_RADIO_MODE_BITS_TX_BUF)
static void
ao_radio_set_mode(uint16_t new_mode)
for (i = 0; i < sizeof (aprs_setup) / sizeof (aprs_setup[0]); i += 2)
ao_radio_reg_write(aprs_setup[i], aprs_setup[i+1]);
+ if (changes & AO_RADIO_MODE_BITS_TEST)
+ for (i = 0; i < sizeof (test_setup) / sizeof (test_setup[0]); i += 2)
+ ao_radio_reg_write(test_setup[i], test_setup[i+1]);
+
if (changes & AO_RADIO_MODE_BITS_INFINITE)
ao_radio_reg_write(CC1120_PKT_CFG0, AO_PKT_CFG0_INFINITE);
ao_packet_slave_stop();
#endif
ao_radio_get(0xff);
+ ao_radio_set_mode(AO_RADIO_MODE_TEST);
ao_radio_strobe(CC1120_STX);
#if CC1120_TRACE
{ int t;
#define CC1120_MARC_SPARE (CC1120_EXTENDED_BIT | 0x03)
#define CC1120_ECG_CFG (CC1120_EXTENDED_BIT | 0x04)
#define CC1120_SOFT_TX_DATA_CFG (CC1120_EXTENDED_BIT | 0x05)
+#define CC1120_SOFT_TX_DATA_CFG_SYMBOL_MAP_CFG 5
+#define CC1120_SOFT_TX_DATA_CFG_SOFT_TX_DATA_EN 0
#define CC1120_EXT_CTRL (CC1120_EXTENDED_BIT | 0x06)
#define CC1120_RCCAL_FINE (CC1120_EXTENDED_BIT | 0x07)
#define CC1120_RCCAL_COARSE (CC1120_EXTENDED_BIT | 0x08)
uint8_t state = ao_radio_strobe(CC115L_SIDLE);
if ((state >> CC115L_STATUS_STATE) == CC115L_STATUS_STATE_IDLE)
break;
+ if ((state >> CC115L_STATUS_STATE) == CC115L_STATUS_STATE_TX_FIFO_UNDERFLOW)
+ ao_radio_strobe(CC115L_SFTX);
}
/* Flush any pending TX bytes */
ao_radio_strobe(CC115L_SFTX);
ao_config_get();
+ ao_radio_strobe(CC115L_SCAL);
+
ao_radio_configured = 1;
}
ao_radio_get(void)
{
static uint32_t last_radio_setting;
- static uint8_t last_power_setting;
ao_mutex_get(&ao_radio_mutex);
if (!ao_radio_configured)
ao_radio_reg_write(CC115L_FREQ0, ao_config.radio_setting);
last_radio_setting = ao_config.radio_setting;
}
- if (ao_config.radio_power != last_power_setting) {
- ao_radio_reg_write(CC115L_PA, ao_config.radio_power);
- last_power_setting = ao_config.radio_power;
- }
}
static void
ao_wakeup(&ao_radio_wake);
}
+#define POWER_STEP 0x08
+
+static void
+ao_radio_stx(void)
+{
+ uint8_t power;
+ ao_radio_pa_on();
+ ao_radio_reg_write(CC115L_PA, 0);
+ ao_radio_strobe(CC115L_STX);
+ for (power = POWER_STEP; power < ao_config.radio_power; power += POWER_STEP)
+ ao_radio_reg_write(CC115L_PA, power);
+ ao_radio_reg_write(CC115L_PA, ao_config.radio_power);
+}
+
static void
ao_radio_test_cmd(void)
{
ao_packet_slave_stop();
#endif
ao_radio_get();
- ao_radio_set_len(0xff);
- ao_radio_set_mode(AO_RADIO_MODE_RDF|AO_RADIO_MODE_BITS_FIXED);
ao_radio_strobe(CC115L_SFTX);
- ao_radio_pa_on();
- ao_radio_strobe(CC115L_STX);
+ ao_radio_set_len(0xff);
+ ao_radio_set_mode(AO_RADIO_MODE_RDF);
+ ao_radio_stx();
radio_on = 1;
}
if (mode == 3) {
}
}
+#if CC115L_TRACE
static inline int16_t
ao_radio_gpio_bits(void)
{
return AO_CC115L_DONE_INT_PORT->idr & ((1 << AO_CC115L_FIFO_INT_PIN) |
(1 << AO_CC115L_DONE_INT_PIN));
}
+#endif
static void
ao_radio_wait_fifo(void)
uint8_t fifo_space;
fifo_space = CC115L_FIFO_SIZE;
+ ao_radio_abort = 0;
+
+ ao_radio_strobe(CC115L_SFTX);
+
ao_radio_done = 0;
ao_radio_fifo = 0;
while (!done) {
ao_exti_enable(AO_CC115L_DONE_INT_PORT, AO_CC115L_DONE_INT_PIN);
if (!started) {
- ao_radio_pa_on();
- ao_radio_strobe(CC115L_STX);
+ ao_radio_stx();
started = 1;
}
}
#define ao_event_queue_empty() (ao_event_queue_insert == ao_event_queue_remove)
#define ao_event_queue_full() (ao_event_queue_next(ao_event_queue_insert) == ao_event_queue_remove)
-/*
- * Whether a sequence of events from the same device should be collapsed
- */
-#define ao_event_can_collapse(type) ((type) == AO_EVENT_QUADRATURE)
-
struct ao_event ao_event_queue[AO_EVENT_QUEUE];
uint8_t ao_event_queue_insert;
uint8_t ao_event_queue_remove;
/* called with interrupts disabled */
void
-ao_event_put_isr(uint8_t type, uint8_t unit, uint32_t value)
+ao_event_put_isr(uint8_t type, uint8_t unit, int32_t value)
{
if (!ao_event_queue_full()) {
-
- if (ao_event_can_collapse(type) && !ao_event_queue_empty()) {
- uint8_t prev = ao_event_queue_prev(ao_event_queue_insert);
-
- if (ao_event_queue[prev].type == type &&
- ao_event_queue[prev].unit == unit)
- ao_event_queue_insert = prev;
- }
ao_event_queue[ao_event_queue_insert] = (struct ao_event) {
.type = type,
.unit = unit,
}
void
-ao_event_put(uint8_t type, uint8_t unit, uint32_t value)
+ao_event_put(uint8_t type, uint8_t unit, int32_t value)
{
ao_arch_critical(ao_event_put_isr(type, unit, value););
}
uint8_t type;
uint8_t unit;
uint16_t tick;
- uint32_t value;
+ int32_t value;
};
uint8_t
ao_event_get(struct ao_event *ev);
void
-ao_event_put_isr(uint8_t type, uint8_t unit, uint32_t value);
+ao_event_put_isr(uint8_t type, uint8_t unit, int32_t value);
void
-ao_event_put(uint8_t type, uint8_t unit, uint32_t value);
+ao_event_put(uint8_t type, uint8_t unit, int32_t value);
#endif /* _AO_EVENT_H_ */
#include "ao.h"
#endif
+__xdata uint8_t ao_gps_new;
__xdata uint8_t ao_gps_mutex;
__pdata uint16_t ao_gps_tick;
__xdata struct ao_telemetry_location ao_gps_data;
else
ao_gps_data.v_error = ao_sirf_data.v_error / 100;
#endif
+ ao_gps_new |= AO_GPS_NEW_DATA;
ao_mutex_put(&ao_gps_mutex);
- ao_wakeup(&ao_gps_data);
+ ao_wakeup(&ao_gps_new);
break;
case 4:
ao_mutex_get(&ao_gps_mutex);
ao_gps_tracking_data.sats[i].svid = ao_sirf_tracker_data.sats[i].svid;
ao_gps_tracking_data.sats[i].c_n_1 = ao_sirf_tracker_data.sats[i].c_n_1;
}
+ ao_gps_new |= AO_GPS_NEW_TRACKING;
ao_mutex_put(&ao_gps_mutex);
- ao_wakeup(&ao_gps_tracking_data);
+ ao_wakeup(&ao_gps_new);
break;
}
}
#define ao_gps_set_speed ao_serial1_set_speed
#endif
+__xdata uint8_t ao_gps_new;
__xdata uint8_t ao_gps_mutex;
static __data char ao_gps_char;
static __data uint8_t ao_gps_cksum;
if (!ao_gps_error) {
ao_mutex_get(&ao_gps_mutex);
+ ao_gps_new |= AO_GPS_NEW_DATA;
ao_gps_tick = ao_gps_next_tick;
ao_xmemcpy(&ao_gps_data, PDATA_TO_XDATA(&ao_gps_next), sizeof (ao_gps_data));
ao_mutex_put(&ao_gps_mutex);
- ao_wakeup(&ao_gps_data);
+ ao_wakeup(&ao_gps_new);
}
}
ao_gps_tracking_next.channels = 0;
else if (done) {
ao_mutex_get(&ao_gps_mutex);
+ ao_gps_new |= AO_GPS_NEW_TRACKING;
ao_xmemcpy(&ao_gps_tracking_data, PDATA_TO_XDATA(&ao_gps_tracking_next), sizeof(ao_gps_tracking_data));
ao_mutex_put(&ao_gps_mutex);
- ao_wakeup(&ao_gps_tracking_data);
+ ao_wakeup(&ao_gps_new);
}
}
__xdata struct ao_task ao_gps_task;
-static void
-gps_dump(void) __reentrant
-{
- uint8_t i;
- ao_mutex_get(&ao_gps_mutex);
- printf ("Date: %02d/%02d/%02d\n", ao_gps_data.year, ao_gps_data.month, ao_gps_data.day);
- printf ("Time: %02d:%02d:%02d\n", ao_gps_data.hour, ao_gps_data.minute, ao_gps_data.second);
- printf ("Lat/Lon: %ld %ld\n", (long) ao_gps_data.latitude, (long) ao_gps_data.longitude);
- printf ("Alt: %d\n", ao_gps_data.altitude);
- printf ("Flags: 0x%x\n", ao_gps_data.flags);
- printf ("Sats: %d", ao_gps_tracking_data.channels);
- for (i = 0; i < ao_gps_tracking_data.channels; i++)
- printf (" %d %d",
- ao_gps_tracking_data.sats[i].svid,
- ao_gps_tracking_data.sats[i].c_n_1);
- printf ("\ndone\n");
- ao_mutex_put(&ao_gps_mutex);
-}
-
static __code uint8_t ao_gps_115200[] = {
SKYTRAQ_MSG_3(5,0,5,0) /* Set to 115200 baud */
};
}
__code struct ao_cmds ao_gps_cmds[] = {
- { gps_dump, "g\0Display GPS" },
+ { ao_gps_show, "g\0Display GPS" },
{ gps_update, "U\0Update GPS firmware" },
{ 0, NULL },
};
#include "ao_gps_ublox.h"
+#define AO_UBLOX_DEBUG 0
+
+#include <stdarg.h>
+
+__xdata uint8_t ao_gps_new;
__xdata uint8_t ao_gps_mutex;
__pdata uint16_t ao_gps_tick;
__xdata struct ao_telemetry_location ao_gps_data;
__xdata struct ao_telemetry_satellite ao_gps_tracking_data;
-static const char ao_gps_set_nmea[] = "\r\n$PUBX,41,1,3,1,57600,0*2d\r\n";
+#undef AO_SERIAL_SPEED_UBLOX
-const char ao_gps_config[] = {
+#ifndef AO_SERIAL_SPEED_UBLOX
+#define AO_SERIAL_SPEED_UBLOX AO_SERIAL_SPEED_9600
+#endif
-};
+#if AO_SERIAL_SPEED_UBLOX == AO_SERIAL_SPEED_57600
+#define SERIAL_SPEED_STRING "57600"
+#define SERIAL_SPEED_CHECKSUM "2d"
+#endif
+#if AO_SERIAL_SPEED_UBLOX == AO_SERIAL_SPEED_19200
+#define SERIAL_SPEED_STRING "19200"
+#define SERIAL_SPEED_CHECKSUM "23"
+#endif
+#if AO_SERIAL_SPEED_UBLOX == AO_SERIAL_SPEED_9600
+#define SERIAL_SPEED_STRING "9600"
+#define SERIAL_SPEED_CHECKSUM "16"
+#endif
+
+static const char ao_gps_set_nmea[] =
+ "\r\n$PUBX,41,1,3,1," SERIAL_SPEED_STRING ",0*" SERIAL_SPEED_CHECKSUM "\r\n";
struct ao_ublox_cksum {
uint8_t a, b;
static __pdata struct ao_ublox_cksum ao_ublox_cksum;
static __pdata uint16_t ao_ublox_len;
-#ifndef ao_ublox_getchar
-#define ao_ublox_getchar ao_serial1_getchar
-#define ao_ublox_putchar ao_serial1_putchar
-#define ao_ublox_set_speed ao_serial1_set_speed
+#if AO_UBLOX_DEBUG
+
+static uint8_t ao_gps_dbg_enable;
+
+#define DBG_PROTO 1
+#define DBG_CHAR 2
+#define DBG_INIT 4
+
+static void ao_gps_dbg(int level, char *format, ...) {
+ va_list a;
+
+ if (level & ao_gps_dbg_enable) {
+ va_start(a, format);
+ vprintf(format, a);
+ va_end(a);
+ flush();
+ }
+}
+
+#else
+#define ao_gps_dbg(fmt, ...)
#endif
-#define ao_ublox_byte() ((uint8_t) ao_ublox_getchar())
+static inline uint8_t ao_ublox_byte(void) {
+ uint8_t c = (uint8_t) ao_gps_getchar();
+ ao_gps_dbg(DBG_CHAR, " %02x", c);
+ return c;
+}
static inline void add_cksum(struct ao_ublox_cksum *cksum, uint8_t c)
{
static void ao_ublox_put_u8(uint8_t c)
{
add_cksum(&ao_ublox_cksum, c);
- ao_ublox_putchar(c);
+ ao_gps_dbg(DBG_CHAR, " (%02x)", c);
+ ao_gps_putchar(c);
}
static void ao_ublox_put_i8(int8_t c)
break;
}
}
+ ao_gps_dbg(DBG_PROTO, "\n");
}
/*
{
uint8_t nsat;
nav_svinfo_nsat = 0;
+
ao_ublox_parse(&nav_svinfo, nav_svinfo_packet);
for (nsat = 0; nsat < nav_svinfo.num_ch && ao_ublox_len >= 12; nsat++) {
if (nsat < NAV_SVINFO_MAX_SAT) {
ublox_discard(12);
}
}
+#if AO_UBLOX_DEBUG
+ ao_gps_dbg(DBG_PROTO, "svinfo num_ch %d flags %02x\n", nav_svinfo.num_ch, nav_svinfo.flags);
+ for (nsat = 0; nsat < nav_svinfo.num_ch; nsat++)
+ ao_gps_dbg(DBG_PROTO, "\t%d: chn %d svid %d flags %02x quality %d cno %d\n",
+ nsat,
+ nav_svinfo_sat[nsat].chn,
+ nav_svinfo_sat[nsat].svid,
+ nav_svinfo_sat[nsat].flags,
+ nav_svinfo_sat[nsat].quality,
+ nav_svinfo_sat[nsat].cno);
+#endif
}
/*
*/
static void
-ao_gps_setup(void)
+ao_gps_delay(void)
{
- uint8_t i, k;
- ao_ublox_set_speed(AO_SERIAL_SPEED_9600);
+ uint8_t i;
/*
* A bunch of nulls so the start bit
* is clear
*/
+
for (i = 0; i < 64; i++)
- ao_ublox_putchar(0x00);
+ ao_gps_putchar(0x00);
+}
+
+static void
+ao_gps_setup(void)
+{
+ uint8_t i, k;
+
+ ao_delay(AO_SEC_TO_TICKS(3));
+
+ ao_gps_dbg(DBG_INIT, "Set speed 9600\n");
+ ao_gps_set_speed(AO_SERIAL_SPEED_9600);
/*
* Send the baud-rate setting and protocol-setting
* command three times
*/
- for (k = 0; k < 3; k++)
+ for (k = 0; k < 3; k++) {
+ ao_gps_delay();
+
+ ao_gps_dbg(DBG_INIT, "Send initial setting\n");
for (i = 0; i < sizeof (ao_gps_set_nmea); i++)
- ao_ublox_putchar(ao_gps_set_nmea[i]);
+ ao_gps_putchar(ao_gps_set_nmea[i]);
+ }
+
+ ao_gps_delay();
+#if AO_SERIAL_SPEED_UBLOX != AO_SERIAL_SPEED_9600
+ ao_gps_dbg(DBG_INIT, "Set speed high\n");
/*
* Increase the baud rate
*/
- ao_ublox_set_speed(AO_SERIAL_SPEED_57600);
+ ao_gps_set_speed(AO_SERIAL_SPEED_UBLOX);
+#endif
- /*
- * Pad with nulls to give the chip
- * time to see the baud rate switch
- */
- for (i = 0; i < 64; i++)
- ao_ublox_putchar(0x00);
+ ao_gps_delay();
}
static void
ao_ublox_putstart(uint8_t class, uint8_t id, uint16_t len)
{
ao_ublox_init_cksum();
- ao_ublox_putchar(0xb5);
- ao_ublox_putchar(0x62);
+ ao_gps_putchar(0xb5);
+ ao_gps_putchar(0x62);
ao_ublox_put_u8(class);
ao_ublox_put_u8(id);
ao_ublox_put_u8(len);
static void
ao_ublox_putend(void)
{
- ao_ublox_putchar(ao_ublox_cksum.a);
- ao_ublox_putchar(ao_ublox_cksum.b);
+ ao_gps_putchar(ao_ublox_cksum.a);
+ ao_gps_putchar(ao_ublox_cksum.b);
}
static void
/* Enable all of the messages we want */
for (i = 0; i < sizeof (ublox_enable_nav); i++)
ao_ublox_set_message_rate(UBLOX_NAV, ublox_enable_nav[i], 1);
-
+
ao_ublox_set_navigation_settings((1 << UBLOX_CFG_NAV5_MASK_DYN) | (1 << UBLOX_CFG_NAV5_MASK_FIXMODE),
UBLOX_CFG_NAV5_DYNMODEL_AIRBORNE_4G,
UBLOX_CFG_NAV5_FIXMODE_3D,
ao_ublox_len = header_byte();
ao_ublox_len |= header_byte() << 8;
+ ao_gps_dbg(DBG_PROTO, "class %02x id %02x len %d\n", class, id, ao_ublox_len);
+
if (ao_ublox_len > 1023)
continue;
break;
}
- if (ao_ublox_len != 0)
+ if (ao_ublox_len != 0) {
+ ao_gps_dbg(DBG_PROTO, "len left %d\n", ao_ublox_len);
continue;
+ }
/* verify checksum and end sequence */
cksum.a = ao_ublox_byte();
continue;
switch (class) {
- case 0x01:
+ case UBLOX_NAV:
switch (id) {
- case 0x21:
+ case UBLOX_NAV_TIMEUTC:
ao_mutex_get(&ao_gps_mutex);
ao_gps_tick = ao_time();
}
if (nav_timeutc.valid & (1 << NAV_TIMEUTC_VALID_UTC))
ao_gps_data.flags |= AO_GPS_DATE_VALID;
-
+
ao_gps_data.altitude = nav_posllh.alt_msl / 1000;
ao_gps_data.latitude = nav_posllh.lat;
ao_gps_data.longitude = nav_posllh.lon;
ao_gps_data.ground_speed = nav_velned.g_speed;
ao_gps_data.climb_rate = -nav_velned.vel_d;
ao_gps_data.course = nav_velned.heading / 200000;
-
+
ao_gps_tracking_data.channels = 0;
struct ao_telemetry_satellite_info *dst = &ao_gps_tracking_data.sats[0];
}
ao_mutex_put(&ao_gps_mutex);
- ao_wakeup(&ao_gps_data);
- ao_wakeup(&ao_gps_tracking_data);
+ ao_gps_new = AO_GPS_NEW_DATA | AO_GPS_NEW_TRACKING;
+ ao_wakeup(&ao_gps_new);
break;
}
break;
}
}
+#if AO_UBLOX_DEBUG
+static void ao_gps_option(void)
+{
+ ao_cmd_hex();
+ if (ao_cmd_status != ao_cmd_success) {
+ ao_cmd_status = ao_cmd_success;
+ ao_gps_show();
+ } else {
+ ao_gps_dbg_enable = ao_cmd_lex_i;
+ printf ("gps debug set to %d\n", ao_gps_dbg_enable);
+ }
+}
+#else
+#define ao_gps_option ao_gps_show
+#endif
+
+__code struct ao_cmds ao_gps_cmds[] = {
+ { ao_gps_option, "g\0Display GPS" },
+ { 0, NULL },
+};
+
__xdata struct ao_task ao_gps_task;
void
ao_gps_init(void)
{
+ ao_cmd_register(&ao_gps_cmds[0]);
ao_add_task(&ao_gps_task, ao_gps, "gps");
}
#if M25_MAX_CHIPS > 1
static uint8_t ao_m25_size[M25_MAX_CHIPS]; /* number of sectors in each chip */
-static uint8_t ao_m25_pin[M25_MAX_CHIPS]; /* chip select pin for each chip */
+static ao_port_t ao_m25_pin[M25_MAX_CHIPS]; /* chip select pin for each chip */
static uint8_t ao_m25_numchips; /* number of chips detected */
#endif
static uint8_t ao_m25_total; /* total sectors available */
-static uint8_t ao_m25_wip; /* write in progress */
+static ao_port_t ao_m25_wip; /* write in progress */
static __xdata uint8_t ao_m25_mutex;
* Block until the specified chip is done writing
*/
static void
-ao_m25_wait_wip(uint8_t cs)
+ao_m25_wait_wip(ao_port_t cs)
{
if (ao_m25_wip & cs) {
M25_SELECT(cs);
* so that future operations will block until the WIP bit goes off
*/
static void
-ao_m25_write_enable(uint8_t cs)
+ao_m25_write_enable(ao_port_t cs)
{
M25_SELECT(cs);
ao_m25_instruction[0] = M25_WREN;
* Returns the number of 64kB sectors
*/
static uint8_t
-ao_m25_read_capacity(uint8_t cs)
+ao_m25_read_capacity(ao_port_t cs)
{
uint8_t capacity;
M25_SELECT(cs);
return 1 << (capacity - 0x10);
}
-static uint8_t
+static ao_port_t
ao_m25_set_address(uint32_t pos)
{
- uint8_t chip;
+ ao_port_t mask;
#if M25_MAX_CHIPS > 1
uint8_t size;
+ uint8_t chip;
for (chip = 0; chip < ao_m25_numchips; chip++) {
size = ao_m25_size[chip];
if (chip == ao_m25_numchips)
return 0xff;
- chip = ao_m25_pin[chip];
+ mask = ao_m25_pin[chip];
#else
- chip = AO_M25_SPI_CS_MASK;
+ mask = AO_M25_SPI_CS_MASK;
#endif
- ao_m25_wait_wip(chip);
+ ao_m25_wait_wip(mask);
ao_m25_instruction[1] = pos >> 16;
ao_m25_instruction[2] = pos >> 8;
ao_m25_instruction[3] = pos;
- return chip;
+ return mask;
}
/*
uint8_t
ao_storage_erase(uint32_t pos) __reentrant
{
- uint8_t cs;
+ ao_port_t cs;
if (pos >= ao_storage_total || pos + ao_storage_block > ao_storage_total)
return 0;
cs = ao_m25_set_address(pos);
- ao_m25_wait_wip(cs);
ao_m25_write_enable(cs);
ao_m25_instruction[0] = M25_SE;
uint8_t
ao_storage_device_write(uint32_t pos, __xdata void *d, uint16_t len) __reentrant
{
- uint8_t cs;
+ ao_port_t cs;
if (pos >= ao_storage_total || pos + len > ao_storage_total)
return 0;
uint8_t
ao_storage_device_read(uint32_t pos, __xdata void *d, uint16_t len) __reentrant
{
- uint8_t cs;
+ ao_port_t cs;
if (pos >= ao_storage_total || pos + len > ao_storage_total)
return 0;
ao_storage_device_info(void) __reentrant
{
#if M25_DEBUG
- uint8_t cs;
+ ao_port_t cs;
#endif
#if M25_MAX_CHIPS > 1
uint8_t chip;
ao_mma655x_reg_write(AO_MMA655X_AXISCFG,
AXISCFG_VALUE |
(1 << AO_MMA655X_AXISCFG_ST));
- for (i = 0; i < 10; i++) {
- a_st = ao_mma655x_value();
- printf ("SELF-TEST %2d = %6d\n", i, a_st);
- }
+ a_st = ao_mma655x_value();
stdefl = ao_mma655x_reg_read(AO_MMA655X_STDEFL);
(0 << AO_MMA655X_AXISCFG_ST));
a = ao_mma655x_value();
- for (i = 0; i < 10; i++) {
- a = ao_mma655x_value();
- printf("NORMAL %2d = %6d\n", i, a);
- }
-
ao_mma655x_reg_write(AO_MMA655X_DEVCFG,
DEVCFG_VALUE | (1 << AO_MMA655X_DEVCFG_ENDINIT));
s0 = ao_mma655x_reg_read(AO_MMA655X_SN0);
serial = lot & 0x1fff;
lot >>= 12;
pn = ao_mma655x_reg_read(AO_MMA655X_PN);
- printf ("MMA655X lot %d serial %d number %d\n", lot, serial, pn);
-
}
uint16_t ao_mma655x_current;
#include <ao_mpu6000.h>
#include <ao_exti.h>
+#if HAS_MPU6000
+
static uint8_t ao_mpu6000_wake;
static uint8_t ao_mpu6000_configured;
-#define ao_mpu6000_spi_get() ao_spi_get_bit(AO_MPU6000_SPI_CS_PORT, \
- AO_MPU6000_SPI_CS_PIN, \
- AO_MPU6000_SPI_CS, \
- AO_MPU6000_SPI_BUS, \
- AO_SPI_SPEED_1MHz)
+#ifndef AO_MPU6000_I2C_INDEX
+#define AO_MPU6000_SPI 1
+#else
+#define AO_MPU6000_SPI 0
+#endif
+
+#if AO_MPU6000_SPI
+
+#define ao_mpu6000_spi_get() ao_spi_get(AO_MPU6000_SPI_BUS, AO_SPI_SPEED_1MHz)
+#define ao_mpu6000_spi_put() ao_spi_put(AO_MPU6000_SPI_BUS)
+
+#define ao_mpu6000_spi_start() ao_spi_set_cs(AO_MPU6000_SPI_CS_PORT, \
+ (1 << AO_MPU6000_SPI_CS_PIN))
+
+#define ao_mpu6000_spi_end() ao_spi_clr_cs(AO_MPU6000_SPI_CS_PORT, \
+ (1 << AO_MPU6000_SPI_CS_PIN))
-#define ao_mpu6000_spi_put() ao_spi_put_bit(AO_MPU6000_SPI_CS_PORT, \
- AO_MPU6000_SPI_CS_PIN, \
- AO_MPU6000_SPI_CS, \
- AO_MPU6000_SPI_BUS)
+#endif
static void
-ao_mpu6000_reg_write(uint8_t addr, uint8_t value)
+_ao_mpu6000_reg_write(uint8_t addr, uint8_t value)
{
uint8_t d[2] = { addr, value };
-#ifdef AO_MPU6000_I2C_INDEX
+#if AO_MPU6000_SPI
+ ao_mpu6000_spi_start();
+ ao_spi_send(d, 2, AO_MPU6000_SPI_BUS);
+ ao_mpu6000_spi_end();
+#else
ao_i2c_get(AO_MPU6000_I2C_INDEX);
ao_i2c_start(AO_MPU6000_I2C_INDEX, MPU6000_ADDR_WRITE);
ao_i2c_send(d, 2, AO_MPU6000_I2C_INDEX, TRUE);
ao_i2c_put(AO_MPU6000_I2C_INDEX);
-#else
- ao_mpu6000_spi_get();
- ao_spi_send(d, 2, AO_MPU6000_SPI_BUS);
- ao_mpu6000_spi_put();
#endif
}
static void
-ao_mpu6000_read(uint8_t addr, void *data, uint8_t len)
+_ao_mpu6000_read(uint8_t addr, void *data, uint8_t len)
{
-#ifdef AO_MPU6000_I2C_INDEX
+#if AO_MPU6000_SPI
+ addr |= 0x80;
+ ao_mpu6000_spi_start();
+ ao_spi_send(&addr, 1, AO_MPU6000_SPI_BUS);
+ ao_spi_recv(data, len, AO_MPU6000_SPI_BUS);
+ ao_mpu6000_spi_end();
+#else
ao_i2c_get(AO_MPU6000_I2C_INDEX);
ao_i2c_start(AO_MPU6000_I2C_INDEX, MPU6000_ADDR_WRITE);
ao_i2c_send(&addr, 1, AO_MPU6000_I2C_INDEX, FALSE);
ao_i2c_start(AO_MPU6000_I2C_INDEX, MPU6000_ADDR_READ);
ao_i2c_recv(data, len, AO_MPU6000_I2C_INDEX, TRUE);
ao_i2c_put(AO_MPU6000_I2C_INDEX);
-#else
- addr |= 0x80;
- ao_mpu6000_spi_get();
- ao_spi_send(&addr, 1, AO_MPU6000_SPI_BUS);
- ao_spi_recv(data, len, AO_MPU6000_SPI_BUS);
- ao_mpu6000_spi_put();
#endif
}
static uint8_t
-ao_mpu6000_reg_read(uint8_t addr)
+_ao_mpu6000_reg_read(uint8_t addr)
{
uint8_t value;
-#ifdef AO_MPU6000_I2C_INDEX
+#if AO_MPU6000_SPI
+ addr |= 0x80;
+ ao_mpu6000_spi_start();
+ ao_spi_send(&addr, 1, AO_MPU6000_SPI_BUS);
+ ao_spi_recv(&value, 1, AO_MPU6000_SPI_BUS);
+ ao_mpu6000_spi_end();
+#else
ao_i2c_get(AO_MPU6000_I2C_INDEX);
ao_i2c_start(AO_MPU6000_I2C_INDEX, MPU6000_ADDR_WRITE);
ao_i2c_send(&addr, 1, AO_MPU6000_I2C_INDEX, FALSE);
ao_i2c_start(AO_MPU6000_I2C_INDEX, MPU6000_ADDR_READ);
ao_i2c_recv(&value, 1, AO_MPU6000_I2C_INDEX, TRUE);
ao_i2c_put(AO_MPU6000_I2C_INDEX);
-#else
- addr |= 0x80;
- ao_mpu6000_spi_get();
- ao_spi_send(&addr, 1, AO_MPU6000_SPI_BUS);
- ao_spi_recv(&value, 1, AO_MPU6000_SPI_BUS);
- ao_mpu6000_spi_put();
#endif
return value;
}
static void
-ao_mpu6000_sample(struct ao_mpu6000_sample *sample)
+_ao_mpu6000_sample(struct ao_mpu6000_sample *sample)
{
uint16_t *d = (uint16_t *) sample;
int i = sizeof (*sample) / 2;
- ao_mpu6000_read(MPU6000_ACCEL_XOUT_H, sample, sizeof (*sample));
+ _ao_mpu6000_read(MPU6000_ACCEL_XOUT_H, sample, sizeof (*sample));
#if __BYTE_ORDER == __LITTLE_ENDIAN
/* byte swap */
while (i--) {
#define G 981 /* in cm/s² */
+#if 0
static int16_t /* cm/s² */
ao_mpu6000_accel(int16_t v)
{
{
return (int16_t) ((v * (int32_t) 20000) / 32767);
}
+#endif
static uint8_t
ao_mpu6000_accel_check(int16_t normal, int16_t test, char *which)
{
int16_t diff = test - normal;
- if (diff < MPU6000_ST_ACCEL(16) / 2) {
+ if (diff < MPU6000_ST_ACCEL(16) / 4) {
return 1;
}
- if (diff > MPU6000_ST_ACCEL(16) * 2) {
+ if (diff > MPU6000_ST_ACCEL(16) * 4) {
return 1;
}
return 0;
if (diff < 0)
diff = -diff;
- if (diff < MPU6000_ST_GYRO(2000) / 2) {
+ if (diff < MPU6000_ST_GYRO(2000) / 4) {
return 1;
}
- if (diff > MPU6000_ST_GYRO(2000) * 2) {
+ if (diff > MPU6000_ST_GYRO(2000) * 4) {
return 1;
}
return 0;
}
static void
-ao_mpu6000_setup(void)
+_ao_mpu6000_wait_alive(void)
+{
+ uint8_t i;
+
+ /* Wait for the chip to wake up */
+ for (i = 0; i < 30; i++) {
+ ao_delay(AO_MS_TO_TICKS(100));
+ if (_ao_mpu6000_reg_read(MPU6000_WHO_AM_I) == 0x68)
+ break;
+ }
+ if (i == 30)
+ ao_panic(AO_PANIC_SELF_TEST_MPU6000);
+}
+
+#define ST_TRIES 10
+
+static void
+_ao_mpu6000_setup(void)
{
struct ao_mpu6000_sample normal_mode, test_mode;
- int errors =0;
+ int errors;
+ int st_tries;
if (ao_mpu6000_configured)
return;
+ _ao_mpu6000_wait_alive();
+
/* Reset the whole chip */
- ao_mpu6000_reg_write(MPU6000_PWR_MGMT_1,
- (1 << MPU6000_PWR_MGMT_1_DEVICE_RESET));
+ _ao_mpu6000_reg_write(MPU6000_PWR_MGMT_1,
+ (1 << MPU6000_PWR_MGMT_1_DEVICE_RESET));
/* Wait for it to reset. If we talk too quickly, it appears to get confused */
- ao_delay(AO_MS_TO_TICKS(100));
- /* Reset signal conditioning */
- ao_mpu6000_reg_write(MPU6000_USER_CONTROL,
- (0 << MPU6000_USER_CONTROL_FIFO_EN) |
- (0 << MPU6000_USER_CONTROL_I2C_MST_EN) |
- (0 << MPU6000_USER_CONTROL_I2C_IF_DIS) |
- (0 << MPU6000_USER_CONTROL_FIFO_RESET) |
- (0 << MPU6000_USER_CONTROL_I2C_MST_RESET) |
- (1 << MPU6000_USER_CONTROL_SIG_COND_RESET));
+ _ao_mpu6000_wait_alive();
- while (ao_mpu6000_reg_read(MPU6000_USER_CONTROL) & (1 << MPU6000_USER_CONTROL_SIG_COND_RESET))
- ao_yield();
+ /* Reset signal conditioning, disabling I2C on SPI systems */
+ _ao_mpu6000_reg_write(MPU6000_USER_CTRL,
+ (0 << MPU6000_USER_CTRL_FIFO_EN) |
+ (0 << MPU6000_USER_CTRL_I2C_MST_EN) |
+ (AO_MPU6000_SPI << MPU6000_USER_CTRL_I2C_IF_DIS) |
+ (0 << MPU6000_USER_CTRL_FIFO_RESET) |
+ (0 << MPU6000_USER_CTRL_I2C_MST_RESET) |
+ (1 << MPU6000_USER_CTRL_SIG_COND_RESET));
+
+ while (_ao_mpu6000_reg_read(MPU6000_USER_CTRL) & (1 << MPU6000_USER_CTRL_SIG_COND_RESET))
+ ao_delay(AO_MS_TO_TICKS(10));
/* Reset signal paths */
- ao_mpu6000_reg_write(MPU6000_SIGNAL_PATH_RESET,
- (1 << MPU6000_SIGNAL_PATH_RESET_GYRO_RESET) |
- (1 << MPU6000_SIGNAL_PATH_RESET_ACCEL_RESET) |
- (1 << MPU6000_SIGNAL_PATH_RESET_TEMP_RESET));
+ _ao_mpu6000_reg_write(MPU6000_SIGNAL_PATH_RESET,
+ (1 << MPU6000_SIGNAL_PATH_RESET_GYRO_RESET) |
+ (1 << MPU6000_SIGNAL_PATH_RESET_ACCEL_RESET) |
+ (1 << MPU6000_SIGNAL_PATH_RESET_TEMP_RESET));
- ao_mpu6000_reg_write(MPU6000_SIGNAL_PATH_RESET,
- (0 << MPU6000_SIGNAL_PATH_RESET_GYRO_RESET) |
- (0 << MPU6000_SIGNAL_PATH_RESET_ACCEL_RESET) |
- (0 << MPU6000_SIGNAL_PATH_RESET_TEMP_RESET));
+ _ao_mpu6000_reg_write(MPU6000_SIGNAL_PATH_RESET,
+ (0 << MPU6000_SIGNAL_PATH_RESET_GYRO_RESET) |
+ (0 << MPU6000_SIGNAL_PATH_RESET_ACCEL_RESET) |
+ (0 << MPU6000_SIGNAL_PATH_RESET_TEMP_RESET));
/* Select clocks, disable sleep */
- ao_mpu6000_reg_write(MPU6000_PWR_MGMT_1,
- (0 << MPU6000_PWR_MGMT_1_DEVICE_RESET) |
- (0 << MPU6000_PWR_MGMT_1_SLEEP) |
- (0 << MPU6000_PWR_MGMT_1_CYCLE) |
- (0 << MPU6000_PWR_MGMT_1_TEMP_DIS) |
- (MPU6000_PWR_MGMT_1_CLKSEL_PLL_X_AXIS << MPU6000_PWR_MGMT_1_CLKSEL));
+ _ao_mpu6000_reg_write(MPU6000_PWR_MGMT_1,
+ (0 << MPU6000_PWR_MGMT_1_DEVICE_RESET) |
+ (0 << MPU6000_PWR_MGMT_1_SLEEP) |
+ (0 << MPU6000_PWR_MGMT_1_CYCLE) |
+ (0 << MPU6000_PWR_MGMT_1_TEMP_DIS) |
+ (MPU6000_PWR_MGMT_1_CLKSEL_PLL_X_AXIS << MPU6000_PWR_MGMT_1_CLKSEL));
- /* Set sample rate divider to sample at full speed
- ao_mpu6000_reg_write(MPU6000_SMPRT_DIV, 0);
+ /* Set sample rate divider to sample at full speed */
+ _ao_mpu6000_reg_write(MPU6000_SMPRT_DIV, 0);
/* Disable filtering */
- ao_mpu6000_reg_write(MPU6000_CONFIG,
- (MPU6000_CONFIG_EXT_SYNC_SET_DISABLED << MPU6000_CONFIG_EXT_SYNC_SET) |
- (MPU6000_CONFIG_DLPF_CFG_260_256 << MPU6000_CONFIG_DLPF_CFG));
-
- /* Configure accelerometer to +/-16G in self-test mode */
- ao_mpu6000_reg_write(MPU6000_ACCEL_CONFIG,
- (1 << MPU600_ACCEL_CONFIG_XA_ST) |
- (1 << MPU600_ACCEL_CONFIG_YA_ST) |
- (1 << MPU600_ACCEL_CONFIG_ZA_ST) |
- (MPU600_ACCEL_CONFIG_AFS_SEL_16G << MPU600_ACCEL_CONFIG_AFS_SEL));
-
- /* Configure gyro to +/- 2000°/s in self-test mode */
- ao_mpu6000_reg_write(MPU6000_GYRO_CONFIG,
- (1 << MPU600_GYRO_CONFIG_XG_ST) |
- (1 << MPU600_GYRO_CONFIG_YG_ST) |
- (1 << MPU600_GYRO_CONFIG_ZG_ST) |
- (MPU600_GYRO_CONFIG_FS_SEL_2000 << MPU600_GYRO_CONFIG_FS_SEL));
-
- ao_delay(AO_MS_TO_TICKS(200));
- ao_mpu6000_sample(&test_mode);
+ _ao_mpu6000_reg_write(MPU6000_CONFIG,
+ (MPU6000_CONFIG_EXT_SYNC_SET_DISABLED << MPU6000_CONFIG_EXT_SYNC_SET) |
+ (MPU6000_CONFIG_DLPF_CFG_260_256 << MPU6000_CONFIG_DLPF_CFG));
#if TRIDGE
// read the product ID rev c has 1/2 the sensitivity of rev d
- _mpu6000_product_id = _register_read(MPUREG_PRODUCT_ID);
- //Serial.printf("Product_ID= 0x%x\n", (unsigned) _mpu6000_product_id);
-
- if ((_mpu6000_product_id == MPU6000ES_REV_C4) || (_mpu6000_product_id == MPU6000ES_REV_C5) ||
- (_mpu6000_product_id == MPU6000_REV_C4) || (_mpu6000_product_id == MPU6000_REV_C5)) {
- // Accel scale 8g (4096 LSB/g)
- // Rev C has different scaling than rev D
- register_write(MPUREG_ACCEL_CONFIG,1<<3);
- } else {
- // Accel scale 8g (4096 LSB/g)
- register_write(MPUREG_ACCEL_CONFIG,2<<3);
- }
- hal.scheduler->delay(1);
-
+ _mpu6000_product_id = _register_read(MPUREG_PRODUCT_ID);
+ //Serial.printf("Product_ID= 0x%x\n", (unsigned) _mpu6000_product_id);
+
+ if ((_mpu6000_product_id == MPU6000ES_REV_C4) || (_mpu6000_product_id == MPU6000ES_REV_C5) ||
+ (_mpu6000_product_id == MPU6000_REV_C4) || (_mpu6000_product_id == MPU6000_REV_C5)) {
+ // Accel scale 8g (4096 LSB/g)
+ // Rev C has different scaling than rev D
+ register_write(MPUREG_ACCEL_CONFIG,1<<3);
+ } else {
+ // Accel scale 8g (4096 LSB/g)
+ register_write(MPUREG_ACCEL_CONFIG,2<<3);
+ }
+ hal.scheduler->delay(1);
#endif
- /* Configure accelerometer to +/-16G */
- ao_mpu6000_reg_write(MPU6000_ACCEL_CONFIG,
- (0 << MPU600_ACCEL_CONFIG_XA_ST) |
- (0 << MPU600_ACCEL_CONFIG_YA_ST) |
- (0 << MPU600_ACCEL_CONFIG_ZA_ST) |
- (MPU600_ACCEL_CONFIG_AFS_SEL_16G << MPU600_ACCEL_CONFIG_AFS_SEL));
-
- /* Configure gyro to +/- 2000°/s */
- ao_mpu6000_reg_write(MPU6000_GYRO_CONFIG,
- (0 << MPU600_GYRO_CONFIG_XG_ST) |
- (0 << MPU600_GYRO_CONFIG_YG_ST) |
- (0 << MPU600_GYRO_CONFIG_ZG_ST) |
- (MPU600_GYRO_CONFIG_FS_SEL_2000 << MPU600_GYRO_CONFIG_FS_SEL));
-
- ao_delay(AO_MS_TO_TICKS(10));
- ao_mpu6000_sample(&normal_mode);
+ for (st_tries = 0; st_tries < ST_TRIES; st_tries++) {
+ errors = 0;
+
+ /* Configure accelerometer to +/-16G in self-test mode */
+ _ao_mpu6000_reg_write(MPU6000_ACCEL_CONFIG,
+ (1 << MPU600_ACCEL_CONFIG_XA_ST) |
+ (1 << MPU600_ACCEL_CONFIG_YA_ST) |
+ (1 << MPU600_ACCEL_CONFIG_ZA_ST) |
+ (MPU600_ACCEL_CONFIG_AFS_SEL_16G << MPU600_ACCEL_CONFIG_AFS_SEL));
+
+ /* Configure gyro to +/- 2000°/s in self-test mode */
+ _ao_mpu6000_reg_write(MPU6000_GYRO_CONFIG,
+ (1 << MPU600_GYRO_CONFIG_XG_ST) |
+ (1 << MPU600_GYRO_CONFIG_YG_ST) |
+ (1 << MPU600_GYRO_CONFIG_ZG_ST) |
+ (MPU600_GYRO_CONFIG_FS_SEL_2000 << MPU600_GYRO_CONFIG_FS_SEL));
+
+ ao_delay(AO_MS_TO_TICKS(200));
+ _ao_mpu6000_sample(&test_mode);
+
+ /* Configure accelerometer to +/-16G */
+ _ao_mpu6000_reg_write(MPU6000_ACCEL_CONFIG,
+ (0 << MPU600_ACCEL_CONFIG_XA_ST) |
+ (0 << MPU600_ACCEL_CONFIG_YA_ST) |
+ (0 << MPU600_ACCEL_CONFIG_ZA_ST) |
+ (MPU600_ACCEL_CONFIG_AFS_SEL_16G << MPU600_ACCEL_CONFIG_AFS_SEL));
+
+ /* Configure gyro to +/- 2000°/s */
+ _ao_mpu6000_reg_write(MPU6000_GYRO_CONFIG,
+ (0 << MPU600_GYRO_CONFIG_XG_ST) |
+ (0 << MPU600_GYRO_CONFIG_YG_ST) |
+ (0 << MPU600_GYRO_CONFIG_ZG_ST) |
+ (MPU600_GYRO_CONFIG_FS_SEL_2000 << MPU600_GYRO_CONFIG_FS_SEL));
+
+ ao_delay(AO_MS_TO_TICKS(200));
+ _ao_mpu6000_sample(&normal_mode);
- errors += ao_mpu6000_accel_check(normal_mode.accel_x, test_mode.accel_x, "x");
- errors += ao_mpu6000_accel_check(normal_mode.accel_y, test_mode.accel_y, "y");
- errors += ao_mpu6000_accel_check(normal_mode.accel_z, test_mode.accel_z, "z");
-
- errors += ao_mpu6000_gyro_check(normal_mode.gyro_x, test_mode.gyro_x, "x");
- errors += ao_mpu6000_gyro_check(normal_mode.gyro_y, test_mode.gyro_y, "y");
- errors += ao_mpu6000_gyro_check(normal_mode.gyro_z, test_mode.gyro_z, "z");
+ errors += ao_mpu6000_accel_check(normal_mode.accel_x, test_mode.accel_x, "x");
+ errors += ao_mpu6000_accel_check(normal_mode.accel_y, test_mode.accel_y, "y");
+ errors += ao_mpu6000_accel_check(normal_mode.accel_z, test_mode.accel_z, "z");
+
+ errors += ao_mpu6000_gyro_check(normal_mode.gyro_x, test_mode.gyro_x, "x");
+ errors += ao_mpu6000_gyro_check(normal_mode.gyro_y, test_mode.gyro_y, "y");
+ errors += ao_mpu6000_gyro_check(normal_mode.gyro_z, test_mode.gyro_z, "z");
+ if (!errors)
+ break;
+ }
- if (errors)
- ao_panic(AO_PANIC_SELF_TEST_MPU6000);
+ if (st_tries == ST_TRIES)
+ ao_sensor_errors = 1;
/* Filter to about 100Hz, which also sets the gyro rate to 1000Hz */
- ao_mpu6000_reg_write(MPU6000_CONFIG,
- (MPU6000_CONFIG_EXT_SYNC_SET_DISABLED << MPU6000_CONFIG_EXT_SYNC_SET) |
- (MPU6000_CONFIG_DLPF_CFG_94_98 << MPU6000_CONFIG_DLPF_CFG));
+ _ao_mpu6000_reg_write(MPU6000_CONFIG,
+ (MPU6000_CONFIG_EXT_SYNC_SET_DISABLED << MPU6000_CONFIG_EXT_SYNC_SET) |
+ (MPU6000_CONFIG_DLPF_CFG_94_98 << MPU6000_CONFIG_DLPF_CFG));
/* Set sample rate divider to sample at 200Hz (v = gyro/rate - 1) */
- ao_mpu6000_reg_write(MPU6000_SMPRT_DIV,
- 1000 / 200 - 1);
+ _ao_mpu6000_reg_write(MPU6000_SMPRT_DIV,
+ 1000 / 200 - 1);
ao_delay(AO_MS_TO_TICKS(100));
ao_mpu6000_configured = 1;
static void
ao_mpu6000(void)
{
- ao_mpu6000_setup();
+ /* ao_mpu6000_init already grabbed the SPI bus and mutex */
+ _ao_mpu6000_setup();
+#if AO_MPU6000_SPI
+ ao_mpu6000_spi_put();
+#endif
for (;;)
{
- ao_mpu6000_sample(&ao_mpu6000_current);
+#if AO_MPU6000_SPI
+ ao_mpu6000_spi_get();
+#endif
+ _ao_mpu6000_sample(&ao_mpu6000_current);
+#if AO_MPU6000_SPI
+ ao_mpu6000_spi_put();
+#endif
ao_arch_critical(
AO_DATA_PRESENT(AO_DATA_MPU6000);
AO_DATA_WAIT();
ao_mpu6000_configured = 0;
ao_add_task(&ao_mpu6000_task, ao_mpu6000, "mpu6000");
+
+#if AO_MPU6000_SPI
+ ao_spi_init_cs(AO_MPU6000_SPI_CS_PORT, (1 << AO_MPU6000_SPI_CS_PIN));
+
+ /* Pretend to be the mpu6000 task. Grab the SPI bus right away and
+ * hold it for the task so that nothing else uses the SPI bus before
+ * we get the I2C mode disabled in the chip
+ */
+
+ ao_cur_task = &ao_mpu6000_task;
+ ao_spi_get(AO_MPU6000_SPI_BUS, AO_SPI_SPEED_1MHz);
+ ao_cur_task = NULL;
+#endif
+
ao_cmd_register(&ao_mpu6000_cmds[0]);
}
+#endif
#ifndef _AO_MPU6000_H_
#define _AO_MPU6000_H_
+#ifndef M_PI
+#define M_PI 3.1415926535897832384626433
+#endif
+
#define MPU6000_ADDR_WRITE 0xd0
#define MPU6000_ADDR_READ 0xd1
#define MPU6000_SIGNAL_PATH_RESET_ACCEL_RESET 1
#define MPU6000_SIGNAL_PATH_RESET_TEMP_RESET 0
-#define MPU6000_USER_CONTROL 0x6a
-#define MPU6000_USER_CONTROL_FIFO_EN 6
-#define MPU6000_USER_CONTROL_I2C_MST_EN 5
-#define MPU6000_USER_CONTROL_I2C_IF_DIS 4
-#define MPU6000_USER_CONTROL_FIFO_RESET 2
-#define MPU6000_USER_CONTROL_I2C_MST_RESET 1
-#define MPU6000_USER_CONTROL_SIG_COND_RESET 0
+#define MPU6000_USER_CTRL 0x6a
+#define MPU6000_USER_CTRL_FIFO_EN 6
+#define MPU6000_USER_CTRL_I2C_MST_EN 5
+#define MPU6000_USER_CTRL_I2C_IF_DIS 4
+#define MPU6000_USER_CTRL_FIFO_RESET 2
+#define MPU6000_USER_CTRL_I2C_MST_RESET 1
+#define MPU6000_USER_CTRL_SIG_COND_RESET 0
#define MPU6000_PWR_MGMT_1 0x6b
#define MPU6000_PWR_MGMT_1_DEVICE_RESET 7
/* Self test gyro is approximately 50°/s */
#define MPU6000_ST_GYRO(full_scale) ((int16_t) (((int32_t) 32767 * (int32_t) 50) / (full_scale)))
-#define MPU6000_GYRO_FULLSCALE 2000
+#define MPU6000_GYRO_FULLSCALE ((float) 2000 * M_PI/180.0)
+
+static inline float
+ao_mpu6000_gyro(float sensor) {
+ return sensor * ((float) (MPU6000_GYRO_FULLSCALE / 32767.0));
+}
+
#define MPU6000_ACCEL_FULLSCALE 16
+static inline float
+ao_mpu6000_accel(int16_t sensor) {
+ return (float) sensor * ((float) (MPU6000_ACCEL_FULLSCALE * GRAVITY / 32767.0));
+}
+
struct ao_mpu6000_sample {
int16_t accel_x;
int16_t accel_y;
#if HAS_MS5607 || HAS_MS5611
-static struct ao_ms5607_prom ms5607_prom;
-static uint8_t ms5607_configured;
+static __xdata struct ao_ms5607_prom ms5607_prom;
+static __xdata uint8_t ms5607_configured;
static void
ao_ms5607_start(void) {
- ao_spi_get(AO_MS5607_SPI_INDEX,AO_SPI_SPEED_FAST);
- ao_gpio_set(AO_MS5607_CS_PORT, AO_MS5607_CS_PIN, AO_MS5607_CS, 0);
+ ao_spi_get_bit(AO_MS5607_CS_PORT, AO_MS5607_CS_PIN, AO_MS5607_CS, AO_MS5607_SPI_INDEX, AO_SPI_SPEED_FAST);
}
static void
ao_ms5607_stop(void) {
- ao_gpio_set(AO_MS5607_CS_PORT, AO_MS5607_CS_PIN, AO_MS5607_CS, 1);
- ao_spi_put(AO_MS5607_SPI_INDEX);
+ ao_spi_put_bit(AO_MS5607_CS_PORT, AO_MS5607_CS_PIN, AO_MS5607_CS, AO_MS5607_SPI_INDEX);
}
static void
cmd = AO_MS5607_RESET;
ao_ms5607_start();
- ao_spi_send(&cmd, 1, AO_MS5607_SPI_INDEX);
+ ao_spi_send(DATA_TO_XDATA(&cmd), 1, AO_MS5607_SPI_INDEX);
ao_delay(AO_MS_TO_TICKS(10));
ao_ms5607_stop();
}
}
static void
-ao_ms5607_prom_read(struct ao_ms5607_prom *prom)
+ao_ms5607_prom_read(__xdata struct ao_ms5607_prom *prom)
{
- uint8_t addr;
- uint8_t crc;
- uint16_t *r;
+ uint8_t addr;
+ uint8_t crc;
+ __xdata uint16_t *r;
- r = (uint16_t *) prom;
+ r = (__xdata uint16_t *) prom;
for (addr = 0; addr < 8; addr++) {
uint8_t cmd = AO_MS5607_PROM_READ(addr);
ao_ms5607_start();
- ao_spi_send(&cmd, 1, AO_MS5607_SPI_INDEX);
+ ao_spi_send(DATA_TO_XDATA(&cmd), 1, AO_MS5607_SPI_INDEX);
ao_spi_recv(r, 2, AO_MS5607_SPI_INDEX);
ao_ms5607_stop();
r++;
ao_ms5607_prom_read(&ms5607_prom);
}
-static volatile uint8_t ao_ms5607_done;
+static __xdata volatile uint8_t ao_ms5607_done;
static void
ao_ms5607_isr(void)
{
ao_exti_disable(AO_MS5607_MISO_PORT, AO_MS5607_MISO_PIN);
ao_ms5607_done = 1;
- ao_wakeup((void *) &ao_ms5607_done);
+ ao_wakeup((__xdata void *) &ao_ms5607_done);
}
static uint32_t
ao_ms5607_get_sample(uint8_t cmd) {
- uint8_t reply[3];
- uint8_t read;
+ __xdata uint8_t reply[3];
+ __xdata uint8_t read;
ao_ms5607_done = 0;
ao_ms5607_start();
- ao_spi_send(&cmd, 1, AO_MS5607_SPI_INDEX);
+ ao_spi_send(DATA_TO_XDATA(&cmd), 1, AO_MS5607_SPI_INDEX);
ao_exti_enable(AO_MS5607_MISO_PORT, AO_MS5607_MISO_PIN);
ao_spi_put(AO_MS5607_SPI_INDEX);
#endif
ao_arch_block_interrupts();
- while (!ao_ms5607_done)
+ while (!ao_gpio_get(AO_MS5607_MISO_PORT, AO_MS5607_MISO_PIN, AO_MS5607_MISO) &&
+ !ao_ms5607_done)
ao_sleep((void *) &ao_ms5607_done);
ao_arch_release_interrupts();
#if AO_MS5607_PRIVATE_PINS
#define AO_CONVERT_D2 token_evaluator(AO_MS5607_CONVERT_D2_, AO_MS5607_TEMP_OVERSAMPLE)
void
-ao_ms5607_sample(struct ao_ms5607_sample *sample)
+ao_ms5607_sample(__xdata struct ao_ms5607_sample *sample)
{
sample->pres = ao_ms5607_get_sample(AO_CONVERT_D1);
sample->temp = ao_ms5607_get_sample(AO_CONVERT_D2);
}
+#ifdef _CC1111_H_
+#include "ao_ms5607_convert_8051.c"
+#else
#include "ao_ms5607_convert.c"
+#endif
#if HAS_TASK
-struct ao_ms5607_sample ao_ms5607_current;
+__xdata struct ao_ms5607_sample ao_ms5607_current;
static void
ao_ms5607(void)
for (;;)
{
ao_ms5607_sample(&ao_ms5607_current);
- ao_arch_critical(
- AO_DATA_PRESENT(AO_DATA_MS5607);
- AO_DATA_WAIT();
- );
+ ao_arch_block_interrupts();
+ AO_DATA_PRESENT(AO_DATA_MS5607);
+ AO_DATA_WAIT();
+ ao_arch_release_interrupts();
}
}
static void
ao_ms5607_dump(void)
{
- struct ao_ms5607_value value;
+ __xdata struct ao_ms5607_value value;
ao_ms5607_convert(&ao_ms5607_current, &value);
- printf ("Pressure: %8u %8d\n", ao_ms5607_current.pres, value.pres);
- printf ("Temperature: %8u %8d\n", ao_ms5607_current.temp, value.temp);
+ printf ("Pressure: %8lu %8ld\n", ao_ms5607_current.pres, value.pres);
+ printf ("Temperature: %8lu %8ld\n", ao_ms5607_current.temp, value.temp);
printf ("Altitude: %ld\n", ao_pa_to_altitude(value.pres));
}
*/
ao_exti_setup(AO_MS5607_MISO_PORT,
AO_MS5607_MISO_PIN,
- AO_EXTI_MODE_RISING,
+ AO_EXTI_MODE_RISING|
+ AO_EXTI_PIN_NOCONFIGURE,
ao_ms5607_isr);
-
-#ifdef STM_MODER_ALTERNATE
- /* Reset the pin from INPUT to ALTERNATE so that SPI works
- * This needs an abstraction at some point...
- */
- stm_moder_set(AO_MS5607_MISO_PORT,
- AO_MS5607_MISO_PIN,
- STM_MODER_ALTERNATE);
-#endif
}
#endif
int32_t temp; /* in °C * 100 */
};
-extern struct ao_ms5607_sample ao_ms5607_current;
+extern __xdata struct ao_ms5607_sample ao_ms5607_current;
void
ao_ms5607_setup(void);
ao_ms5607_info(void);
void
-ao_ms5607_sample(struct ao_ms5607_sample *sample);
+ao_ms5607_sample(__xdata struct ao_ms5607_sample *sample);
void
-ao_ms5607_convert(struct ao_ms5607_sample *sample, struct ao_ms5607_value *value);
+ao_ms5607_convert(__xdata struct ao_ms5607_sample *sample,
+ __xdata struct ao_ms5607_value *value);
void
-ao_ms5607_get_prom(struct ao_ms5607_prom *prom);
+ao_ms5607_get_prom(__data struct ao_ms5607_prom *prom);
#endif /* _AO_MS5607_H_ */
int32_t TEMPM = TEMP - 2000;
int64_t OFF2 = (61 * (int64_t) TEMPM * (int64_t) TEMPM) >> 4;
int64_t SENS2 = 2 * (int64_t) TEMPM * (int64_t) TEMPM;
- if (TEMP < 1500) {
+ if (TEMP < -1500) {
int32_t TEMPP = TEMP + 1500;
- int64_t TEMPP2 = TEMPP * TEMPP;
- OFF2 = OFF2 + 15 * TEMPP2;
- SENS2 = SENS2 + 8 * TEMPP2;
+ /* You'd think this would need a 64-bit int, but
+ * that would imply a temperature below -327.67°C...
+ */
+ int32_t TEMPP2 = TEMPP * TEMPP;
+ OFF2 = OFF2 + (int64_t) 15 * TEMPP2;
+ SENS2 = SENS2 + (int64_t) 8 * TEMPP2;
}
TEMP -= T2;
OFF -= OFF2;
--- /dev/null
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao_ms5607.h>
+#include <ao_int64.h>
+
+#if HAS_MS5611
+#define SHIFT_OFF 16
+#define SHIFT_TCO 7
+#define SHIFT_SENS 15
+#define SHFIT_TCS 8
+#else
+#define SHIFT_OFF 17
+#define SHIFT_TCO 6
+#define SHIFT_SENS 16
+#define SHIFT_TCS 7
+#endif
+
+void
+ao_ms5607_convert(__xdata struct ao_ms5607_sample *sample,
+ __xdata struct ao_ms5607_value *value)
+{
+ __LOCAL int32_t dT;
+ __LOCAL int32_t TEMP;
+ __LOCAL ao_int64_t OFF;
+ __LOCAL ao_int64_t SENS;
+ __LOCAL ao_int64_t a;
+
+ dT = sample->temp - ((int32_t) ms5607_prom.tref << 8);
+
+ /* TEMP = 2000 + (((int64_t) dT * ms5607_prom.tempsens) >> 23); */
+ ao_mul64_32_32(&a, dT, ms5607_prom.tempsens);
+ ao_rshift64(&a, &a, 23);
+ TEMP = 2000 + a.low;
+ /* */
+
+ /* OFF = ((int64_t) ms5607_prom.off << SHIFT_OFF) + (((int64_t) ms5607_prom.tco * dT) >> SHIFT_TCO);*/
+#if SHIFT_OFF > 16
+ OFF.high = ms5607_prom.off >> (32 - SHIFT_OFF);
+#else
+ OFF.high = 0;
+#endif
+ OFF.low = (uint32_t) ms5607_prom.off << SHIFT_OFF;
+ ao_mul64_32_32(&a, ms5607_prom.tco, dT);
+ ao_rshift64(&a, &a, SHIFT_TCO);
+ ao_plus64(&OFF, &OFF, &a);
+ /**/
+
+ /* SENS = ((int64_t) ms5607_prom.sens << SHIFT_SENS) + (((int64_t) ms5607_prom.tcs * dT) >> SHIFT_TCS); */
+ SENS.high = 0;
+ SENS.low = (uint32_t) ms5607_prom.sens << SHIFT_SENS;
+ ao_mul64_32_32(&a, ms5607_prom.tcs, dT);
+ ao_rshift64(&a, &a, SHIFT_TCS);
+ ao_plus64(&SENS, &SENS, &a);
+ /**/
+
+ if (TEMP < 2000) {
+ __LOCAL int32_t T2;
+ __LOCAL int32_t TEMPM;
+ __LOCAL ao_int64_t OFF2;
+ __LOCAL ao_int64_t SENS2;
+
+ /* T2 = ((int64_t) dT * (int64_t) dT) >> 31; */
+ ao_mul64_32_32(&a, dT, dT);
+ T2 = (a.low >> 31) | (a.high << 1);
+ /**/
+
+ TEMPM = TEMP - 2000;
+
+ /* OFF2 = (61 * (int64_t) TEMPM * (int64_t) TEMPM) >> 4; */
+ ao_mul64_32_32(&OFF2, TEMPM, TEMPM);
+ ao_mul64_64_16(&OFF2, &OFF2, 61);
+ ao_rshift64(&OFF2, &OFF2, 4);
+ /**/
+
+ /* SENS2 = 2 * (int64_t) TEMPM * (int64_t) TEMPM; */
+ ao_mul64_32_32(&SENS2, TEMPM, TEMPM);
+ ao_lshift64(&SENS2, &SENS2, 1);
+ /**/
+
+ if (TEMP < -1500) {
+ int32_t TEMPP;
+ int32_t TEMPP2;
+
+ TEMPP = TEMP + 1500;
+ TEMPP2 = TEMPP * TEMPP;
+
+ /* OFF2 = OFF2 + 15 * TEMPP2; */
+ ao_mul64_32_32(&a, 15, TEMPP2);
+ ao_plus64(&OFF2, &OFF2, &a);
+ /**/
+
+ /* SENS2 = SENS2 + 8 * TEMPP2; */
+ a.high = 0;
+ a.low = TEMPP2;
+ ao_lshift64(&a, &a, 3);
+ ao_plus64(&SENS2, &SENS2, &a);
+ /**/
+ }
+ TEMP -= T2;
+
+ /* OFF -= OFF2; */
+ ao_minus64(&OFF, &OFF, &OFF2);
+ /**/
+
+ /* SENS -= SENS2; */
+ ao_minus64(&SENS, &SENS, &SENS2);
+ /**/
+ }
+
+ /* value->pres = ((((int64_t) sample->pres * SENS) >> 21) - OFF) >> 15; */
+ a.high = 0;
+ a.low = sample->pres;
+ ao_mul64(&a, &a, &SENS);
+ ao_rshift64(&a, &a, 21);
+ ao_minus64(&a, &a, &OFF);
+ ao_rshift64(&a, &a, 15);
+ value->pres = a.low;
+ /**/
+
+ value->temp = TEMP;
+}
#include <ao.h>
#include <ao_pad.h>
-#include <ao_74hc497.h>
+#include <ao_74hc165.h>
#include <ao_radio_cmac.h>
static __xdata uint8_t ao_pad_ignite;
static __pdata uint16_t ao_pad_arm_time;
static __pdata uint8_t ao_pad_box;
static __xdata uint8_t ao_pad_disabled;
+static __pdata uint16_t ao_pad_packet_time;
#define DEBUG 1
query.arm_status = AO_PAD_ARM_STATUS_UNKNOWN;
arm_beep_time = 0;
}
+ if ((ao_time() - ao_pad_packet_time) > AO_SEC_TO_TICKS(2))
+ cur |= AO_LED_RED;
+ else if (ao_radio_cmac_rssi < -90)
+ cur |= AO_LED_AMBER;
+ else
+ cur |= AO_LED_GREEN;
for (c = 0; c < AO_PAD_NUM; c++) {
int16_t sense = packet->adc.sense[c];
query.igniter_status[c] = status;
}
if (cur != prev) {
- PRINTD("change leds from %02x to %02x mask %02x\n",
- prev, cur, AO_LED_CONTINUITY_MASK|AO_LED_ARMED);
- ao_led_set_mask(cur, AO_LED_CONTINUITY_MASK | AO_LED_ARMED);
+ PRINTD("change leds from %02x to %02x\n",
+ prev, cur);
+ FLUSHD();
+ ao_led_set(cur);
prev = cur;
}
if (ao_pad_armed) {
ao_strobe(1);
- if (sample & 2)
- ao_siren(1);
- else
- ao_siren(0);
+ ao_siren(1);
beeping = 1;
} else if (query.arm_status == AO_PAD_ARM_STATUS_ARMED && !beeping) {
if (arm_beep_time == 0) {
ao_wakeup (&ao_pad_disabled);
}
+#if HAS_74HC165
+static uint8_t
+ao_pad_read_box(void)
+{
+ uint8_t byte = ao_74hc165_read();
+ uint8_t h, l;
+
+ h = byte >> 4;
+ l = byte & 0xf;
+ return h * 10 + l;
+}
+#else
+#define ao_pad_read_box() 0
+#endif
+
static void
ao_pad(void)
{
ao_pad_box = 0;
ao_led_set(0);
- ao_led_on(AO_LED_POWER);
for (;;) {
FLUSHD();
while (ao_pad_disabled)
ao_sleep(&ao_pad_disabled);
ret = ao_radio_cmac_recv(&command, sizeof (command), 0);
- PRINTD ("cmac_recv %d\n", ret);
+ PRINTD ("cmac_recv %d %d\n", ret, ao_radio_cmac_rssi);
if (ret != AO_RADIO_CMAC_OK)
continue;
+ ao_pad_packet_time = ao_time();
- PRINTD ("tick %d box %d cmd %d channels %02x\n",
- command.tick, command.box, command.cmd, command.channels);
+ ao_pad_box = ao_pad_read_box();
+
+ PRINTD ("tick %d box %d (me %d) cmd %d channels %02x\n",
+ command.tick, command.box, ao_pad_box, command.cmd, command.channels);
switch (command.cmd) {
case AO_LAUNCH_ARM:
}
for (c = 0; c < AO_PAD_NUM; c++) {
- printf ("Pad %d: ");
+ printf ("Pad %d: ", c);
switch (query.igniter_status[c]) {
case AO_PAD_IGNITER_STATUS_NO_IGNITER_RELAY_CLOSED: printf ("No igniter. Relay closed\n"); break;
case AO_PAD_IGNITER_STATUS_NO_IGNITER_RELAY_OPEN: printf ("No igniter. Relay open\n"); break;
if (ao_cmd_status == ao_cmd_success)
ao_pad_debug = ao_cmd_lex_i != 0;
}
+
+
+static void
+ao_pad_alarm_debug(void)
+{
+ uint8_t which, value;
+ ao_cmd_decimal();
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+ which = ao_cmd_lex_i;
+ ao_cmd_decimal();
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+ value = ao_cmd_lex_i;
+ printf ("Set %s to %d\n", which ? "siren" : "strobe", value);
+ if (which)
+ ao_siren(value);
+ else
+ ao_strobe(value);
+}
#endif
__code struct ao_cmds ao_pad_cmds[] = {
{ ao_pad_manual, "i <key> <n>\0Fire igniter. <key> is doit with D&I" },
#if DEBUG
{ ao_pad_set_debug, "D <0 off, 1 on>\0Debug" },
+ { ao_pad_alarm_debug, "S <0 strobe, 1 siren> <0 off, 1 on>\0Set alarm output" },
#endif
{ 0, NULL }
};
/* Don't try the SPI bus during initialization */
if (!ao_cur_task)
return;
- ao_spi_get_bit(AO_PCA9922_CS_PORT, AO_PCA9922_CS_PIN, AO_PCA9922_CS, AO_PCA9922_SPI_BUS, AO_SPI_SPEED_FAST);
+ ao_spi_get(AO_PCA9922_SPI_BUS);
+ ao_spi_set_speed(AO_PCA9922_SPI_BUS,AO_SPI_SPEED_FAST);
+ AO_PCA9922_CS = 1;
ao_spi_send(&ao_led_state, 1, AO_PCA9922_SPI_BUS);
- ao_spi_put_bit(AO_PCA9922_CS_PORT, AO_PCA9922_CS_PIN, AO_PCA9922_CS, AO_PCA9922_SPI_BUS);
+ AO_PCA9922_CS = 0;
+ ao_spi_put(AO_PCA9922_SPI_BUS);
}
void
#include <ao.h>
#include <ao_quadrature.h>
#include <ao_exti.h>
-#if AO_EVENT
+#include <ao_fast_timer.h>
#include <ao_event.h>
-#define ao_quadrature_queue(q) ao_event_put_isr(AO_EVENT_QUADRATURE, q, ao_quadrature_count[q])
-#else
-#define ao_quadrature_queue(q)
-#endif
__xdata int32_t ao_quadrature_count[AO_QUADRATURE_COUNT];
-
static uint8_t ao_quadrature_state[AO_QUADRATURE_COUNT];
+static int8_t ao_quadrature_raw[AO_QUADRATURE_COUNT];
#define BIT(a,b) ((a) | ((b) << 1))
#define STATE(old_a, old_b, new_a, new_b) (((BIT(old_a, old_b) << 2) | BIT(new_a, new_b)))
#define port(q) AO_QUADRATURE_ ## q ## _PORT
#define bita(q) AO_QUADRATURE_ ## q ## _A
#define bitb(q) AO_QUADRATURE_ ## q ## _B
+#define pina(q) AO_QUADRATURE_ ## q ## _A ## _PIN
+#define pinb(q) AO_QUADRATURE_ ## q ## _B ## _PIN
+#define isr(q) ao_quadrature_isr_ ## q
-#define ao_quadrature_update(q) do { \
- ao_quadrature_state[q] = ((ao_quadrature_state[q] & 3) << 2); \
- ao_quadrature_state[q] |= ao_gpio_get(port(q), bita(q), 0); \
- ao_quadrature_state[q] |= ao_gpio_get(port(q), bitb(q), 0) << 1; \
- } while (0)
-
+static inline uint16_t
+ao_quadrature_read(struct stm_gpio *gpio, uint8_t pin_a, uint8_t pin_b) {
+ uint16_t v = stm_gpio_get_all(gpio);
+
+ return ~((((v >> pin_a) & 1) | (((v >> pin_b) & 1) << 1))) & 3;
+}
+
+#define _ao_quadrature_get(q) ao_quadrature_read(port(q), bita(q), bitb(q))
static void
-ao_quadrature_isr(void)
+_ao_quadrature_queue(uint8_t q, int8_t step)
{
- uint8_t q;
-#if AO_QUADRATURE_COUNT > 0
- ao_quadrature_update(0);
-#endif
-#if AO_QUADRATURE_COUNT > 1
- ao_quadrature_update(1);
+ ao_quadrature_count[q] += step;
+#if AO_EVENT
+ ao_event_put_isr(AO_EVENT_QUADRATURE, q, step);
#endif
+ ao_wakeup(&ao_quadrature_count[q]);
+}
- for (q = 0; q < AO_QUADRATURE_COUNT; q++) {
- switch (ao_quadrature_state[q]) {
- case STATE(0, 1, 0, 0):
- ao_quadrature_count[q]++;
- break;
- case STATE(1, 0, 0, 0):
- ao_quadrature_count[q]--;
- break;
- default:
- continue;
- }
- ao_quadrature_queue(q);
- ao_wakeup(&ao_quadrature_count[q]);
+static const int8_t step[16] = {
+ [STATE(0,0,0,0)] = 0,
+ [STATE(0,0,0,1)] = -1,
+ [STATE(0,0,1,0)] = 1,
+ [STATE(0,0,1,1)] = 0,
+ [STATE(0,1,0,0)] = 1,
+ [STATE(0,1,1,0)] = 0,
+ [STATE(0,1,1,1)] = -1,
+ [STATE(1,0,0,0)] = -1,
+ [STATE(1,0,0,1)] = 0,
+ [STATE(1,0,1,0)] = 0,
+ [STATE(1,0,1,1)] = 1,
+ [STATE(1,1,0,0)] = 0,
+ [STATE(1,1,0,1)] = 1,
+ [STATE(1,1,1,0)] = -1,
+ [STATE(1,1,1,1)] = 0
+};
+
+static void
+_ao_quadrature_set(uint8_t q, uint8_t value) {
+ uint8_t v;
+
+ v = ao_quadrature_state[q] & 3;
+ value = value & 3;
+
+ if (v == value)
+ return;
+
+ ao_quadrature_state[q] = (v << 2) | value;
+
+ ao_quadrature_raw[q] += step[ao_quadrature_state[q]];
+ if (value == 0) {
+ if (ao_quadrature_raw[q] == 4)
+ _ao_quadrature_queue(q, 1);
+ else if (ao_quadrature_raw[q] == -4)
+ _ao_quadrature_queue(q, -1);
+ ao_quadrature_raw[q] = 0;
}
}
+static void
+ao_quadrature_isr(void)
+{
+ _ao_quadrature_set(0, _ao_quadrature_get(0));
+ _ao_quadrature_set(1, _ao_quadrature_get(1));
+}
+
int32_t
ao_quadrature_poll(uint8_t q)
{
ao_cmd_decimal();
q = ao_cmd_lex_i;
+ if (q >= AO_QUADRATURE_COUNT) {
+ ao_cmd_status = ao_cmd_syntax_error;
+ return;
+ }
+ printf ("count %d state %x raw %d\n",
+ ao_quadrature_count[q],
+ ao_quadrature_state[q],
+ ao_quadrature_raw[q]);
+#if 0
for (;;) {
int32_t c;
flush();
if (c == 100)
break;
}
+#endif
}
static const struct ao_cmds ao_quadrature_cmds[] = {
{ 0, NULL }
};
-#define init(q) do { \
- ao_enable_port(port(q)); \
- \
- ao_exti_setup(port(q), bita(q), \
- AO_QUADRATURE_MODE|AO_EXTI_MODE_FALLING|AO_EXTI_MODE_RISING|AO_EXTI_PRIORITY_MED, \
- ao_quadrature_isr); \
- ao_exti_enable(port(q), bita(q)); \
- \
- ao_exti_setup(port(q), bitb(q), \
- AO_QUADRATURE_MODE|AO_EXTI_MODE_FALLING|AO_EXTI_MODE_RISING|AO_EXTI_PRIORITY_MED, \
- ao_quadrature_isr); \
- ao_exti_enable(port(q), bitb(q)); \
+#define init(q) do { \
+ ao_enable_input(port(q), bita(q), 0); \
+ ao_enable_input(port(q), bitb(q), 0); \
} while (0)
void
#if AO_QUADRATURE_COUNT > 1
init(1);
#endif
+ ao_fast_timer_init();
+ ao_fast_timer_on(ao_quadrature_isr);
ao_cmd_register(&ao_quadrature_cmds[0]);
}
--- /dev/null
+#!/usr/bin/nickle
+string[] speeds = { "57600", "19200", "9600" };
+
+string make_set_nmea(string speed) {
+ return sprintf ("PUBX,41,1,3,1,%s,0", speed);
+}
+
+int csum(string x) {
+ int csum = 0;
+ for (int i = 0; i < String::length(x); i++)
+ csum ^= x[i];
+ return csum;
+}
+
+for (int i = 0; i < dim(speeds); i++) {
+ string s = make_set_nmea(speeds[i]);
+ int c = csum(s);
+ printf ("/* $%s* */\n", s);
+ printf ("#define SERIAL_SPEED_STRING \"%s\"\n", speeds[i]);
+ printf ("#define SERIAL_SPEED_CHECKSUM \"%02x\"\n", c);
+}
+
+
--- /dev/null
+ao_product.h
+*.elf
--- /dev/null
+#
+# AltOS build
+#
+#
+
+include ../lpc/Makefile.defs
+
+INC = \
+ ao.h \
+ ao_arch.h \
+ ao_arch_funcs.h \
+ ao_pins.h \
+ ao_product.h \
+ lpc.h
+
+#
+# Common AltOS sources
+#
+ALTOS_SRC = \
+ ao_interrupt.c \
+ ao_boot_chain.c \
+ ao_romconfig.c \
+ ao_product.c \
+ ao_mutex.c \
+ ao_panic.c \
+ ao_stdio.c \
+ ao_storage.c \
+ ao_report.c \
+ ao_ignite.c \
+ ao_flight.c \
+ ao_kalman.c \
+ ao_sample.c \
+ ao_data.c \
+ ao_convert_pa.c \
+ ao_task.c \
+ ao_log.c \
+ ao_log_mini.c \
+ ao_cmd.c \
+ ao_config.c \
+ ao_timer_lpc.c \
+ ao_exti_lpc.c \
+ ao_usb_lpc.c \
+ ao_spi_lpc.c \
+ ao_adc_lpc.c \
+ ao_beep_lpc.c \
+ ao_m25.c \
+ ao_ms5607.c
+
+PRODUCT=EasyMini-v1.0
+PRODUCT_DEF=-DEASYMINI_V_1_0
+IDPRODUCT=0x0026
+
+CFLAGS = $(PRODUCT_DEF) $(LPC_CFLAGS) -g -Os
+
+PROGNAME=easymini-v1.0
+PROG=$(PROGNAME)-$(VERSION).elf
+HEX=$(PROGNAME)-$(VERSION).ihx
+
+SRC=$(ALTOS_SRC) ao_easymini.c
+OBJ=$(SRC:.c=.o)
+
+all: $(PROG) $(HEX)
+
+$(PROG): Makefile $(OBJ) altos.ld
+ $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
+
+ao_product.h: ao-make-product.5c ../Version
+ $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@
+
+$(OBJ): $(INC)
+
+load: $(PROG)
+ lpc-load $(PROG)
+
+distclean: clean
+
+clean:
+ rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx
+ rm -f ao_product.h
+
+install:
+
+uninstall:
--- /dev/null
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+#include <ao_exti.h>
+
+void
+main(void)
+{
+ ao_clock_init();
+ ao_task_init();
+ ao_timer_init();
+ ao_exti_init();
+
+ ao_beep_init();
+
+ ao_adc_init();
+ ao_spi_init();
+ ao_storage_init();
+
+ ao_usb_init();
+
+ ao_cmd_init();
+ ao_flight_init();
+ ao_ms5607_init();
+ ao_log_init();
+ ao_report_init();
+ ao_igniter_init();
+ ao_config_init();
+
+ ao_start_scheduler();
+}
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#define HAS_BEEP 1
+#define HAS_LED 0
+
+#define AO_STACK_SIZE 384
+
+#define IS_FLASH_LOADER 0
+
+/* Crystal on the board */
+#define AO_LPC_CLKIN 12000000
+
+/* Main clock frequency. 48MHz for USB so we don't use the USB PLL */
+#define AO_LPC_CLKOUT 48000000
+
+/* System clock frequency */
+#define AO_LPC_SYSCLK 24000000
+
+#define HAS_USB 1
+
+#define HAS_USB_CONNECT 0
+#define HAS_USB_VBUS 0
+#define HAS_USB_PULLUP 1
+#define AO_USB_PULLUP_PORT 0
+#define AO_USB_PULLUP_PIN 20
+
+#define PACKET_HAS_SLAVE 0
+
+#define AO_LOG_FORMAT AO_LOG_FORMAT_EASYMINI
+
+/* USART */
+
+#define HAS_SERIAL 0
+#define USE_SERIAL_0_STDIN 1
+#define SERIAL_0_18_19 1
+#define SERIAL_0_14_15 0
+#define SERIAL_0_17_18 0
+#define SERIAL_0_26_27 0
+
+/* SPI */
+
+#define HAS_SPI_0 1
+#define SPI_SCK0_P0_6 1
+#define HAS_SPI_1 1
+#define SPI_SCK1_P1_15 1
+#define SPI_MISO1_P0_22 1
+#define SPI_MOSI1_P0_21 1
+
+/* M25 */
+
+#define M25_MAX_CHIPS 1
+#define AO_M25_SPI_CS_PORT 0
+#define AO_M25_SPI_CS_MASK (1 << 23)
+#define AO_M25_SPI_BUS 1
+
+/* MS5607 */
+
+#define HAS_MS5607 1
+#define HAS_MS5611 0
+#define AO_MS5607_PRIVATE_PINS 0
+#define AO_MS5607_CS_PORT 0
+#define AO_MS5607_CS_PIN 7
+#define AO_MS5607_CS_MASK (1 << AO_MS5607_CS_PIN)
+#define AO_MS5607_MISO_PORT 0
+#define AO_MS5607_MISO_PIN 8
+#define AO_MS5607_MISO_MASK (1 << AO_MS5607_MISO_PIN)
+#define AO_MS5607_SPI_INDEX 0
+
+#define HAS_ACCEL 0
+#define HAS_GPS 0
+#define HAS_RADIO 0
+#define HAS_FLIGHT 1
+#define HAS_EEPROM 1
+#define HAS_TELEMETRY 0
+#define HAS_APRS 0
+#define HAS_LOG 1
+#define USE_INTERNAL_FLASH 0
+#define HAS_IGNITE 1
+#define HAS_IGNITE_REPORT 1
+
+#define AO_DATA_RING 16
+
+/*
+ * ADC
+ */
+
+#define HAS_ADC 1
+
+#define AO_NUM_ADC 3
+
+#define AO_ADC_0 1
+#define AO_ADC_1 1
+#define AO_ADC_2 1
+
+struct ao_adc {
+ int16_t sense_a;
+ int16_t sense_m;
+ int16_t v_batt;
+};
+
+/*
+ * Igniter
+ */
+
+#define AO_IGNITER_CLOSED 400
+#define AO_IGNITER_OPEN 60
+
+#define AO_IGNITER_DROGUE_PORT 0
+#define AO_IGNITER_DROGUE_PIN 2
+#define AO_IGNITER_SET_DROGUE(v) ao_gpio_set(AO_IGNITER_DROGUE_PORT, AO_IGNITER_DROGUE_PIN, AO_IGNITER_DROGUE, v)
+
+#define AO_IGNITER_MAIN_PORT 0
+#define AO_IGNITER_MAIN_PIN 3
+#define AO_IGNITER_SET_MAIN(v) ao_gpio_set(AO_IGNITER_MAIN_PORT, AO_IGNITER_MAIN_PIN, AO_IGNITER_MAIN, v)
+
+#define AO_SENSE_DROGUE(p) ((p)->adc.sense_a)
+#define AO_SENSE_MAIN(p) ((p)->adc.sense_m)
+
+#define AO_ADC_DUMP(p) \
+ printf("tick: %5u apogee: %5d main: %5d batt: %5d\n", \
+ (p)->tick, (p)->adc.sense_a, (p)->adc.sense_m, (p)->adc.v_batt)
--- /dev/null
+#
+# AltOS flash loader build
+#
+#
+
+TOPDIR=../..
+HARDWARE=easymini-v1.0
+include $(TOPDIR)/lpc/Makefile-flash.defs
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_PINS_H_
+#define _AO_PINS_H_
+
+#include <ao_flash_lpc_pins.h>
+
+#define AO_BOOT_PIN 1
+#define AO_BOOT_APPLICATION_GPIO 0
+#define AO_BOOT_APPLICATION_PIN 19
+#define AO_BOOT_APPLICATION_VALUE 1
+#define AO_BOOT_APPLICATION_MODE AO_EXTI_MODE_PULL_UP
+
+#define HAS_USB_PULLUP 1
+#define AO_USB_PULLUP_PORT 0
+#define AO_USB_PULLUP_PIN 20
+
+#endif /* _AO_PINS_H_ */
--- /dev/null
+include $(TOPDIR)/lpc/Makefile-lpc.defs
+
+INC = \
+ ao.h \
+ ao_arch.h \
+ ao_arch_funcs.h \
+ ao_flash_pins.h \
+ ao_flash_lpc_pins.h \
+ ao_flash_task.h \
+ ao_pins.h \
+ ao_product.h \
+ Makefile
+
+#
+# Common AltOS sources
+#
+SRC = \
+ ao_interrupt.c \
+ ao_romconfig.c \
+ ao_boot_chain.c \
+ ao_boot_pin.c \
+ ao_product.c \
+ ao_notask.c \
+ ao_timer_lpc.c \
+ ao_usb_lpc.c \
+ ao_flash_lpc.c \
+ ao_flash_task.c \
+ ao_flash_loader_lpc.c
+
+OBJ=$(SRC:.c=.o)
+
+PRODUCT=AltosFlash
+PRODUCT_DEF=-DALTOS_FLASH
+IDPRODUCT=0x000a
+
+CFLAGS = $(PRODUCT_DEF) $(LPC_CFLAGS) -g -Os
+
+LDFLAGS=$(CFLAGS) -L$(TOPDIR)/lpc -Wl,-Taltos-loader.ld
+
+PROGNAME=altos-flash
+PROG=$(HARDWARE)-$(PROGNAME)-$(VERSION).elf
+
+$(PROG): Makefile $(OBJ) altos-loader.ld
+ $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
+
+ao_product.h: ao-make-product.5c $(TOPDIR)/Version
+ $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@
+
+$(OBJ): $(INC)
+
+all: $(PROG)
+
+distclean: clean
+
+clean:
+ rm -f *.o $(HARDWARE)-$(PROGNAME)-*.elf
+ rm -f ao_product.h
+
+install:
+
+uninstall:
--- /dev/null
+ifndef TOPDIR
+TOPDIR=..
+endif
+
+include $(TOPDIR)/Makedefs
+
+vpath % $(TOPDIR)/lpc:$(TOPDIR)/product:$(TOPDIR)/drivers:$(TOPDIR)/core:$(TOPDIR)/util:$(TOPDIR)/kalman:$(TOPDIR/aes):$(TOPDIR)
+vpath make-altitude $(TOPDIR)/util
+vpath make-kalman $(TOPDIR)/util
+vpath kalman.5c $(TOPDIR)/kalman
+vpath kalman_filter.5c $(TOPDIR)/kalman
+vpath load_csv.5c $(TOPDIR)/kalman
+vpath matrix.5c $(TOPDIR)/kalman
+vpath ao-make-product.5c $(TOPDIR)/util
+
+.SUFFIXES: .elf .ihx
+
+.elf.ihx:
+ $(ELFTOHEX) --output=$@ $*.elf
+
+
+ifndef VERSION
+include $(TOPDIR)/Version
+endif
+
+ELFTOHEX=$(TOPDIR)/../ao-tools/ao-elftohex/ao-elftohex
+CC=$(ARM_CC)
+
+AO_CFLAGS=-I. -I$(TOPDIR)/lpc -I$(TOPDIR)/core -I$(TOPDIR)/drivers -I$(TOPDIR)/product -I$(TOPDIR) $(PDCLIB_INCLUDES)
+LPC_CFLAGS=-std=gnu99 -mlittle-endian -mcpu=cortex-m0 -mthumb -ffreestanding -nostdlib $(AO_CFLAGS)
+
+NICKLE=nickle
+
+LIBS=$(PDCLIB_LIBS_M0) -lgcc
+
+V=0
+# The user has explicitly enabled quiet compilation.
+ifeq ($(V),0)
+quiet = @printf " $1 $2 $@\n"; $($1)
+endif
+# Otherwise, print the full command line.
+quiet ?= $($1)
+
+.c.o:
+ $(call quiet,CC) -c $(CFLAGS) -o $@ $<
--- /dev/null
+ifndef TOPDIR
+TOPDIR=..
+endif
+
+include $(TOPDIR)/lpc/Makefile-lpc.defs
+include $(TOPDIR)/Makedefs
+
+LDFLAGS=$(CFLAGS) -L$(TOPDIR)/lpc -Wl,-Taltos.ld
+
+ao_serial_lpc.h: $(TOPDIR)/lpc/baud_rate ao_pins.h
+ nickle $(TOPDIR)/lpc/baud_rate `awk '/AO_LPC_CLKOUT/{print $$3}' ao_pins.h` > $@
+
+ao_serial_lpc.o: ao_serial_lpc.h
+
+.DEFAULT_GOAL=all
--- /dev/null
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+MEMORY {
+ rom : ORIGIN = 0x00000000, LENGTH = 4K
+ ram : ORIGIN = 0x10000000, LENGTH = 4k - 128 - 32
+ usb (!x) : ORIGIN = 0x20004000 + 2K - 256, LENGTH = 256
+ stack (!w) : ORIGIN = 0x10000000 + 4K - 128 - 32, LENGTH = 128
+}
+
+INCLUDE registers.ld
+
+EXTERN (lpc_interrupt_vector)
+
+SECTIONS {
+ /*
+ * Rom contents
+ */
+
+ .interrupt : {
+ __text_start__ = .;
+ *(.interrupt) /* Interrupt vectors */
+
+ } > rom
+
+ .text ORIGIN(rom) + 0x100 : {
+ ao_romconfig.o(.romconfig*)
+ ao_product.o(.romconfig*)
+
+ *(.text*) /* Executable code */
+ *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+ *(.rodata*) /* Constants */
+ __text_end__ = .;
+ } > rom
+
+ /* Boot data which must live at the start of ram so that
+ * the application and bootloader share the same addresses.
+ * This must be all uninitialized data
+ */
+ .boot ORIGIN(ram) + SIZEOF(.interrupt) (NOLOAD) : {
+ __boot_start__ = .;
+ *(.boot*)
+ __boot_end__ = .;
+ } >ram
+
+ /* Data -- relocated to RAM, but written to ROM
+ */
+ .data : {
+ __data_start__ = .;
+ *(.data*) /* initialized data */
+ __data_end__ = .;
+ } >ram AT>rom
+
+
+ .bss : {
+ __bss_start__ = .;
+ *(.bss*)
+ *(COMMON*)
+ __bss_end__ = .;
+ } >ram
+
+ PROVIDE(__stack__ = ORIGIN(ram) + LENGTH(ram));
+ PROVIDE(end = .);
+}
+
+ENTRY(start);
--- /dev/null
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+MEMORY {
+ rom (rx) : ORIGIN = 0x00000000, LENGTH = 32K
+ ram (!w) : ORIGIN = 0x10000000, LENGTH = 4K - 128 - 32
+ usb (!x) : ORIGIN = 0x20004000 + 2K - 256, LENGTH = 256
+ stack (!w) : ORIGIN = 0x10000000 + 4K - 128 - 32, LENGTH = 128
+}
+
+INCLUDE registers.ld
+
+EXTERN (lpc_interrupt_vector)
+
+SECTIONS {
+ /*
+ * Rom contents
+ */
+
+ .text ORIGIN(rom) : {
+ __text_start__ = .;
+ *(.interrupt) /* Interrupt vectors */
+
+ . = ORIGIN(rom) + 0x100;
+
+ ao_romconfig.o(.romconfig*)
+ ao_product.o(.romconfig*)
+
+ *(.text*) /* Executable code */
+ *(.rodata*) /* Constants */
+
+ } > rom
+
+ .ARM.exidx : {
+ *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+ __text_end__ = .;
+ } > rom
+
+ /* Boot data which must live at the start of ram so that
+ * the application and bootloader share the same addresses.
+ * This must be all uninitialized data
+ */
+ .boot (NOLOAD) : {
+ __boot_start__ = .;
+ *(.boot)
+ . = ALIGN(4);
+ __boot_end__ = .;
+ } >ram
+
+ /* Data -- relocated to RAM, but written to ROM
+ */
+ .data ORIGIN(ram) : AT (ADDR(.ARM.exidx) + SIZEOF (.ARM.exidx)) {
+ __data_start__ = .;
+ *(.data) /* initialized data */
+ __data_end__ = .;
+ __bss_start__ = .;
+ } >ram
+
+ .bss : {
+ *(.bss)
+ *(COMMON)
+ __bss_end__ = .;
+ } >ram
+ PROVIDE(end = .);
+
+ PROVIDE(__stack__ = ORIGIN(stack) + LENGTH(stack));
+}
+
+ENTRY(start);
+
+
--- /dev/null
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+MEMORY {
+ rom (rx) : ORIGIN = 0x00001000, LENGTH = 28K
+ ram (!w) : ORIGIN = 0x10000000, LENGTH = 4K - 128
+ usb (!x) : ORIGIN = 0x20004000 + 2K - 256, LENGTH = 256
+ stack (!w) : ORIGIN = 0x10000000 + 4K - 128, LENGTH = 128
+}
+
+INCLUDE registers.ld
+
+EXTERN (lpc_interrupt_vector)
+
+SECTIONS {
+ /*
+ * Rom contents
+ */
+
+ .interrupt ORIGIN(ram) : AT (ORIGIN(rom)) {
+ __interrupt_start__ = .;
+ __interrupt_rom__ = ORIGIN(rom);
+ *(.interrupt) /* Interrupt vectors */
+ __interrupt_end__ = .;
+ } > ram
+
+ .text ORIGIN(rom) + 0x100 : {
+ __text_start__ = .;
+
+ ao_romconfig.o(.romconfig*)
+ ao_product.o(.romconfig*)
+
+ *(.text*) /* Executable code */
+ *(.rodata*) /* Constants */
+
+ } > rom
+
+ .ARM.exidx : {
+ *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+ __text_end__ = .;
+ } > rom
+
+ /* Boot data which must live at the start of ram so that
+ * the application and bootloader share the same addresses.
+ * This must be all uninitialized data
+ */
+ .boot : {
+ __boot_start__ = .;
+ *(.boot)
+ . = ALIGN(4);
+ __boot_end__ = .;
+ } >ram
+
+ /* Data -- relocated to RAM, but written to ROM
+ */
+ .data : AT (ADDR(.ARM.exidx) + SIZEOF (.ARM.exidx)) {
+ __data_start__ = .;
+ *(.data) /* initialized data */
+ __data_end__ = .;
+ __bss_start__ = .;
+ } >ram
+
+ .bss : {
+ __bss_start__ = .;
+ *(.bss)
+ *(COMMON)
+ __bss_end__ = .;
+ } >ram
+ PROVIDE(end = .);
+
+ PROVIDE(__stack__ = ORIGIN(stack) + LENGTH(stack));
+}
+
+ENTRY(start);
+
+
--- /dev/null
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+#include <ao_data.h>
+
+#ifndef AO_ADC_0
+#define AO_ADC_0 0
+#endif
+
+#ifndef AO_ADC_1
+#define AO_ADC_1 0
+#endif
+
+#ifndef AO_ADC_2
+#define AO_ADC_2 0
+#endif
+
+#ifndef AO_ADC_3
+#define AO_ADC_3 0
+#endif
+
+#ifndef AO_ADC_4
+#define AO_ADC_4 0
+#endif
+
+#ifndef AO_ADC_5
+#define AO_ADC_5 0
+#endif
+
+#ifndef AO_ADC_6
+#define AO_ADC_6 0
+#endif
+
+#ifndef AO_ADC_7
+#define AO_ADC_7 0
+#endif
+
+#define AO_ADC_NUM (AO_ADC_0 + AO_ADC_1 + AO_ADC_2 + AO_ADC_3 + \
+ AO_ADC_4 + AO_ADC_5 + AO_ADC_6 + AO_ADC_7)
+
+/* ADC clock is divided by this value + 1, which ensures that
+ * the ADC clock will be strictly less than 4.5MHz as required
+ */
+#define AO_ADC_CLKDIV (AO_LPC_SYSCLK / 450000)
+
+static uint8_t ao_adc_ready;
+static uint8_t ao_adc_sequence;
+
+static const uint8_t ao_adc_mask_seq[AO_ADC_NUM] = {
+#if AO_ADC_0
+ 1 << 0,
+#endif
+#if AO_ADC_1
+ 1 << 1,
+#endif
+#if AO_ADC_2
+ 1 << 2,
+#endif
+#if AO_ADC_3
+ 1 << 3,
+#endif
+#if AO_ADC_4
+ 1 << 4,
+#endif
+#if AO_ADC_5
+ 1 << 6,
+#endif
+#if AO_ADC_6
+ 1 << 6,
+#endif
+#if AO_ADC_7
+ 1 << 7,
+#endif
+};
+
+#define sample(id) (*out++ = (uint16_t) lpc_adc.dr[id] >> 1)
+
+static inline void lpc_adc_start(void) {
+ lpc_adc.cr = ((ao_adc_mask_seq[ao_adc_sequence] << LPC_ADC_CR_SEL) |
+ (AO_ADC_CLKDIV << LPC_ADC_CR_CLKDIV) |
+ (0 << LPC_ADC_CR_BURST) |
+ (LPC_ADC_CR_CLKS_11 << LPC_ADC_CR_CLKS) |
+ (LPC_ADC_CR_START_NOW << LPC_ADC_CR_START));
+}
+
+void lpc_adc_isr(void)
+{
+ uint16_t *out;
+
+ /* Store converted value in packet */
+ out = (uint16_t *) &ao_data_ring[ao_data_head].adc;
+ out[ao_adc_sequence] = (uint16_t) lpc_adc.gdr >> 1;
+ if (++ao_adc_sequence < AO_ADC_NUM) {
+ lpc_adc_start();
+ return;
+ }
+
+ AO_DATA_PRESENT(AO_DATA_ADC);
+ if (ao_data_present == AO_DATA_ALL) {
+#if HAS_MS5607
+ ao_data_ring[ao_data_head].ms5607_raw = ao_ms5607_current;
+#endif
+#if HAS_MMA655X
+ ao_data_ring[ao_data_head].mma655x = ao_mma655x_current;
+#endif
+#if HAS_HMC5883
+ ao_data_ring[ao_data_head].hmc5883 = ao_hmc5883_current;
+#endif
+#if HAS_MPU6000
+ ao_data_ring[ao_data_head].mpu6000 = ao_mpu6000_current;
+#endif
+ ao_data_ring[ao_data_head].tick = ao_tick_count;
+ ao_data_head = ao_data_ring_next(ao_data_head);
+ ao_wakeup((void *) &ao_data_head);
+ }
+ ao_adc_ready = 1;
+}
+
+
+/*
+ * Start the ADC sequence using burst mode
+ */
+void
+ao_adc_poll(void)
+{
+ if (!ao_adc_ready)
+ return;
+ ao_adc_ready = 0;
+ ao_adc_sequence = 0;
+ lpc_adc_start();
+}
+
+static void
+ao_adc_dump(void) __reentrant
+{
+ struct ao_data packet;
+ int16_t *d;
+ uint8_t i;
+
+ ao_data_get(&packet);
+#ifdef AO_ADC_DUMP
+ AO_ADC_DUMP(&packet);
+#else
+ printf("tick: %5u", packet.tick);
+ d = (int16_t *) (&packet.adc);
+ for (i = 0; i < AO_NUM_ADC; i++)
+ printf (" %2d: %5d", i, d[i]);
+ printf("\n");
+#endif
+}
+
+__code struct ao_cmds ao_adc_cmds[] = {
+ { ao_adc_dump, "a\0Display current ADC values" },
+ { 0, NULL },
+};
+
+void
+ao_adc_init(void)
+{
+ lpc_scb.sysahbclkctrl |= (1 << LPC_SCB_SYSAHBCLKCTRL_ADC);
+ lpc_scb.pdruncfg &= ~(1 << LPC_SCB_PDRUNCFG_ADC_PD);
+
+ /* Enable interrupt when channel is complete */
+ lpc_adc.inten = (1 << LPC_ADC_INTEN_ADGINTEN);
+
+ lpc_nvic_set_enable(LPC_ISR_ADC_POS);
+ lpc_nvic_set_priority(LPC_ISR_ADC_POS, AO_LPC_NVIC_CLOCK_PRIORITY);
+#if AO_ADC_0
+ ao_enable_analog(0, 11, 0);
+#endif
+#if AO_ADC_1
+ ao_enable_analog(0, 12, 1);
+#endif
+#if AO_ADC_2
+ ao_enable_analog(0, 13, 2);
+#endif
+#if AO_ADC_3
+ ao_enable_analog(0, 14, 3);
+#endif
+#if AO_ADC_4
+ ao_enable_analog(0, 15, 4);
+#endif
+#if AO_ADC_5
+ ao_enable_analog(0, 16, 5);
+#endif
+#if AO_ADC_6
+ ao_enable_analog(0, 22, 6);
+#endif
+#if AO_ADC_7
+ ao_enable_analog(0, 23, 7);
+#endif
+
+ lpc_adc.cr = ((0 << LPC_ADC_CR_SEL) |
+ (AO_ADC_CLKDIV << LPC_ADC_CR_CLKDIV) |
+ (0 << LPC_ADC_CR_BURST) |
+ (LPC_ADC_CR_CLKS_11 << LPC_ADC_CR_CLKS));
+
+ ao_cmd_register(&ao_adc_cmds[0]);
+
+ ao_adc_ready = 1;
+}
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_ARCH_H_
+#define _AO_ARCH_H_
+
+#include <lpc.h>
+
+/*
+ * LPC11U14 definitions and code fragments for AltOS
+ */
+
+#ifndef AO_STACK_SIZE
+#define AO_STACK_SIZE 512
+#endif
+
+#define AO_LED_TYPE uint16_t
+
+#define AO_PORT_TYPE uint32_t
+
+#ifndef AO_TICK_TYPE
+#define AO_TICK_TYPE uint16_t
+#define AO_TICK_SIGNED int16_t
+#endif
+
+/* Various definitions to make GCC look more like SDCC */
+
+#define ao_arch_naked_declare __attribute__((naked))
+#define ao_arch_naked_define
+#define __pdata
+#define __data
+#define __xdata
+#define __code const
+#define __reentrant
+#define __interrupt(n)
+#define __at(n)
+
+#define ao_arch_reboot() arm_scb.aircr = ((0x05fa << 16) | \
+ (0 << 15) | \
+ (1 << 2) | \
+ (0 << 1))
+
+#define ao_arch_nop() asm("nop")
+
+#define ao_arch_interrupt(n) /* nothing */
+
+#undef putchar
+#undef getchar
+#define putchar(c) ao_putchar(c)
+#define getchar ao_getchar
+
+extern void putchar(char c);
+extern char getchar(void);
+
+/*
+ * ao_romconfig.c
+ */
+
+#define AO_ROMCONFIG_VERSION 2
+
+#define AO_ROMCONFIG_SYMBOL(a) __attribute__((section(".romconfig"))) const
+
+extern const uint16_t ao_romconfig_version;
+extern const uint16_t ao_romconfig_check;
+extern const uint16_t ao_serial_number;
+extern const uint32_t ao_radio_cal;
+
+#define ao_arch_task_members\
+ uint32_t *sp; /* saved stack pointer */
+
+#define ao_arch_block_interrupts() asm("cpsid i")
+#define ao_arch_release_interrupts() asm("cpsie i")
+
+/*
+ * For now, we're running at a weird frequency
+ */
+
+#if AO_HSE
+#define AO_PLLSRC AO_HSE
+#else
+#define AO_PLLSRC STM_HSI_FREQ
+#endif
+
+#define AO_PLLVCO (AO_PLLSRC * AO_PLLMUL)
+#define AO_SYSCLK (AO_PLLVCO / AO_PLLDIV)
+#define AO_HCLK (AO_SYSCLK / AO_AHB_PRESCALER)
+#define AO_PCLK1 (AO_HCLK / AO_APB1_PRESCALER)
+#define AO_PCLK2 (AO_HCLK / AO_APB2_PRESCALER)
+
+#if AO_APB1_PRESCALER == 1
+#define AO_TIM23467_CLK AO_PCLK1
+#else
+#define AO_TIM23467_CLK (2 * AO_PCLK1)
+#endif
+
+#if AO_APB2_PRESCALER == 1
+#define AO_TIM91011_CLK AO_PCLK2
+#else
+#define AO_TIM91011_CLK (2 * AO_PCLK2)
+#endif
+
+#define AO_LPC_NVIC_HIGH_PRIORITY 0
+#define AO_LPC_NVIC_CLOCK_PRIORITY 1
+#define AO_LPC_NVIC_MED_PRIORITY 2
+#define AO_LPC_NVIC_LOW_PRIORITY 3
+
+void
+ao_adc_init(void);
+
+#define AO_USB_OUT_EP 2
+#define AO_USB_IN_EP 3
+
+void
+ao_serial_init(void);
+
+/* SPI definitions */
+
+#define AO_SPI_SPEED_12MHz 4
+#define AO_SPI_SPEED_6MHz 8
+#define AO_SPI_SPEED_4MHz 12
+#define AO_SPI_SPEED_2MHz 24
+#define AO_SPI_SPEED_1MHz 48
+#define AO_SPI_SPEED_500kHz 96
+#define AO_SPI_SPEED_250kHz 192
+
+#define AO_SPI_SPEED_FAST AO_SPI_SPEED_12MHz
+
+#define AO_BOOT_APPLICATION_BASE ((uint32_t *) 0x00001000)
+#define AO_BOOT_LOADER_BASE ((uint32_t *) 0x00000000)
+#define HAS_BOOT_LOADER 1
+
+#endif /* _AO_ARCH_H_ */
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_ARCH_FUNCS_H_
+#define _AO_ARCH_FUNCS_H_
+
+#define ao_spi_get_bit(reg,bit,pin,bus,speed) ao_spi_get_mask(reg,(1<<bit),bus,speed)
+#define ao_spi_put_bit(reg,bit,pin,bus) ao_spi_put_mask(reg,(1<<bit),bus)
+
+#define ao_enable_port(port) (lpc_scb.sysahbclkctrl |= (1 << LPC_SCB_SYSAHBCLKCTRL_GPIO))
+#define ao_disable_port(port) (lpc_scb.sysahbclkctrl &= ~(1 << LPC_SCB_SYSAHBCLKCTRL_GPIO))
+
+#define lpc_all_bit(port,bit) (((port) << 5) | (bit))
+
+#define ao_gpio_set(port, bit, pin, v) (lpc_gpio.byte[lpc_all_bit(port,bit)] = (v))
+
+#define ao_gpio_get(port, bit, pin) (lpc_gpio.byte[lpc_all_bit(port,bit)])
+
+#define ao_enable_output(port,bit,pin,v) do { \
+ ao_enable_port(port); \
+ ao_gpio_set(port, bit, pin, v); \
+ lpc_gpio.dir[port] |= (1 << bit); \
+ } while (0)
+
+#define ao_gpio_set_mode(port,bit,mode) do { \
+ vuint32_t *_ioconf = &lpc_ioconf.pio0_0 + ((port)*24+(bit)); \
+ vuint32_t _mode; \
+ if (mode == AO_EXTI_MODE_PULL_UP) \
+ _mode = LPC_IOCONF_MODE_PULL_UP << LPC_IOCONF_MODE; \
+ else if (mode == AO_EXTI_MODE_PULL_DOWN) \
+ _mode = LPC_IOCONF_MODE_PULL_UP << LPC_IOCONF_MODE; \
+ else \
+ _mode = LPC_IOCONF_MODE_INACTIVE << LPC_IOCONF_MODE; \
+ *_ioconf = ((*_ioconf & ~(LPC_IOCONF_MODE_MASK << LPC_IOCONF_MODE)) | \
+ _mode | \
+ (1 << LPC_IOCONF_ADMODE)); \
+ } while (0)
+
+#define ao_enable_input(port,bit,mode) do { \
+ ao_enable_port(port); \
+ lpc_gpio.dir[port] &= ~(1 << bit); \
+ ao_gpio_set_mode(port,bit,mode); \
+ } while (0)
+
+#define lpc_token_paster_2(x,y) x ## y
+#define lpc_token_evaluator_2(x,y) lpc_token_paster_2(x,y)
+#define lpc_token_paster_3(x,y,z) x ## y ## z
+#define lpc_token_evaluator_3(x,y,z) lpc_token_paster_3(x,y,z)
+#define lpc_token_paster_4(w,x,y,z) w ## x ## y ## z
+#define lpc_token_evaluator_4(w,x,y,z) lpc_token_paster_4(w,x,y,z)
+#define analog_reg(port,bit) lpc_token_evaluator_4(pio,port,_,bit)
+#define analog_func(id) lpc_token_evaluator_2(LPC_IOCONF_FUNC_AD,id)
+
+#define ao_enable_analog(port,bit,id) do { \
+ ao_enable_port(port); \
+ lpc_gpio.dir[port] &= ~(1 << bit); \
+ lpc_ioconf.analog_reg(port,bit) = ((analog_func(id) << LPC_IOCONF_FUNC) | \
+ (0 << LPC_IOCONF_ADMODE)); \
+ } while (0)
+
+#define ARM_PUSH32(stack, val) (*(--(stack)) = (val))
+
+static inline uint32_t
+ao_arch_irqsave(void) {
+ uint32_t primask;
+ asm("mrs %0,primask" : "=&r" (primask));
+ ao_arch_block_interrupts();
+ return primask;
+}
+
+static inline void
+ao_arch_irqrestore(uint32_t primask) {
+ asm("msr primask,%0" : : "r" (primask));
+}
+
+static inline void
+ao_arch_memory_barrier() {
+ asm volatile("" ::: "memory");
+}
+
+#if HAS_TASK
+static inline void
+ao_arch_init_stack(struct ao_task *task, void *start)
+{
+ uint32_t *sp = (uint32_t *) (task->stack + AO_STACK_SIZE);
+ uint32_t a = (uint32_t) start;
+ int i;
+
+ /* Return address (goes into LR) */
+ ARM_PUSH32(sp, a);
+
+ /* Clear register values r0-r7 */
+ i = 8;
+ while (i--)
+ ARM_PUSH32(sp, 0);
+
+ /* APSR */
+ ARM_PUSH32(sp, 0);
+
+ /* PRIMASK with interrupts enabled */
+ ARM_PUSH32(sp, 0);
+
+ task->sp = sp;
+}
+
+static inline void ao_arch_save_regs(void) {
+ /* Save general registers */
+ asm("push {r0-r7,lr}\n");
+
+ /* Save APSR */
+ asm("mrs r0,apsr");
+ asm("push {r0}");
+
+ /* Save PRIMASK */
+ asm("mrs r0,primask");
+ asm("push {r0}");
+}
+
+static inline void ao_arch_save_stack(void) {
+ uint32_t *sp;
+ asm("mov %0,sp" : "=&r" (sp) );
+ ao_cur_task->sp = (sp);
+ if ((uint8_t *) sp < &ao_cur_task->stack[0])
+ ao_panic (AO_PANIC_STACK);
+}
+
+static inline void ao_arch_restore_stack(void) {
+ uint32_t sp;
+ sp = (uint32_t) ao_cur_task->sp;
+
+ /* Switch stacks */
+ asm("mov sp, %0" : : "r" (sp) );
+
+ /* Restore PRIMASK */
+ asm("pop {r0}");
+ asm("msr primask,r0");
+
+ /* Restore APSR */
+ asm("pop {r0}");
+ asm("msr apsr_nczvq,r0");
+
+ /* Restore general registers and return */
+ asm("pop {r0-r7,pc}\n");
+}
+
+#define ao_arch_isr_stack()
+
+#endif /* HAS_TASK */
+
+#define ao_arch_wait_interrupt() do { \
+ asm(".global ao_idle_loc\n\twfi\nao_idle_loc:"); \
+ ao_arch_release_interrupts(); \
+ ao_arch_block_interrupts(); \
+ } while (0)
+
+#define ao_arch_critical(b) do { \
+ ao_arch_block_interrupts(); \
+ do { b } while (0); \
+ ao_arch_release_interrupts(); \
+ } while (0)
+
+/*
+ * SPI
+ */
+
+#define ao_spi_set_cs(port,mask) (lpc_gpio.clr[port] = (mask))
+#define ao_spi_clr_cs(port,mask) (lpc_gpio.set[port] = (mask))
+
+#define ao_spi_get_mask(port,mask,bus,speed) do { \
+ ao_spi_get(bus, speed); \
+ ao_spi_set_cs(port, mask); \
+ } while (0)
+
+#define ao_spi_put_mask(reg,mask,bus) do { \
+ ao_spi_clr_cs(reg,mask); \
+ ao_spi_put(bus); \
+ } while (0)
+
+#define ao_spi_get_bit(reg,bit,pin,bus,speed) ao_spi_get_mask(reg,(1<<bit),bus,speed)
+#define ao_spi_put_bit(reg,bit,pin,bus) ao_spi_put_mask(reg,(1<<bit),bus)
+
+void
+ao_spi_get(uint8_t spi_index, uint32_t speed);
+
+void
+ao_spi_put(uint8_t spi_index);
+
+void
+ao_spi_send(void *block, uint16_t len, uint8_t spi_index);
+
+void
+ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t spi_index);
+
+void
+ao_spi_recv(void *block, uint16_t len, uint8_t spi_index);
+
+void
+ao_spi_duplex(void *out, void *in, uint16_t len, uint8_t spi_index);
+
+extern uint16_t ao_spi_speed[LPC_NUM_SPI];
+
+void
+ao_spi_init(void);
+
+#define ao_spi_init_cs(port, mask) do { \
+ uint8_t __bit__; \
+ for (__bit__ = 0; __bit__ < 32; __bit__++) { \
+ if (mask & (1 << __bit__)) \
+ ao_enable_output(port, __bit__, PIN, 1); \
+ } \
+ } while (0)
+
+#define HAS_ARCH_START_SCHEDULER 1
+
+static inline void ao_arch_start_scheduler(void) {
+ uint32_t sp;
+ uint32_t control;
+
+ asm("mrs %0,msp" : "=&r" (sp));
+ asm("msr psp,%0" : : "r" (sp));
+ asm("mrs %0,control" : "=&r" (control));
+ control |= (1 << 1);
+ asm("msr control,%0" : : "r" (control));
+ asm("isb");
+}
+
+#endif /* _AO_ARCH_FUNCS_H_ */
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+
+void
+ao_beep(uint8_t beep)
+{
+ if (beep == 0) {
+ lpc_ct32b1.tcr = ((0 << LPC_CT32B_TCR_CEN) |
+ (1 << LPC_CT32B_TCR_CRST));
+ lpc_scb.sysahbclkctrl &= ~(1 << LPC_SCB_SYSAHBCLKCTRL_CT32B1);
+ } else {
+ lpc_scb.sysahbclkctrl |= (1 << LPC_SCB_SYSAHBCLKCTRL_CT32B1);
+
+ /* Set prescaler to match cc1111 clocks
+ */
+ lpc_ct32b1.pr = AO_LPC_SYSCLK / 750000 - 1;
+
+ /* Write the desired data in the match registers */
+
+ /* Reset after two time units */
+ lpc_ct32b1.mr[0] = beep << 1;
+
+ /* PWM width is half of that */
+ lpc_ct32b1.mr[1] = beep;
+
+ /* Flip output 1 on PWM match */
+ lpc_ct32b1.emr = (LPC_CT32B_EMR_EMC_TOGGLE << LPC_CT32B_EMR_EMC1);
+
+ /* Reset on match 0 */
+ lpc_ct32b1.mcr = (1 << LPC_CT32B_MCR_MR0R);
+
+ /* PWM on match 1 */
+ lpc_ct32b1.pwmc = (1 << LPC_CT32B_PWMC_PWMEN1);
+
+ /* timer mode */
+ lpc_ct32b1.ctcr = 0;
+
+ /* And turn the timer on */
+ lpc_ct32b1.tcr = ((1 << LPC_CT32B_TCR_CEN) |
+ (0 << LPC_CT32B_TCR_CRST));
+ }
+}
+
+void
+ao_beep_for(uint8_t beep, uint16_t ticks) __reentrant
+{
+ ao_beep(beep);
+ ao_delay(ticks);
+ ao_beep(0);
+}
+
+void
+ao_beep_init(void)
+{
+ /* Our beeper is on c32b1_mat1
+ * which is on pin pio0_14
+ */
+
+ lpc_ioconf.pio0_14 = ((LPC_IOCONF_FUNC_PIO0_14_CT32B1_MAT1 << LPC_IOCONF_FUNC) |
+ (LPC_IOCONF_MODE_INACTIVE << LPC_IOCONF_MODE) |
+ (0 << LPC_IOCONF_HYS) |
+ (0 << LPC_IOCONF_INV) |
+ (1 << LPC_IOCONF_ADMODE) |
+ (0 << LPC_IOCONF_OD));
+
+ lpc_scb.sysahbclkctrl |= (1 << LPC_SCB_SYSAHBCLKCTRL_CT32B1);
+
+ /* Disable the counter and reset the value */
+ lpc_ct32b1.tcr = ((0 << LPC_CT32B_TCR_CEN) |
+ (1 << LPC_CT32B_TCR_CRST));
+}
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_BOOT_H_
+#define _AO_BOOT_H_
+
+void
+ao_boot_chain(uint32_t *base);
+
+void
+ao_boot_check_pin(void);
+
+/* Return true to switch to application (if present) */
+int
+ao_boot_check_chain(void);
+
+void
+ao_boot_reboot(uint32_t *base);
+
+static inline void
+ao_boot_loader(void) {
+ ao_boot_reboot(AO_BOOT_LOADER_BASE);
+}
+
+#endif /* _AO_BOOT_H_ */
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+#include <ao_boot.h>
+
+void
+ao_boot_chain(uint32_t *base)
+{
+ uint32_t sp;
+ uint32_t pc;
+
+ sp = base[0];
+ pc = base[1];
+ if (0x00000100 <= pc && pc <= 0x00008000 && (pc & 1) == 1) {
+ asm ("mov sp, %0" : : "r" (sp));
+ asm ("mov lr, %0" : : "r" (pc));
+ asm ("bx lr");
+ }
+}
+
+#define AO_BOOT_SIGNAL 0x5a5aa5a5
+#define AO_BOOT_CHECK 0xc3c33c3c
+
+struct ao_boot {
+ uint32_t *base;
+ uint32_t signal;
+ uint32_t check;
+};
+
+static struct ao_boot __attribute__ ((section(".boot"))) ao_boot;
+
+int
+ao_boot_check_chain(void)
+{
+ if (ao_boot.signal == AO_BOOT_SIGNAL && ao_boot.check == AO_BOOT_CHECK) {
+ ao_boot.signal = 0;
+ ao_boot.check = 0;
+ if (ao_boot.base == 0)
+ return 0;
+ ao_boot_chain(ao_boot.base);
+ }
+ return 1;
+}
+
+void
+ao_boot_reboot(uint32_t *base)
+{
+ ao_boot.base = base;
+ ao_boot.signal = AO_BOOT_SIGNAL;
+ ao_boot.check = AO_BOOT_CHECK;
+ ao_arch_reboot();
+}
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+#include <ao_boot.h>
+#include <ao_exti.h>
+
+void
+ao_boot_check_pin(void)
+{
+ uint16_t v;
+
+ /* Enable power interface clock */
+// stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_PWREN);
+
+ /* Enable the input pin */
+ ao_enable_input(AO_BOOT_APPLICATION_GPIO, AO_BOOT_APPLICATION_PIN,
+ AO_BOOT_APPLICATION_MODE);
+
+ for (v = 0; v < 100; v++)
+ ao_arch_nop();
+
+ /* Read the value */
+ v = ao_gpio_get(AO_BOOT_APPLICATION_GPIO, AO_BOOT_APPLICATION_PIN, AO_BOOT_APPLICATION);
+
+ /* Reset the chip to turn off the port and the power interface clock */
+ ao_gpio_set_mode(AO_BOOT_APPLICATION_GPIO, AO_BOOT_APPLICATION_PIN, 0);
+ ao_disable_port(AO_BOOT_APPLICATION_GPIO);
+// stm_rcc.apb1enr &= ~(1 << STM_RCC_APB1ENR_PWREN);
+ if (v == AO_BOOT_APPLICATION_VALUE)
+ ao_boot_chain(AO_BOOT_APPLICATION_BASE);
+}
--- /dev/null
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_EXTI_H_
+#define _AO_EXTI_H_
+
+#define AO_EXTI_MODE_RISING 1
+#define AO_EXTI_MODE_FALLING 2
+#define AO_EXTI_MODE_PULL_UP 4
+#define AO_EXTI_MODE_PULL_DOWN 8
+#define AO_EXTI_PRIORITY_LOW 16
+#define AO_EXTI_PRIORITY_MED 0
+#define AO_EXTI_PRIORITY_HIGH 32
+#define AO_EXTI_PIN_NOCONFIGURE 64
+
+void
+ao_exti_setup(uint8_t gpio, uint8_t pin, uint8_t mode, void (*callback)());
+
+void
+ao_exti_set_mode(uint8_t gpio, uint8_t pin, uint8_t mode);
+
+void
+ao_exti_set_callback(uint8_t gpio, uint8_t pin, void (*callback)());
+
+void
+ao_exti_enable(uint8_t gpio, uint8_t pin);
+
+void
+ao_exti_disable(uint8_t gpio, uint8_t pin);
+
+void
+ao_exti_init(void);
+
+#endif /* _AO_EXTI_H_ */
--- /dev/null
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+#include <ao_exti.h>
+
+#define LPC_NUM_PINS 56
+#define LPC_NUM_PINT 8
+
+static void (*ao_exti_callback[LPC_NUM_PINT])(void);
+
+static uint8_t ao_pint_map[LPC_NUM_PINS];
+static uint8_t ao_pint_mode[LPC_NUM_PINS];
+static uint8_t ao_pint_inuse;
+static uint8_t ao_pint_enabled;
+
+static void
+ao_exti_isr(uint8_t pint)
+{
+ uint8_t mask = 1 << pint;
+
+ if (lpc_gpio_pin.ist & mask) {
+ lpc_gpio_pin.ist = mask;
+ lpc_gpio_pin.rise = mask;
+ lpc_gpio_pin.fall = mask;
+
+ (*ao_exti_callback[pint]) ();
+ }
+}
+
+#define pin_isr(n) void lpc_pin_int ## n ## _isr(void) { ao_exti_isr(n); }
+pin_isr(0)
+pin_isr(1)
+pin_isr(2)
+pin_isr(3)
+pin_isr(4)
+pin_isr(5)
+pin_isr(6)
+pin_isr(7)
+
+#define pin_id(port,pin) ((port) * 24 + (pin));
+
+static void
+_ao_exti_set_enable(uint8_t pint)
+{
+ uint8_t mask = 1 << pint;
+ uint8_t mode;
+
+ if (ao_pint_enabled & mask)
+ mode = ao_pint_mode[pint];
+ else
+ mode = 0;
+
+ if (mode & AO_EXTI_MODE_RISING)
+ lpc_gpio_pin.sienr = mask;
+ else
+ lpc_gpio_pin.cienr = mask;
+
+ if (mode & AO_EXTI_MODE_FALLING)
+ lpc_gpio_pin.sienf = mask;
+ else
+ lpc_gpio_pin.cienf = mask;
+ lpc_gpio_pin.rise = mask;
+ lpc_gpio_pin.fall = mask;
+}
+
+void
+ao_exti_setup (uint8_t port, uint8_t pin, uint8_t mode, void (*callback)(void)) {
+ uint8_t id = pin_id(port,pin);
+ uint8_t pint;
+ uint32_t mask;
+ uint8_t prio;
+
+ for (pint = 0; pint < LPC_NUM_PINT; pint++)
+ if ((ao_pint_inuse & (1 << pint)) == 0)
+ break;
+ if (pint == LPC_NUM_PINT)
+ ao_panic(AO_PANIC_EXTI);
+
+ if (!mode & AO_EXTI_PIN_NOCONFIGURE)
+ ao_enable_input(port, pin, mode);
+
+ ao_arch_block_interrupts();
+ mask = (1 << pint);
+ ao_pint_inuse |= mask;
+ ao_pint_enabled &= ~mask;
+
+ ao_pint_map[id] = pint;
+ ao_exti_callback[pint] = callback;
+
+ /* configure gpio to interrupt routing */
+ lpc_scb.pintsel[pint] = id;
+
+ /* Set edge triggered */
+ lpc_gpio_pin.isel &= ~mask;
+
+ ao_pint_enabled &= ~mask;
+ ao_pint_mode[pint] = mode;
+ _ao_exti_set_enable(pint);
+
+ /* Set interrupt mask and rising/falling mode */
+
+ prio = AO_LPC_NVIC_MED_PRIORITY;
+ if (mode & AO_EXTI_PRIORITY_LOW)
+ prio = AO_LPC_NVIC_LOW_PRIORITY;
+ else if (mode & AO_EXTI_PRIORITY_HIGH)
+ prio = AO_LPC_NVIC_HIGH_PRIORITY;
+
+ /* Set priority and enable */
+ lpc_nvic_set_priority(LPC_ISR_PIN_INT0_POS + pint, prio);
+ lpc_nvic_set_enable(LPC_ISR_PIN_INT0_POS + pint);
+ ao_arch_release_interrupts();
+}
+
+void
+ao_exti_set_mode(uint8_t port, uint8_t pin, uint8_t mode)
+{
+ uint8_t id = pin_id(port,pin);
+ uint8_t pint = ao_pint_map[id];
+
+ ao_arch_block_interrupts();
+ ao_pint_mode[pint] = mode;
+ _ao_exti_set_enable(pint);
+ ao_arch_release_interrupts();
+}
+
+void
+ao_exti_set_callback(uint8_t port, uint8_t pin, void (*callback)()) {
+ uint8_t id = pin_id(port,pin);
+ uint8_t pint = ao_pint_map[id];
+
+ ao_exti_callback[pint] = callback;
+}
+
+void
+ao_exti_enable(uint8_t port, uint8_t pin)
+{
+ uint8_t id = pin_id(port,pin);
+ uint8_t pint = ao_pint_map[id];
+ uint8_t mask = 1 << pint;
+
+ ao_arch_block_interrupts();
+ ao_pint_enabled |= mask;
+ _ao_exti_set_enable(pint);
+ ao_arch_release_interrupts();
+}
+
+void
+ao_exti_disable(uint8_t port, uint8_t pin) {
+ uint8_t id = pin_id(port,pin);
+ uint8_t pint = ao_pint_map[id];
+ uint8_t mask = 1 << pint;
+
+ ao_arch_block_interrupts();
+ ao_pint_enabled &= ~mask;
+ _ao_exti_set_enable(pint);
+ ao_arch_release_interrupts();
+}
+
+void
+ao_exti_init(void)
+{
+ lpc_scb.sysahbclkctrl |= (1 << LPC_SCB_SYSAHBCLKCTRL_PINT);
+}
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_FLASH_H_
+#define _AO_FLASH_H_
+
+uint32_t
+ao_flash_erase_page(uint8_t *page);
+
+uint32_t
+ao_flash_page(uint8_t *page, uint8_t *src);
+
+uint32_t
+ao_lpc_read_part_id(void);
+
+#endif /* _AO_FLASH_H_ */
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+#include <ao_exti.h>
+#include <ao_boot.h>
+#include <ao_flash_task.h>
+
+int
+main(void)
+{
+ ao_clock_init();
+
+ ao_usb_init();
+
+ ao_flash_task();
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+#include <ao_flash.h>
+
+#define IAP_LOCATION 0x1fff1ff1
+
+typedef void (*iap_func)(uint32_t *in, uint32_t *out);
+
+static void
+iap(uint32_t *in, uint32_t *out)
+{
+ ao_arch_block_interrupts();
+ lpc_scb.sysahbclkctrl |= (1 << LPC_SCB_SYSAHBCLKCTRL_FLASHREG);
+ ((iap_func) IAP_LOCATION)(in, out);
+ ao_arch_release_interrupts();
+}
+
+#define LPC_IAP_PREPARE_WRITE 50
+#define LPC_IAP_COPY_RAM_TO_FLASH 51
+#define LPC_IAP_ERASE_SECTOR 52
+#define LPC_IAP_BLANK_CHECK 53
+#define LPC_IAP_READ_PART_ID 54
+#define LPC_IAP_READ_BOOT_CODE_VERSION 55
+#define LPC_IAP_COMPARE 56
+#define LPC_IAP_REINVOKE_ISP 57
+#define LPC_IAP_READ_UID 58
+#define LPC_IAP_ERASE_PAGE 59
+#define LPC_IAP_EEPROM_WRITE 61
+#define LPC_IAP_EEPROM_READ 62
+
+#define LPC_IAP_CMD_SUCCESS 0
+#define LPC_IAP_INVALID_COMMAND 1
+#define LPC_IAP_SRC_ADDR_ERROR 2
+#define LPC_IAP_DST_ADDR_ERROR 3
+#define LPC_IAP_SRC_ADDR_NOT_MAPPED 4
+#define LPC_IAP_DST_ADDR_NOT_MAPPED 5
+#define LPC_IAP_COUNT_ERROR 6
+#define LPC_IAP_INVALID_SECTOR 7
+#define LPC_IAP_SECTOR_NOT_BLANK 8
+#define LPC_IAP_SECTOR_NOT_PREPARED_FOR_WRITE_OPERATION 9
+#define LPC_IAP_COMPARE_ERROR 10
+#define LPC_IAP_BUSY 11
+#define LPC_IAP_PARAM_ERROR 12
+#define LPC_IAP_ADDR_ERROR 13
+#define LPC_IAP_ADDR_NOT_MAPPED 14
+#define LPC_IAP_CMD_LOCKED 15
+#define LPC_IAP_INVALID_CODE 16
+#define LPC_IAP_INVALID_BAUD_RATE 17
+#define LPC_IAP_INVALID_STOP_BIT 18
+#define LPC_IAP_CODE_READ_PROTECTION_ENABLED 19
+
+#define LPC_FLASH_BASE ((uint8_t *) 0x0)
+#define LPC_FLASH_SECTOR 4096
+#define LPC_FLASH_SECTOR_MASK (LPC_FLASH_SECTOR - 1)
+#define LPC_FLASH_SECTOR_SHIFT 12
+
+static uint32_t iap_in[5], iap_out[5];
+
+static uint32_t
+ao_lpc_addr_to_sector(uint8_t *addr)
+{
+ uint32_t off = addr - LPC_FLASH_BASE;
+
+ return off >> LPC_FLASH_SECTOR_SHIFT;
+}
+
+static uint8_t
+ao_lpc_addr_is_sector_aligned(uint8_t *addr)
+{
+ uint32_t off = addr - LPC_FLASH_BASE;
+ return (off & LPC_FLASH_SECTOR_MASK) == 0;
+}
+
+static uint32_t
+ao_lpc_prepare_write(uint32_t start_sector, uint32_t end_sector)
+{
+ iap_in[0] = LPC_IAP_PREPARE_WRITE;
+ iap_in[1] = start_sector;
+ iap_in[2] = end_sector;
+ iap(iap_in,iap_out);
+ return iap_out[0];
+}
+
+static uint32_t
+ao_lpc_copy_ram_to_flash(uint8_t *dst, uint8_t *src, uint32_t len, uint32_t freq)
+{
+ iap_in[0] = LPC_IAP_COPY_RAM_TO_FLASH;
+ iap_in[1] = (uint32_t) dst;
+ iap_in[2] = (uint32_t) src;
+ iap_in[3] = len;
+ iap_in[4] = freq;
+ iap(iap_in,iap_out);
+ return iap_out[0];
+}
+
+static uint32_t
+ao_lpc_erase_sector(uint32_t start_sector, uint32_t end_sector, uint32_t freq)
+{
+ iap_in[0] = LPC_IAP_ERASE_SECTOR;
+ iap_in[1] = start_sector;
+ iap_in[2] = end_sector;
+ iap_in[3] = freq;
+ iap(iap_in,iap_out);
+ return iap_out[0];
+}
+
+uint32_t
+ao_lpc_read_part_id(void)
+{
+ iap_in[0] = LPC_IAP_READ_PART_ID;
+ iap(iap_in,iap_out);
+ return iap_out[1];
+}
+
+uint32_t
+ao_flash_erase_page(uint8_t *page)
+{
+ uint32_t ret = LPC_IAP_CMD_SUCCESS;
+ if (ao_lpc_addr_is_sector_aligned(page)) {
+ uint32_t sector = ao_lpc_addr_to_sector(page);
+ ret = ao_lpc_prepare_write(sector, sector);
+ if (ret == LPC_IAP_CMD_SUCCESS)
+ ret = ao_lpc_erase_sector(sector, sector, AO_LPC_SYSCLK / 1000);
+ }
+ return ret;
+}
+
+uint32_t
+ao_flash_page(uint8_t *page, uint8_t *src)
+{
+ uint32_t sector = ao_lpc_addr_to_sector(page);
+ uint32_t ret;
+
+ ret = ao_flash_erase_page(page);
+ if (ret != LPC_IAP_CMD_SUCCESS)
+ return ret;
+ ret = ao_lpc_prepare_write(sector, sector);
+ if (ret != LPC_IAP_CMD_SUCCESS)
+ return ret;
+ ret = ao_lpc_copy_ram_to_flash(page, src, 256, AO_LPC_SYSCLK / 1000);
+ return ret;
+}
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_FLASH_LPC_PINS_H_
+#define _AO_FLASH_LPC_PINS_H_
+
+#include <ao_flash_pins.h>
+
+/* Crystal on the board */
+#define AO_LPC_CLKIN 12000000
+
+/* Main clock frequency. 48MHz for USB so we don't use the USB PLL */
+#define AO_LPC_CLKOUT 48000000
+
+/* System clock frequency */
+#define AO_LPC_SYSCLK 24000000
+
+#endif /* _AO_FLASH_STM_PINS_H_ */
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+#include <string.h>
+#include <ao_boot.h>
+
+#ifndef IS_FLASH_LOADER
+#error Should define IS_FLASH_LOADER
+#define IS_FLASH_LOADER 0
+#endif
+
+#if !IS_FLASH_LOADER
+#define RELOCATE_INTERRUPT 1
+#endif
+
+extern void main(void);
+extern char __stack__;
+extern char __text_start__, __text_end__;
+extern char __data_start__, __data_end__;
+extern char __bss_start__, __bss_end__;
+#if RELOCATE_INTERRUPT
+extern char __interrupt_rom__, __interrupt_start__, __interrupt_end__;
+#endif
+
+/* Interrupt functions */
+
+void lpc_halt_isr(void)
+{
+ ao_panic(AO_PANIC_CRASH);
+}
+
+void lpc_ignore_isr(void)
+{
+}
+
+void start(void) {
+#ifdef AO_BOOT_CHAIN
+ if (ao_boot_check_chain()) {
+#ifdef AO_BOOT_PIN
+ ao_boot_check_pin();
+#endif
+ }
+#endif
+#if RELOCATE_INTERRUPT
+ memcpy(&__interrupt_start__, &__interrupt_rom__, &__interrupt_end__ - &__interrupt_start__);
+ lpc_scb.sysmemremap = LPC_SCB_SYSMEMREMAP_MAP_RAM << LPC_SCB_SYSMEMREMAP_MAP;
+#endif
+ memcpy(&__data_start__, &__text_end__, &__data_end__ - &__data_start__);
+ memset(&__bss_start__, '\0', &__bss_end__ - &__bss_start__);
+ main();
+}
+
+#define STRINGIFY(x) #x
+
+#define isr(name) \
+ void __attribute__ ((weak)) lpc_ ## name ## _isr(void); \
+ _Pragma(STRINGIFY(weak lpc_ ## name ## _isr = lpc_ignore_isr))
+
+#define isr_halt(name) \
+ void __attribute__ ((weak)) lpc_ ## name ## _isr(void); \
+ _Pragma(STRINGIFY(weak lpc_ ## name ## _isr = lpc_halt_isr))
+
+isr(nmi)
+isr_halt(hardfault)
+isr_halt(memmanage)
+isr_halt(busfault)
+isr_halt(usagefault)
+isr(svc)
+isr(debugmon)
+isr(pendsv)
+isr(systick)
+
+isr(pin_int0) /* IRQ0 */
+isr(pin_int1)
+isr(pin_int2)
+isr(pin_int3)
+isr(pin_int4) /* IRQ4 */
+isr(pin_int5)
+isr(pin_int6)
+isr(pin_int7)
+
+isr(gint0) /* IRQ8 */
+isr(gint1)
+isr(ssp1)
+isr(i2c)
+
+isr(ct16b0) /* IRQ16 */
+isr(ct16b1)
+isr(ct32b0)
+isr(ct32b1)
+isr(ssp0) /* IRQ20 */
+isr(usart)
+isr(usb_irq)
+isr(usb_fiq)
+
+isr(adc) /* IRQ24 */
+isr(wwdt)
+isr(bod)
+isr(flash)
+
+isr(usb_wakeup)
+
+#define i(addr,name) [(addr)/4] = lpc_ ## name ## _isr
+#define c(addr,value) [(addr)/4] = (value)
+
+__attribute__ ((section(".interrupt")))
+const void *lpc_interrupt_vector[] = {
+ [0] = &__stack__,
+ [1] = start,
+ i(0x08, nmi),
+ i(0x0c, hardfault),
+ c(0x10, 0),
+ c(0x14, 0),
+ c(0x18, 0),
+ c(0x1c, 0),
+ c(0x20, 0),
+ c(0x24, 0),
+ c(0x28, 0),
+ i(0x2c, svc),
+ i(0x30, hardfault),
+ i(0x34, hardfault),
+ i(0x38, pendsv),
+ i(0x3c, systick),
+
+ i(0x40, pin_int0), /* IRQ0 */
+ i(0x44, pin_int1),
+ i(0x48, pin_int2),
+ i(0x4c, pin_int3),
+ i(0x50, pin_int4), /* IRQ4 */
+ i(0x54, pin_int5),
+ i(0x58, pin_int6),
+ i(0x5c, pin_int7),
+
+ i(0x60, gint0), /* IRQ8 */
+ i(0x64, gint1),
+ i(0x68, hardfault),
+ i(0x6c, hardfault),
+ i(0x70, hardfault), /* IRQ12 */
+ i(0x74, hardfault),
+ i(0x78, ssp1),
+ i(0x7c, i2c),
+
+ i(0x80, ct16b0), /* IRQ16 */
+ i(0x84, ct16b1),
+ i(0x88, ct32b0),
+ i(0x8c, ct32b1),
+ i(0x90, ssp0), /* IRQ20 */
+ i(0x94, usart),
+ i(0x98, usb_irq),
+ i(0x9c, usb_fiq),
+
+ i(0xa0, adc), /* IRQ24 */
+ i(0xa4, wwdt),
+ i(0xa8, bod),
+ i(0xac, flash),
+
+ i(0xb0, hardfault), /* IRQ28 */
+ i(0xb4, hardfault),
+ i(0xb8, usb_wakeup),
+ i(0xbc, hardfault),
+};
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+
+__pdata uint16_t ao_led_enable;
+
+void
+ao_led_on(uint16_t colors)
+{
+ lpc_gpio.pin[LED_PORT] |= colors;
+}
+
+void
+ao_led_off(uint16_t colors)
+{
+ lpc_gpio.pin[LED_PORT] &= ~colors;
+}
+
+void
+ao_led_set(uint16_t colors)
+{
+ uint16_t on = colors & ao_led_enable;
+ uint16_t off = ~colors & ao_led_enable;
+
+ ao_led_off(off);
+ ao_led_on(on);
+}
+
+void
+ao_led_toggle(uint16_t colors)
+{
+ lpc_gpio.pin[LED_PORT] ^= colors;
+}
+
+void
+ao_led_for(uint16_t colors, uint16_t ticks) __reentrant
+{
+ ao_led_on(colors);
+ ao_delay(ticks);
+ ao_led_off(colors);
+}
+
+void
+ao_led_init(uint16_t enable)
+{
+ int bit;
+
+ ao_led_enable = enable;
+ lpc_scb.sysahbclkctrl |= (1 << LPC_SCB_SYSAHBCLKCTRL_GPIO);
+ lpc_gpio.dir[LED_PORT] |= enable;
+}
--- /dev/null
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+
+AO_ROMCONFIG_SYMBOL (0) uint16_t ao_romconfig_version = AO_ROMCONFIG_VERSION;
+AO_ROMCONFIG_SYMBOL (0) uint16_t ao_romconfig_check = ~AO_ROMCONFIG_VERSION;
+AO_ROMCONFIG_SYMBOL (0) uint16_t ao_serial_number = 0;
+#ifdef AO_RADIO_CAL_DEFAULT
+AO_ROMCONFIG_SYMBOL (0) uint32_t ao_radio_cal = AO_RADIO_CAL_DEFAULT;
+#endif
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+#include <ao_serial.h>
+
+struct ao_fifo ao_usart_rx_fifo;
+struct ao_fifo ao_usart_tx_fifo;
+uint8_t ao_usart_tx_avail;
+uint8_t ao_usart_tx_avail_min;
+
+#define LPC_USART_TX_FIFO_SIZE 16
+
+void
+ao_debug_out(char c)
+{
+ if (c == '\n')
+ ao_debug_out('\r');
+ while (!(lpc_usart.lsr & (1 << LPC_USART_LSR_TEMT)))
+ ;
+ lpc_usart.rbr_thr = c;
+}
+
+static void
+_ao_serial_tx_start(void)
+{
+ if (!ao_fifo_empty(ao_usart_tx_fifo) && ao_usart_tx_avail) {
+ ao_usart_tx_avail--;
+ if (ao_usart_tx_avail < ao_usart_tx_avail_min)
+ ao_usart_tx_avail_min = ao_usart_tx_avail;
+ ao_fifo_remove(ao_usart_tx_fifo, lpc_usart.rbr_thr);
+ }
+}
+
+void
+lpc_usart_isr(void)
+{
+ uint8_t wake_input = 0;
+ (void) lpc_usart.iir_fcr;
+
+ while (lpc_usart.lsr & (1 << LPC_USART_LSR_RDR)) {
+ char c = lpc_usart.rbr_thr;
+ if (!ao_fifo_full(ao_usart_rx_fifo))
+ ao_fifo_insert(ao_usart_rx_fifo, c);
+ wake_input = 1;
+ }
+ if (lpc_usart.lsr & (1 << LPC_USART_LSR_THRE)) {
+ ao_usart_tx_avail = LPC_USART_TX_FIFO_SIZE;
+ _ao_serial_tx_start();
+ ao_wakeup(&ao_usart_tx_fifo);
+ }
+ if (wake_input) {
+ ao_wakeup(&ao_usart_rx_fifo);
+ if (stdin)
+ ao_wakeup(&ao_stdin_ready);
+ }
+}
+
+int
+_ao_serial0_pollchar(void)
+{
+ int c;
+
+ if (ao_fifo_empty(ao_usart_rx_fifo))
+ c = AO_READ_AGAIN;
+ else {
+ uint8_t u;
+ ao_fifo_remove(ao_usart_rx_fifo,u);
+ c = u;
+ }
+ return c;
+}
+
+char
+ao_serial0_getchar(void)
+{
+ int c;
+ ao_arch_block_interrupts();
+ while ((c = _ao_serial0_pollchar()) == AO_READ_AGAIN)
+ ao_sleep(&ao_usart_rx_fifo);
+ ao_arch_release_interrupts();
+ return (char) c;
+}
+
+void
+ao_serial0_putchar(char c)
+{
+ ao_arch_block_interrupts();
+ while (ao_fifo_full(ao_usart_tx_fifo))
+ ao_sleep(&ao_usart_tx_fifo);
+ ao_fifo_insert(ao_usart_tx_fifo, c);
+ _ao_serial_tx_start();
+ ao_arch_release_interrupts();
+}
+
+void
+ao_serial0_drain(void)
+{
+ ao_arch_block_interrupts();
+ while (!ao_fifo_empty(ao_usart_tx_fifo))
+ ao_sleep(&ao_usart_tx_fifo);
+ ao_arch_release_interrupts();
+}
+
+#include "ao_serial_lpc.h"
+
+void
+ao_serial0_set_speed(uint8_t speed)
+{
+ if (speed > AO_SERIAL_SPEED_115200)
+ return;
+
+ /* Flip to allow access to divisor latches */
+ lpc_usart.lcr |= (1 << LPC_USART_LCR_DLAB);
+
+ /* DL LSB */
+ lpc_usart.rbr_thr = ao_usart_speeds[speed].dl & 0xff;
+
+ /* DL MSB */
+ lpc_usart.ier = (ao_usart_speeds[speed].dl >> 8) & 0xff;
+
+ lpc_usart.fdr = ((ao_usart_speeds[speed].divaddval << LPC_USART_FDR_DIVADDVAL) |
+ (ao_usart_speeds[speed].mulval << LPC_USART_FDR_MULVAL));
+
+ /* Turn access to divisor latches back off */
+ lpc_usart.lcr &= ~(1 << LPC_USART_LCR_DLAB);
+}
+
+void
+ao_serial_init(void)
+{
+#if SERIAL_0_18_19
+ lpc_ioconf.pio0_18 = ((LPC_IOCONF_FUNC_PIO0_18_RXD << LPC_IOCONF_FUNC) |
+ (LPC_IOCONF_MODE_INACTIVE << LPC_IOCONF_MODE) |
+ (0 << LPC_IOCONF_HYS) |
+ (0 << LPC_IOCONF_INV) |
+ (0 << LPC_IOCONF_OD));
+ lpc_ioconf.pio0_19 = ((LPC_IOCONF_FUNC_PIO0_19_TXD << LPC_IOCONF_FUNC) |
+ (LPC_IOCONF_MODE_INACTIVE << LPC_IOCONF_MODE) |
+ (0 << LPC_IOCONF_HYS) |
+ (0 << LPC_IOCONF_INV) |
+ (0 << LPC_IOCONF_OD));
+#endif
+
+ /* Turn on the USART */
+ lpc_scb.sysahbclkctrl |= (1 << LPC_SCB_SYSAHBCLKCTRL_USART);
+
+ /* Turn on the USART clock */
+ lpc_scb.uartclkdiv = AO_LPC_CLKOUT / AO_LPC_USARTCLK;
+
+ /* Configure USART */
+
+ /* Enable FIFOs, reset fifo contents, interrupt on 1 received char */
+ lpc_usart.iir_fcr = ((1 << LPC_USART_FCR_FIFOEN) |
+ (1 << LPC_USART_FCR_RXFIFORES) |
+ (1 << LPC_USART_FCR_TXFIFORES) |
+ (LPC_USART_FCR_RXTL_1 << LPC_USART_FCR_RXTL));
+
+ ao_usart_tx_avail = LPC_USART_TX_FIFO_SIZE;
+ ao_usart_tx_avail_min = LPC_USART_TX_FIFO_SIZE;
+
+ /* 8 n 1 */
+ lpc_usart.lcr = ((LPC_USART_LCR_WLS_8 << LPC_USART_LCR_WLS) |
+ (LPC_USART_LCR_SBS_1 << LPC_USART_LCR_SBS) |
+ (0 << LPC_USART_LCR_PE) |
+ (LPC_USART_LCR_PS_ODD << LPC_USART_LCR_PS) |
+ (0 << LPC_USART_LCR_BC) |
+ (0 << LPC_USART_LCR_DLAB));
+
+ /* Disable flow control */
+ lpc_usart.mcr = ((0 << LPC_USART_MCR_DTRCTRL) |
+ (0 << LPC_USART_MCR_RTSCTRL) |
+ (0 << LPC_USART_MCR_LMS) |
+ (0 << LPC_USART_MCR_RTSEN) |
+ (0 << LPC_USART_MCR_CTSEN));
+
+ /* 16x oversampling */
+ lpc_usart.osr = ((0 << LPC_USART_OSR_OSFRAC) |
+ ((16 - 1) << LPC_USART_OSR_OSINT) |
+ (0 << LPC_USART_OSR_FDINT));
+
+ /* Full duplex */
+ lpc_usart.hden = ((0 << LPC_USART_HDEN_HDEN));
+
+ /* Set baud rate */
+ ao_serial0_set_speed(AO_SERIAL_SPEED_9600);
+
+ /* Enable interrupts */
+ lpc_usart.ier = ((1 << LPC_USART_IER_RBRINTEN) |
+ (1 << LPC_USART_IER_THREINTEN));
+
+ lpc_nvic_set_enable(LPC_ISR_USART_POS);
+ lpc_nvic_set_priority(LPC_ISR_USART_POS, 0);
+#if USE_SERIAL_0_STDIN
+ ao_add_stdio(_ao_serial_pollchar,
+ ao_serial_putchar,
+ NULL);
+#endif
+}
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+
+static uint8_t ao_spi_mutex[LPC_NUM_SPI];
+
+static struct lpc_ssp * const ao_lpc_ssp[LPC_NUM_SPI] = { &lpc_ssp0, &lpc_ssp1 };
+
+static uint8_t spi_dev_null;
+
+#define tx_busy(lpc_ssp) (lpc_ssp->sr & ((1 << LPC_SSP_SR_BSY) | (1 << LPC_SSP_SR_TNF))) != (1 << LPC_SSP_SR_TNF)
+#define rx_busy(lpc_ssp) (lpc_ssp->sr & ((1 << LPC_SSP_SR_BSY) | (1 << LPC_SSP_SR_RNE))) != (1 << LPC_SSP_SR_RNE)
+
+#define spi_loop(len, put, get) do { \
+ while (len--) { \
+ /* Wait for space in the fifo */ \
+ while (tx_busy(lpc_ssp)) \
+ ; \
+ \
+ /* send a byte */ \
+ lpc_ssp->dr = put; \
+ \
+ /* Wait for byte to appear in the fifo */ \
+ while (rx_busy(lpc_ssp)) \
+ ; \
+ \
+ /* recv a byte */ \
+ get lpc_ssp->dr; \
+ } \
+ } while (0)
+
+void
+ao_spi_send(void *block, uint16_t len, uint8_t id)
+{
+ uint8_t *b = block;
+ struct lpc_ssp *lpc_ssp = ao_lpc_ssp[id];
+
+ spi_loop(len, *b++, (void));
+}
+
+void
+ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t id)
+{
+ struct lpc_ssp *lpc_ssp = ao_lpc_ssp[id];
+
+ spi_loop(len, value, (void));
+}
+
+void
+ao_spi_recv(void *block, uint16_t len, uint8_t id)
+{
+ uint8_t *b = block;
+ struct lpc_ssp *lpc_ssp = ao_lpc_ssp[id];
+
+ spi_loop(len, 0xff, *b++ =);
+}
+
+void
+ao_spi_duplex(void *out, void *in, uint16_t len, uint8_t id)
+{
+ uint8_t *o = out;
+ uint8_t *i = in;
+ struct lpc_ssp *lpc_ssp = ao_lpc_ssp[id];
+
+ spi_loop(len, *o++, *i++ =);
+}
+
+void
+ao_spi_get(uint8_t id, uint32_t speed)
+{
+ struct lpc_ssp *lpc_ssp = ao_lpc_ssp[id];
+
+ ao_mutex_get(&ao_spi_mutex[id]);
+
+ /* Set the clock prescale */
+ lpc_ssp->cpsr = speed;
+}
+
+void
+ao_spi_put(uint8_t id)
+{
+ ao_mutex_put(&ao_spi_mutex[id]);
+}
+
+static void
+ao_spi_channel_init(uint8_t id)
+{
+ struct lpc_ssp *lpc_ssp = ao_lpc_ssp[id];
+ uint8_t d;
+
+ lpc_ssp->cr0 = ((LPC_SSP_CR0_DSS_8 << LPC_SSP_CR0_DSS) |
+ (LPC_SSP_CR0_FRF_SPI << LPC_SSP_CR0_FRF) |
+ (0 << LPC_SSP_CR0_CPOL) |
+ (0 << LPC_SSP_CR0_CPHA) |
+ (0 << LPC_SSP_CR0_SCR));
+
+ /* Enable the device */
+ lpc_ssp->cr1 = ((0 << LPC_SSP_CR1_LBM) |
+ (1 << LPC_SSP_CR1_SSE) |
+ (LPC_SSP_CR1_MS_MASTER << LPC_SSP_CR1_MS) |
+ (0 << LPC_SSP_CR1_SOD));
+
+ /* Drain the receive fifo */
+ for (d = 0; d < LPC_SSP_FIFOSIZE; d++)
+ (void) lpc_ssp->dr;
+}
+
+void
+ao_spi_init(void)
+{
+#if HAS_SPI_0
+ /* Configure pins */
+#if SPI_SCK0_P0_6
+ lpc_ioconf.pio0_6 = ao_lpc_alternate(LPC_IOCONF_FUNC_PIO0_6_SCK0);
+#define HAS_SCK0
+#endif
+#if SPI_SCK0_P0_10
+ lpc_ioconf.pio0_10 = ao_lpc_alternate(LPC_IOCONF_FUNC_PIO0_10_SCK0);
+#define HAS_SCK0
+#endif
+#if SPI_SCK0_P1_29
+ lpc_ioconf.pio1_29 = ao_lpc_alternate(LPC_IOCONF_FUNC_PIO1_29_SCK0);
+#define HAS_SCK0
+#endif
+#ifndef HAS_SCK0
+#error "No pin specified for SCK0"
+#endif
+ lpc_ioconf.pio0_8 = ao_lpc_alternate(LPC_IOCONF_FUNC_MISO0);
+ lpc_ioconf.pio0_9 = ao_lpc_alternate(LPC_IOCONF_FUNC_MOSI0);
+
+ /* Enable the device */
+ lpc_scb.sysahbclkctrl |= (1 << LPC_SCB_SYSAHBCLKCTRL_SSP0);
+
+ /* Turn on the clock */
+ lpc_scb.ssp0clkdiv = 1;
+
+ /* Reset the device */
+ lpc_scb.presetctrl &= ~(1 << LPC_SCB_PRESETCTRL_SSP0_RST_N);
+ lpc_scb.presetctrl |= (1 << LPC_SCB_PRESETCTRL_SSP0_RST_N);
+ ao_spi_channel_init(0);
+#endif
+
+#if HAS_SPI_1
+
+#if SPI_SCK1_P1_15
+ lpc_ioconf.pio1_15 = ao_lpc_alternate(LPC_IOCONF_FUNC_PIO1_15_SCK1);
+#define HAS_SCK1
+#endif
+#if SPI_SCK1_P1_20
+ lpc_ioconf.pio1_20 = ao_lpc_alternate(LPC_IOCONF_FUNC_PIO1_20_SCK1);
+#define HAS_SCK1
+#endif
+#ifndef HAS_SCK1
+#error "No pin specified for SCK1"
+#endif
+
+#if SPI_MISO1_P0_22
+ lpc_ioconf.pio0_22 = ao_lpc_alternate(LPC_IOCONF_FUNC_PIO0_22_MISO1);
+#define HAS_MISO1
+#endif
+#if SPI_MISO1_P1_21
+ lpc_ioconf.pio1_21 = ao_lpc_alternate(LPC_IOCONF_FUNC_PIO1_21_MISO1);
+#define HAS_MISO1
+#endif
+#ifndef HAS_MISO1
+#error "No pin specified for MISO1"
+#endif
+
+#if SPI_MOSI1_P0_21
+ lpc_ioconf.pio0_21 = ao_lpc_alternate(LPC_IOCONF_FUNC_PIO0_21_MOSI1);
+#define HAS_MOSI1
+#endif
+#if SPI_MOSI1_P1_22
+ lpc_ioconf.pio1_22 = ao_lpc_alternate(LPC_IOCONF_FUNC_PIO1_22_MOSI1);
+#define HAS_MOSI1
+#endif
+#ifndef HAS_MOSI1
+#error "No pin specified for MOSI1"
+#endif
+
+ /* Enable the device */
+ lpc_scb.sysahbclkctrl |= (1 << LPC_SCB_SYSAHBCLKCTRL_SSP1);
+
+ /* Turn on the clock */
+ lpc_scb.ssp1clkdiv = 1;
+
+ /* Reset the device */
+ lpc_scb.presetctrl &= ~(1 << LPC_SCB_PRESETCTRL_SSP1_RST_N);
+ lpc_scb.presetctrl |= (1 << LPC_SCB_PRESETCTRL_SSP1_RST_N);
+ ao_spi_channel_init(1);
+#endif /* HAS_SPI_1 */
+}
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+
+volatile __data AO_TICK_TYPE ao_tick_count;
+
+uint16_t
+ao_time(void)
+{
+ return ao_tick_count;
+}
+
+#if AO_DATA_ALL
+volatile __data uint8_t ao_data_interval = 1;
+volatile __data uint8_t ao_data_count;
+#endif
+
+void lpc_systick_isr(void)
+{
+ if (lpc_systick.csr & (1 << LPC_SYSTICK_CSR_COUNTFLAG)) {
+ ++ao_tick_count;
+#if HAS_TASK_QUEUE
+ if (ao_task_alarm_tick && (int16_t) (ao_tick_count - ao_task_alarm_tick) >= 0)
+ ao_task_check_alarm((uint16_t) ao_tick_count);
+#endif
+#if AO_DATA_ALL
+ if (++ao_data_count == ao_data_interval) {
+ ao_data_count = 0;
+ ao_adc_poll();
+#if (AO_DATA_ALL & ~(AO_DATA_ADC))
+ ao_wakeup((void *) &ao_data_count);
+#endif
+ }
+#endif
+ }
+}
+
+#if HAS_ADC
+void
+ao_timer_set_adc_interval(uint8_t interval)
+{
+ ao_arch_critical(
+ ao_data_interval = interval;
+ ao_data_count = 0;
+ );
+}
+#endif
+
+#define SYSTICK_RELOAD ((AO_LPC_SYSCLK / 2) / 100 - 1)
+
+/* Initialize our 100Hz clock */
+void
+ao_timer_init(void)
+{
+ lpc_systick.rvr = SYSTICK_RELOAD;
+ lpc_systick.cvr = 0;
+ lpc_systick.csr = ((1 << LPC_SYSTICK_CSR_ENABLE) |
+ (1 << LPC_SYSTICK_CSR_TICKINT) |
+ (LPC_SYSTICK_CSR_CLKSOURCE_CPU_OVER_2 << LPC_SYSTICK_CSR_CLKSOURCE));
+}
+
+#define AO_LPC_M ((AO_LPC_CLKOUT / AO_LPC_CLKIN) - 1)
+
+#define AO_LPC_FCCO_MIN 156000000
+
+static void
+ao_clock_delay(void)
+{
+ uint32_t i;
+ for (i = 0; i < 200; i++)
+ ao_arch_nop();
+}
+
+void
+ao_clock_init(void)
+{
+ uint8_t p;
+ uint32_t i;
+
+ /* Turn off all perhipherals except for GPIO configuration */
+ lpc_scb.sysahbclkctrl = ((1 << LPC_SCB_SYSAHBCLKCTRL_SYS) |
+ (1 << LPC_SCB_SYSAHBCLKCTRL_ROM) |
+ (1 << LPC_SCB_SYSAHBCLKCTRL_RAM0) |
+ (1 << LPC_SCB_SYSAHBCLKCTRL_FLASHARRAY) |
+ (1 << LPC_SCB_SYSAHBCLKCTRL_GPIO) |
+ (1 << LPC_SCB_SYSAHBCLKCTRL_IOCON));
+
+ /* Enable the brown-out detection at the highest voltage to
+ * make sure the flash part remains happy
+ */
+
+ lpc_scb.pdruncfg &= ~(1 << LPC_SCB_PDRUNCFG_BOD_PD);
+ lpc_scb.bodctrl = ((LPC_SCB_BOD_BODRSTLEV_2_63 << LPC_SCB_BOD_BODRSTLEV) |
+ (LPC_SCB_BOD_BODINTVAL_RESERVED << LPC_SCB_BOD_BODINTVAL) |
+ (1 << LPC_SCB_BOD_BODRSTENA));
+
+ /* Turn the IRC clock back on */
+ lpc_scb.pdruncfg &= ~(1 << LPC_SCB_PDRUNCFG_IRC_PD);
+ ao_clock_delay();
+
+ /* Switch to the IRC clock */
+ lpc_scb.mainclksel = LPC_SCB_MAINCLKSEL_SEL_IRC << LPC_SCB_MAINCLKSEL_SEL;
+ lpc_scb.mainclkuen = (0 << LPC_SCB_MAINCLKUEN_ENA);
+ lpc_scb.mainclkuen = (1 << LPC_SCB_MAINCLKUEN_ENA);
+ while (!(lpc_scb.mainclkuen & (1 << LPC_SCB_MAINCLKUEN_ENA)))
+ ;
+
+ /* Switch USB to the main clock */
+ lpc_scb.usbclksel = (LPC_SCB_USBCLKSEL_SEL_MAIN_CLOCK << LPC_SCB_USBCLKSEL_SEL);
+ lpc_scb.usbclkuen = (0 << LPC_SCB_USBCLKUEN_ENA);
+ lpc_scb.usbclkuen = (1 << LPC_SCB_USBCLKUEN_ENA);
+ while (!(lpc_scb.usbclkuen & (1 << LPC_SCB_USBCLKUEN_ENA)))
+ ;
+
+ /* Find a PLL post divider ratio that gets the FCCO in range */
+ for (p = 0; p < 4; p++)
+ if (AO_LPC_CLKOUT << (1 + p) >= AO_LPC_FCCO_MIN)
+ break;
+
+ if (p == 4)
+ ao_panic(AO_PANIC_CRASH);
+
+ /* Power down the PLL before touching the registers */
+ lpc_scb.pdruncfg |= (1 << LPC_SCB_PDRUNCFG_SYSPLL_PD);
+ ao_clock_delay();
+
+ /* Set PLL divider values */
+ lpc_scb.syspllctrl = ((AO_LPC_M << LPC_SCB_SYSPLLCTRL_MSEL) |
+ (p << LPC_SCB_SYSPLLCTRL_PSEL));
+
+ /* Turn off the external crystal clock */
+ lpc_scb.pdruncfg |= (1 << LPC_SCB_PDRUNCFG_SYSOSC_PD);
+ ao_clock_delay();
+
+ /* Configure the crystal clock */
+ lpc_scb.sysoscctrl = ((0 << LPC_SCB_SYSOSCCTRL_BYPASS) | /* using a crystal */
+ ((AO_LPC_CLKIN > 15000000) << LPC_SCB_SYSOSCCTRL_FREQRANGE));/* set range */
+
+ /* Turn on the external crystal clock */
+ lpc_scb.pdruncfg &= ~(1 << LPC_SCB_PDRUNCFG_SYSOSC_PD);
+ ao_clock_delay();
+
+ /* Select crystal as PLL input */
+
+ lpc_scb.syspllclksel = (LPC_SCB_SYSPLLCLKSEL_SEL_SYSOSC << LPC_SCB_SYSPLLCLKSEL_SEL);
+ lpc_scb.syspllclkuen = (1 << LPC_SCB_SYSPLLCLKUEN_ENA);
+ lpc_scb.syspllclkuen = (0 << LPC_SCB_SYSPLLCLKUEN_ENA);
+ lpc_scb.syspllclkuen = (1 << LPC_SCB_SYSPLLCLKUEN_ENA);
+ while (!(lpc_scb.syspllclkuen & (1 << LPC_SCB_SYSPLLCLKUEN_ENA)))
+ ;
+
+ /* Turn on the PLL */
+ lpc_scb.pdruncfg &= ~(1 << LPC_SCB_PDRUNCFG_SYSPLL_PD);
+
+ /* Wait for it to lock */
+
+ for (i = 0; i < 20000; i++)
+ if (lpc_scb.syspllstat & (1 << LPC_SCB_SYSPLLSTAT_LOCK))
+ break;
+ if (i == 20000)
+ ao_panic(AO_PANIC_CRASH);
+
+ /* Switch to the PLL */
+ lpc_scb.mainclksel = LPC_SCB_MAINCLKSEL_SEL_PLL_OUTPUT << LPC_SCB_MAINCLKSEL_SEL;
+ lpc_scb.mainclkuen = (1 << LPC_SCB_MAINCLKUEN_ENA);
+ lpc_scb.mainclkuen = (0 << LPC_SCB_MAINCLKUEN_ENA);
+ lpc_scb.mainclkuen = (1 << LPC_SCB_MAINCLKUEN_ENA);
+ while (!(lpc_scb.mainclkuen & (1 << LPC_SCB_MAINCLKUEN_ENA)))
+ ;
+
+ /* Set system clock divider */
+ lpc_scb.sysahbclkdiv = AO_LPC_CLKOUT / AO_LPC_SYSCLK;
+
+ /* Shut down perhipheral clocks (enabled as needed) */
+ lpc_scb.ssp0clkdiv = 0;
+ lpc_scb.uartclkdiv = 0;
+ lpc_scb.ssp1clkdiv = 0;
+ lpc_scb.usbclkdiv = 0;
+ lpc_scb.clkoutdiv = 0;
+
+ /* Switch USB PLL source to system osc so we can power down the IRC */
+ lpc_scb.usbpllclksel = (LPC_SCB_USBPLLCLKSEL_SEL_SYSOSC << LPC_SCB_USBPLLCLKSEL_SEL);
+ lpc_scb.usbpllclkuen = (0 << LPC_SCB_USBPLLCLKUEN_ENA);
+ lpc_scb.usbpllclkuen = (1 << LPC_SCB_USBPLLCLKUEN_ENA);
+ while (!(lpc_scb.usbpllclkuen & (1 << LPC_SCB_USBPLLCLKUEN_ENA)))
+ ;
+
+ /* Power down everything we don't need */
+ lpc_scb.pdruncfg = ((1 << LPC_SCB_PDRUNCFG_IRCOUT_PD) |
+ (1 << LPC_SCB_PDRUNCFG_IRC_PD) |
+ (0 << LPC_SCB_PDRUNCFG_BOD_PD) |
+ (1 << LPC_SCB_PDRUNCFG_ADC_PD) |
+ (1 << LPC_SCB_PDRUNCFG_WDTOSC_PD) |
+ (1 << LPC_SCB_PDRUNCFG_USBPLL_PD) |
+ (1 << LPC_SCB_PDRUNCFG_USBPAD_PD) |
+ (1 << 11) |
+ (7 << 13));
+}
--- /dev/null
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+#include "ao_usb.h"
+#include "ao_product.h"
+
+#ifndef USE_USB_STDIO
+#define USE_USB_STDIO 1
+#endif
+
+#if USE_USB_STDIO
+#define AO_USB_OUT_SLEEP_ADDR (&ao_stdin_ready)
+#else
+#define AO_USB_OUT_SLEEP_ADDR (&ao_usb_out_avail)
+#endif
+
+#define USB_DEBUG 0
+#define USB_DEBUG_DATA 0
+#define USB_ECHO 0
+
+#if USB_DEBUG
+#define debug(format, args...) printf(format, ## args);
+#else
+#define debug(format, args...)
+#endif
+
+#if USB_DEBUG_DATA
+#define debug_data(format, args...) printf(format, ## args);
+#else
+#define debug_data(format, args...)
+#endif
+
+struct ao_usb_setup {
+ uint8_t dir_type_recip;
+ uint8_t request;
+ uint16_t value;
+ uint16_t index;
+ uint16_t length;
+} ao_usb_setup;
+
+static uint8_t ao_usb_ep0_state;
+
+/* Pending EP0 IN data */
+static const uint8_t *ao_usb_ep0_in_data; /* Remaining data */
+static uint8_t ao_usb_ep0_in_len; /* Remaining amount */
+static uint16_t ao_usb_ep0_in_max; /* Requested amount from host */
+
+/* Temp buffer for smaller EP0 in data */
+static uint8_t ao_usb_ep0_in_buf[2];
+
+/* Pending EP0 OUT data */
+static uint8_t *ao_usb_ep0_out_data;
+static uint8_t ao_usb_ep0_out_len;
+
+/*
+ * Objects allocated in special USB memory
+ */
+
+/* USB address of end of allocated storage */
+static uint8_t *ao_usb_sram;
+
+/* Pointer to ep0 tx/rx buffers in USB memory */
+static uint8_t *ao_usb_ep0_tx_buffer;
+static uint8_t *ao_usb_ep0_setup_buffer;
+static uint8_t *ao_usb_ep0_rx_buffer;
+
+/* Pointer to bulk data tx/rx buffers in USB memory */
+static uint8_t *ao_usb_in_tx_buffer;
+static uint8_t *ao_usb_out_rx_buffer;
+
+/* Our data buffers */
+static uint8_t ao_usb_tx_buffer[AO_USB_IN_SIZE];
+static uint8_t ao_usb_tx_count;
+
+static uint8_t ao_usb_rx_buffer[AO_USB_OUT_SIZE];
+static uint8_t ao_usb_rx_count, ao_usb_rx_pos;
+
+extern struct lpc_usb_endpoint lpc_usb_endpoint;
+
+/* Marks when we don't need to send an IN packet.
+ * This happens only when the last IN packet is not full,
+ * otherwise the host will expect to keep seeing packets.
+ * Send a zero-length packet as required
+ */
+static uint8_t ao_usb_in_flushed;
+
+/* Marks when we have delivered an IN packet to the hardware
+ * and it has not been received yet. ao_sleep on this address
+ * to wait for it to be delivered.
+ */
+static uint8_t ao_usb_in_pending;
+
+/* Marks when an OUT packet has been received by the hardware
+ * but not pulled to the shadow buffer.
+ */
+static uint8_t ao_usb_out_avail;
+static uint8_t ao_usb_running;
+static uint8_t ao_usb_configuration;
+static uint8_t ueienx_0;
+
+#define AO_USB_EP0_GOT_RESET 1
+#define AO_USB_EP0_GOT_SETUP 2
+#define AO_USB_EP0_GOT_RX_DATA 4
+#define AO_USB_EP0_GOT_TX_ACK 8
+
+static uint8_t ao_usb_ep0_receive;
+static uint8_t ao_usb_address;
+static uint8_t ao_usb_address_pending;
+
+static inline uint32_t set_toggle(uint32_t current_value,
+ uint32_t mask,
+ uint32_t desired_value)
+{
+ return (current_value ^ desired_value) & mask;
+}
+
+/*
+ * Set current device address and mark the
+ * interface as active
+ */
+void
+ao_usb_set_address(uint8_t address)
+{
+ debug("ao_usb_set_address %02x\n", address);
+ lpc_usb.devcmdstat = ((address << LPC_USB_DEVCMDSTAT_DEV_ADDR) |
+ (1 << LPC_USB_DEVCMDSTAT_DEV_EN) |
+ (0 << LPC_USB_DEVCMDSTAT_SETUP) |
+ (0 << LPC_USB_DEVCMDSTAT_PLL_ON) |
+ (0 << LPC_USB_DEVCMDSTAT_LPM_SUP) |
+ (0 << LPC_USB_DEVCMDSTAT_INTONNAK_AO) |
+ (0 << LPC_USB_DEVCMDSTAT_INTONNAK_AI) |
+ (0 << LPC_USB_DEVCMDSTAT_INTONNAK_CO) |
+ (0 << LPC_USB_DEVCMDSTAT_INTONNAK_CI) |
+ (1 << LPC_USB_DEVCMDSTAT_DCON) |
+ (0 << LPC_USB_DEVCMDSTAT_DSUS) |
+ (0 << LPC_USB_DEVCMDSTAT_DCON_C) |
+ (0 << LPC_USB_DEVCMDSTAT_DSUS_C) |
+ (0 << LPC_USB_DEVCMDSTAT_DRES_C) |
+ (0 << LPC_USB_DEVCMDSTAT_VBUSDEBOUNCED));
+ ao_usb_address_pending = 0;
+}
+
+#define TX_DBG 0
+#define RX_DBG 0
+
+#if TX_DBG
+#define _tx_dbg0(msg) _dbg(__LINE__,msg,0)
+#define _tx_dbg1(msg,value) _dbg(__LINE__,msg,value)
+#else
+#define _tx_dbg0(msg)
+#define _tx_dbg1(msg,value)
+#endif
+
+#if RX_DBG
+#define _rx_dbg0(msg) _dbg(__LINE__,msg,0)
+#define _rx_dbg1(msg,value) _dbg(__LINE__,msg,value)
+#else
+#define _rx_dbg0(msg)
+#define _rx_dbg1(msg,value)
+#endif
+
+#if TX_DBG || RX_DBG
+static void _dbg(int line, char *msg, uint32_t value);
+#endif
+
+/*
+ * Set just endpoint 0, for use during startup
+ */
+
+static uint8_t *
+ao_usb_alloc_sram(uint16_t size)
+{
+ uint8_t *addr = ao_usb_sram;
+
+ ao_usb_sram += (size + 63) & ~63;
+ return addr;
+}
+
+static uint16_t
+ao_usb_sram_offset(uint8_t *addr)
+{
+ return (uint16_t) ((intptr_t) addr >> 6);
+}
+
+static void
+ao_usb_set_ep(vuint32_t *ep, uint8_t *addr, uint16_t nbytes)
+{
+ *ep = ((ao_usb_sram_offset(addr) << LPC_USB_EP_OFFSET) |
+ (nbytes << LPC_USB_EP_NBYTES) |
+ (0 << LPC_USB_EP_ENDPOINT_ISO) |
+ (0 << LPC_USB_EP_RATE_FEEDBACK) |
+ (0 << LPC_USB_EP_TOGGLE_RESET) |
+ (0 << LPC_USB_EP_STALL) |
+ (0 << LPC_USB_EP_DISABLED) |
+ (1 << LPC_USB_EP_ACTIVE));
+}
+
+static inline uint16_t
+ao_usb_ep_count(vuint32_t *ep)
+{
+ return (*ep >> LPC_USB_EP_NBYTES) & LPC_USB_EP_NBYTES_MASK;
+}
+
+static inline uint8_t
+ao_usb_ep_stall(vuint32_t *ep)
+{
+ return (*ep >> LPC_USB_EP_STALL) & 1;
+}
+
+static inline vuint32_t *
+ao_usb_ep0_out(void)
+{
+ return &lpc_usb_endpoint.ep0_out;
+}
+
+static inline vuint32_t *
+ao_usb_ep0_in(void)
+{
+ return &lpc_usb_endpoint.ep0_in;
+}
+
+static inline vuint32_t *
+ao_usb_epn_out(uint8_t n)
+{
+ return &lpc_usb_endpoint.epn[n-1].out[0];
+}
+
+static inline vuint32_t *
+ao_usb_epn_in(uint8_t n)
+{
+ return &lpc_usb_endpoint.epn[n-1].in[0];
+}
+
+static void
+ao_usb_set_epn_in(uint8_t n, uint8_t *addr, uint16_t nbytes)
+{
+ ao_usb_set_ep(ao_usb_epn_in(n), addr, nbytes);
+}
+
+static void
+ao_usb_set_epn_out(uint8_t n, uint8_t *addr, uint16_t nbytes)
+{
+ ao_usb_set_ep(ao_usb_epn_out(n), addr, nbytes);
+}
+
+static inline uint16_t
+ao_usb_epn_out_count(uint8_t n)
+{
+ return ao_usb_ep_count(ao_usb_epn_out(n));
+}
+
+static inline uint16_t
+ao_usb_epn_in_count(uint8_t n)
+{
+ return ao_usb_ep_count(ao_usb_epn_in(n));
+}
+
+static uint8_t *
+ao_usb_enable_ep(vuint32_t *ep, uint16_t nbytes, uint16_t set_nbytes)
+{
+ uint8_t *addr = ao_usb_alloc_sram(nbytes);
+
+ ao_usb_set_ep(ep, addr, set_nbytes);
+ return addr;
+}
+
+static void
+ao_usb_disable_ep(vuint32_t *ep)
+{
+ *ep = ((0 << LPC_USB_EP_OFFSET) |
+ (0 << LPC_USB_EP_NBYTES) |
+ (0 << LPC_USB_EP_ENDPOINT_ISO) |
+ (0 << LPC_USB_EP_RATE_FEEDBACK) |
+ (0 << LPC_USB_EP_TOGGLE_RESET) |
+ (0 << LPC_USB_EP_STALL) |
+ (1 << LPC_USB_EP_DISABLED) |
+ (0 << LPC_USB_EP_ACTIVE));
+}
+
+static void
+ao_usb_enable_epn(uint8_t n, uint16_t out_bytes, uint8_t **out_addr, uint16_t in_bytes, uint8_t **in_addr)
+{
+ uint8_t *addr;
+
+ addr = ao_usb_enable_ep(ao_usb_epn_out(n), out_bytes, out_bytes);
+ if (out_addr)
+ *out_addr = addr;
+ ao_usb_disable_ep(&lpc_usb_endpoint.epn[n-1].out[1]);
+
+ addr = ao_usb_enable_ep(ao_usb_epn_in(n), in_bytes, 0);
+ if (in_addr)
+ *in_addr = addr;
+ ao_usb_disable_ep(&lpc_usb_endpoint.epn[n-1].in[1]);
+}
+
+static void
+ao_usb_disable_epn(uint8_t n)
+{
+ ao_usb_disable_ep(ao_usb_epn_out(n));
+ ao_usb_disable_ep(&lpc_usb_endpoint.epn[n-1].out[1]);
+ ao_usb_disable_ep(ao_usb_epn_in(n));
+ ao_usb_disable_ep(&lpc_usb_endpoint.epn[n-1].in[1]);
+}
+
+static void
+ao_usb_reset(void)
+{
+ ao_usb_set_address(0);
+ ao_usb_configuration = 0;
+}
+
+static void
+ao_usb_set_ep0(void)
+{
+ int e;
+
+ /* Everything is single buffered for now */
+ lpc_usb.epbufcfg = 0;
+ lpc_usb.epinuse = 0;
+ lpc_usb.epskip = 0xffffffff;
+
+ lpc_usb.intstat = 0xc00003ff;
+
+ ao_usb_sram = lpc_usb_sram;
+
+ lpc_usb.epliststart = (uint32_t) (intptr_t) &lpc_usb_endpoint;
+ lpc_usb.databufstart = ((uint32_t) (intptr_t) ao_usb_sram) & 0xffc00000;
+
+ /* Set up EP 0 - a Control end point with 32 bytes of in and out buffers */
+
+ ao_usb_ep0_rx_buffer = ao_usb_enable_ep(ao_usb_ep0_out(), AO_USB_CONTROL_SIZE, AO_USB_CONTROL_SIZE);
+ ao_usb_ep0_setup_buffer = ao_usb_alloc_sram(AO_USB_CONTROL_SIZE);
+ lpc_usb_endpoint.setup = ao_usb_sram_offset(ao_usb_ep0_setup_buffer);
+ ao_usb_ep0_tx_buffer = ao_usb_enable_ep(ao_usb_ep0_in(), AO_USB_CONTROL_SIZE, 0);
+
+ /* Clear all of the other endpoints */
+ for (e = 1; e <= 4; e++)
+ ao_usb_disable_epn(e);
+ ao_usb_reset();
+}
+
+static void
+ao_usb_set_configuration(void)
+{
+ debug ("ao_usb_set_configuration\n");
+
+ /* Set up the INT end point */
+ ao_usb_enable_epn(AO_USB_INT_EP, 0, NULL, 0, NULL);
+
+ /* Set up the OUT end point */
+ ao_usb_enable_epn(AO_USB_OUT_EP, AO_USB_OUT_SIZE, &ao_usb_out_rx_buffer, 0, NULL);
+
+ /* Set up the IN end point */
+ ao_usb_enable_epn(AO_USB_IN_EP, 0, NULL, AO_USB_IN_SIZE, &ao_usb_in_tx_buffer);
+
+ ao_usb_running = 1;
+}
+
+/* Send an IN data packet */
+static void
+ao_usb_ep0_flush(void)
+{
+ uint8_t this_len;
+
+ this_len = ao_usb_ep0_in_len;
+ if (this_len > AO_USB_CONTROL_SIZE)
+ this_len = AO_USB_CONTROL_SIZE;
+
+ ao_usb_ep0_in_len -= this_len;
+ ao_usb_ep0_in_max -= this_len;
+
+ if (this_len < AO_USB_CONTROL_SIZE || ao_usb_ep0_in_max == 0)
+ ao_usb_ep0_state = AO_USB_EP0_IDLE;
+
+ debug_data ("Flush EP0 len %d:", this_len);
+ memcpy(ao_usb_ep0_tx_buffer, ao_usb_ep0_in_data, this_len);
+ debug_data ("\n");
+ ao_usb_ep0_in_data += this_len;
+
+ /* Mark the endpoint as TX valid to send the packet */
+ ao_usb_set_ep(ao_usb_ep0_in(), ao_usb_ep0_tx_buffer, this_len);
+ debug ("queue tx. 0 now %08x\n", *ao_usb_ep0_in());
+}
+
+/* Read data from the ep0 OUT fifo */
+static void
+ao_usb_ep0_fill(void)
+{
+ uint16_t len;
+ uint8_t *rx_buffer;
+
+ /* Pull all of the data out of the packet */
+ if (lpc_usb.devcmdstat & (1 << LPC_USB_DEVCMDSTAT_SETUP)) {
+ rx_buffer = ao_usb_ep0_setup_buffer;
+ len = 8;
+ } else {
+ rx_buffer = ao_usb_ep0_rx_buffer;
+ len = AO_USB_CONTROL_SIZE - ao_usb_ep_count(ao_usb_ep0_out());
+ }
+
+ if (len > ao_usb_ep0_out_len)
+ len = ao_usb_ep0_out_len;
+ ao_usb_ep0_out_len -= len;
+
+ debug_data ("Fill EP0 len %d:", len);
+ memcpy(ao_usb_ep0_out_data, rx_buffer, len);
+ debug_data ("\n");
+ ao_usb_ep0_out_data += len;
+
+ /* ACK the packet */
+ ao_usb_set_ep(ao_usb_ep0_out(), ao_usb_ep0_rx_buffer, AO_USB_CONTROL_SIZE);
+ lpc_usb.devcmdstat |= (1 << LPC_USB_DEVCMDSTAT_SETUP);
+}
+
+static void
+ao_usb_ep0_in_reset(void)
+{
+ ao_usb_ep0_in_data = ao_usb_ep0_in_buf;
+ ao_usb_ep0_in_len = 0;
+}
+
+static void
+ao_usb_ep0_in_queue_byte(uint8_t a)
+{
+ if (ao_usb_ep0_in_len < sizeof (ao_usb_ep0_in_buf))
+ ao_usb_ep0_in_buf[ao_usb_ep0_in_len++] = a;
+}
+
+static void
+ao_usb_ep0_in_set(const uint8_t *data, uint8_t len)
+{
+ ao_usb_ep0_in_data = data;
+ ao_usb_ep0_in_len = len;
+}
+
+static void
+ao_usb_ep0_out_set(uint8_t *data, uint8_t len)
+{
+ ao_usb_ep0_out_data = data;
+ ao_usb_ep0_out_len = len;
+}
+
+static void
+ao_usb_ep0_in_start(uint16_t max)
+{
+ ao_usb_ep0_in_max = max;
+ /* Don't send more than asked for */
+ if (ao_usb_ep0_in_len > max)
+ ao_usb_ep0_in_len = max;
+ ao_usb_ep0_flush();
+}
+
+static struct ao_usb_line_coding ao_usb_line_coding = {115200, 0, 0, 8};
+
+/* Walk through the list of descriptors and find a match
+ */
+static void
+ao_usb_get_descriptor(uint16_t value)
+{
+ const uint8_t *descriptor;
+ uint8_t type = value >> 8;
+ uint8_t index = value;
+
+ descriptor = ao_usb_descriptors;
+ while (descriptor[0] != 0) {
+ if (descriptor[1] == type && index-- == 0) {
+ uint8_t len;
+ if (type == AO_USB_DESC_CONFIGURATION)
+ len = descriptor[2];
+ else
+ len = descriptor[0];
+ ao_usb_ep0_in_set(descriptor, len);
+ break;
+ }
+ descriptor += descriptor[0];
+ }
+}
+
+static void
+ao_usb_ep0_setup(void)
+{
+ /* Pull the setup packet out of the fifo */
+ ao_usb_ep0_out_set((uint8_t *) &ao_usb_setup, 8);
+ ao_usb_ep0_fill();
+ if (ao_usb_ep0_out_len != 0) {
+ debug ("invalid setup packet length\n");
+ return;
+ }
+
+ if ((ao_usb_setup.dir_type_recip & AO_USB_DIR_IN) || ao_usb_setup.length == 0)
+ ao_usb_ep0_state = AO_USB_EP0_DATA_IN;
+ else
+ ao_usb_ep0_state = AO_USB_EP0_DATA_OUT;
+
+ ao_usb_ep0_in_reset();
+
+ switch(ao_usb_setup.dir_type_recip & AO_USB_SETUP_TYPE_MASK) {
+ case AO_USB_TYPE_STANDARD:
+ debug ("Standard setup packet\n");
+ switch(ao_usb_setup.dir_type_recip & AO_USB_SETUP_RECIP_MASK) {
+ case AO_USB_RECIP_DEVICE:
+ debug ("Device setup packet\n");
+ switch(ao_usb_setup.request) {
+ case AO_USB_REQ_GET_STATUS:
+ debug ("get status\n");
+ ao_usb_ep0_in_queue_byte(0);
+ ao_usb_ep0_in_queue_byte(0);
+ break;
+ case AO_USB_REQ_SET_ADDRESS:
+ debug ("set address %d\n", ao_usb_setup.value);
+ ao_usb_address = ao_usb_setup.value;
+ ao_usb_address_pending = 1;
+ break;
+ case AO_USB_REQ_GET_DESCRIPTOR:
+ debug ("get descriptor %d\n", ao_usb_setup.value);
+ ao_usb_get_descriptor(ao_usb_setup.value);
+ break;
+ case AO_USB_REQ_GET_CONFIGURATION:
+ debug ("get configuration %d\n", ao_usb_configuration);
+ ao_usb_ep0_in_queue_byte(ao_usb_configuration);
+ break;
+ case AO_USB_REQ_SET_CONFIGURATION:
+ ao_usb_configuration = ao_usb_setup.value;
+ debug ("set configuration %d\n", ao_usb_configuration);
+ ao_usb_set_configuration();
+ break;
+ }
+ break;
+ case AO_USB_RECIP_INTERFACE:
+ debug ("Interface setup packet\n");
+ switch(ao_usb_setup.request) {
+ case AO_USB_REQ_GET_STATUS:
+ ao_usb_ep0_in_queue_byte(0);
+ ao_usb_ep0_in_queue_byte(0);
+ break;
+ case AO_USB_REQ_GET_INTERFACE:
+ ao_usb_ep0_in_queue_byte(0);
+ break;
+ case AO_USB_REQ_SET_INTERFACE:
+ break;
+ }
+ break;
+ case AO_USB_RECIP_ENDPOINT:
+ debug ("Endpoint setup packet\n");
+ switch(ao_usb_setup.request) {
+ case AO_USB_REQ_GET_STATUS:
+ ao_usb_ep0_in_queue_byte(0);
+ ao_usb_ep0_in_queue_byte(0);
+ break;
+ }
+ break;
+ }
+ break;
+ case AO_USB_TYPE_CLASS:
+ debug ("Class setup packet\n");
+ switch (ao_usb_setup.request) {
+ case AO_USB_SET_LINE_CODING:
+ debug ("set line coding\n");
+ ao_usb_ep0_out_set((uint8_t *) &ao_usb_line_coding, 7);
+ break;
+ case AO_USB_GET_LINE_CODING:
+ debug ("get line coding\n");
+ ao_usb_ep0_in_set((const uint8_t *) &ao_usb_line_coding, 7);
+ break;
+ case AO_USB_SET_CONTROL_LINE_STATE:
+ break;
+ }
+ break;
+ }
+
+ /* If we're not waiting to receive data from the host,
+ * queue an IN response
+ */
+ if (ao_usb_ep0_state == AO_USB_EP0_DATA_IN)
+ ao_usb_ep0_in_start(ao_usb_setup.length);
+}
+
+static void
+ao_usb_ep0_handle(uint8_t receive)
+{
+ ao_usb_ep0_receive = 0;
+
+ if (receive & AO_USB_EP0_GOT_RESET) {
+ debug ("\treset\n");
+ ao_usb_reset();
+ return;
+ }
+ if (receive & AO_USB_EP0_GOT_SETUP) {
+ debug ("\tsetup\n");
+ ao_usb_ep0_setup();
+ }
+ if (receive & AO_USB_EP0_GOT_RX_DATA) {
+ debug ("\tgot rx data\n");
+ if (ao_usb_ep0_state == AO_USB_EP0_DATA_OUT) {
+ ao_usb_ep0_fill();
+ if (ao_usb_ep0_out_len == 0) {
+ ao_usb_ep0_state = AO_USB_EP0_DATA_IN;
+ ao_usb_ep0_in_start(0);
+ }
+ }
+ }
+ if (receive & AO_USB_EP0_GOT_TX_ACK) {
+ debug ("\tgot tx ack\n");
+
+ /* Wait until the IN packet is received from addr 0
+ * before assigning our local address
+ */
+ if (ao_usb_address_pending) {
+#if HAS_FLIGHT
+ /* Go to idle mode if USB is connected
+ */
+ ao_flight_force_idle = 1;
+#endif
+ ao_usb_set_address(ao_usb_address);
+ }
+ if (ao_usb_ep0_state == AO_USB_EP0_DATA_IN)
+ ao_usb_ep0_flush();
+ }
+}
+
+static uint16_t control_count;
+static uint16_t int_count;
+static uint16_t in_count;
+static uint16_t out_count;
+static uint16_t reset_count;
+
+void
+lpc_usb_irq_isr(void)
+{
+ uint32_t intstat = lpc_usb.intstat & lpc_usb.inten;
+
+ lpc_usb.intstat = intstat;
+ /* Handle EP0 OUT packets */
+ if (intstat & (1 << LPC_USB_INT_EPOUT(0))) {
+ if (lpc_usb.devcmdstat & (1 << LPC_USB_DEVCMDSTAT_SETUP))
+ ao_usb_ep0_receive |= AO_USB_EP0_GOT_SETUP;
+ else
+ ao_usb_ep0_receive |= AO_USB_EP0_GOT_RX_DATA;
+
+ ao_usb_ep0_handle(ao_usb_ep0_receive);
+ }
+
+ /* Handle EP0 IN packets */
+ if (intstat & (1 << LPC_USB_INT_EPIN(0))) {
+ ao_usb_ep0_receive |= AO_USB_EP0_GOT_TX_ACK;
+
+ ao_usb_ep0_handle(ao_usb_ep0_receive);
+ }
+
+
+ /* Handle OUT packets */
+ if (intstat & (1 << LPC_USB_INT_EPOUT(AO_USB_OUT_EP))) {
+ ++out_count;
+ _rx_dbg1("RX ISR", *ao_usb_epn_out(AO_USB_OUT_EP));
+ ao_usb_out_avail = 1;
+ _rx_dbg0("out avail set");
+ ao_wakeup(AO_USB_OUT_SLEEP_ADDR)
+ _rx_dbg0("stdin awoken");
+ }
+
+ /* Handle IN packets */
+ if (intstat & (1 << LPC_USB_INT_EPIN(AO_USB_IN_EP))) {
+ ++in_count;
+ _tx_dbg1("TX ISR", *ao_usb_epn_in(AO_USB_IN_EP));
+ ao_usb_in_pending = 0;
+ ao_wakeup(&ao_usb_in_pending);
+ }
+
+ /* NAK all INT EP IN packets */
+ if (intstat & (1 << LPC_USB_INT_EPIN(AO_USB_INT_EP))) {
+ ;
+ }
+
+ /* Check for reset */
+ if (intstat & (1 << LPC_USB_INT_DEV)) {
+ if (lpc_usb.devcmdstat & (1 << LPC_USB_DEVCMDSTAT_DRES_C))
+ {
+ lpc_usb.devcmdstat |= (1 << LPC_USB_DEVCMDSTAT_DRES_C);
+ ao_usb_ep0_receive |= AO_USB_EP0_GOT_RESET;
+ ao_usb_ep0_handle(ao_usb_ep0_receive);
+ }
+ }
+}
+
+
+
+/* Queue the current IN buffer for transmission */
+static void
+_ao_usb_in_send(void)
+{
+ _tx_dbg0("in_send start");
+ debug ("send %d\n", ao_usb_tx_count);
+ while (ao_usb_in_pending)
+ ao_sleep(&ao_usb_in_pending);
+ ao_usb_in_pending = 1;
+ if (ao_usb_tx_count != AO_USB_IN_SIZE)
+ ao_usb_in_flushed = 1;
+ memcpy(ao_usb_in_tx_buffer, ao_usb_tx_buffer, ao_usb_tx_count);
+ ao_usb_set_ep(ao_usb_epn_in(AO_USB_IN_EP), ao_usb_in_tx_buffer, ao_usb_tx_count);
+ ao_usb_tx_count = 0;
+ _tx_dbg0("in_send end");
+}
+
+/* Wait for a free IN buffer. Interrupts are blocked */
+static void
+_ao_usb_in_wait(void)
+{
+ for (;;) {
+ /* Check if the current buffer is writable */
+ if (ao_usb_tx_count < AO_USB_IN_SIZE)
+ break;
+
+ _tx_dbg0("in_wait top");
+ /* Wait for an IN buffer to be ready */
+ while (ao_usb_in_pending)
+ ao_sleep(&ao_usb_in_pending);
+ _tx_dbg0("in_wait bottom");
+ }
+}
+
+void
+ao_usb_flush(void)
+{
+ if (!ao_usb_running)
+ return;
+
+ /* Anytime we've sent a character since
+ * the last time we flushed, we'll need
+ * to send a packet -- the only other time
+ * we would send a packet is when that
+ * packet was full, in which case we now
+ * want to send an empty packet
+ */
+ ao_arch_block_interrupts();
+ while (!ao_usb_in_flushed) {
+ _tx_dbg0("flush top");
+ _ao_usb_in_send();
+ _tx_dbg0("flush end");
+ }
+ ao_arch_release_interrupts();
+}
+
+void
+ao_usb_putchar(char c)
+{
+ if (!ao_usb_running)
+ return;
+
+ ao_arch_block_interrupts();
+ _ao_usb_in_wait();
+
+ ao_usb_in_flushed = 0;
+ ao_usb_tx_buffer[ao_usb_tx_count++] = (uint8_t) c;
+
+ /* Send the packet when full */
+ if (ao_usb_tx_count == AO_USB_IN_SIZE) {
+ _tx_dbg0("putchar full");
+ _ao_usb_in_send();
+ _tx_dbg0("putchar flushed");
+ }
+ ao_arch_release_interrupts();
+}
+
+static void
+_ao_usb_out_recv(void)
+{
+ _rx_dbg0("out_recv top");
+ ao_usb_out_avail = 0;
+
+ ao_usb_rx_count = AO_USB_OUT_SIZE - ao_usb_epn_out_count(AO_USB_OUT_EP);
+
+ _rx_dbg1("out_recv count", ao_usb_rx_count);
+ debug ("recv %d\n", ao_usb_rx_count);
+ debug_data("Fill OUT len %d:", ao_usb_rx_count);
+ memcpy(ao_usb_rx_buffer, ao_usb_out_rx_buffer, ao_usb_rx_count);
+ debug_data("\n");
+ ao_usb_rx_pos = 0;
+
+ /* ACK the packet */
+ ao_usb_set_epn_out(AO_USB_OUT_EP, ao_usb_out_rx_buffer, AO_USB_OUT_SIZE);
+}
+
+int
+_ao_usb_pollchar(void)
+{
+ uint8_t c;
+
+ if (!ao_usb_running)
+ return AO_READ_AGAIN;
+
+ for (;;) {
+ if (ao_usb_rx_pos != ao_usb_rx_count)
+ break;
+
+ _rx_dbg0("poll check");
+ /* Check to see if a packet has arrived */
+ if (!ao_usb_out_avail) {
+ _rx_dbg0("poll none");
+ return AO_READ_AGAIN;
+ }
+ _ao_usb_out_recv();
+ }
+
+ /* Pull a character out of the fifo */
+ c = ao_usb_rx_buffer[ao_usb_rx_pos++];
+ return c;
+}
+
+char
+ao_usb_getchar(void)
+{
+ int c;
+
+ ao_arch_block_interrupts();
+ while ((c = _ao_usb_pollchar()) == AO_READ_AGAIN)
+ ao_sleep(AO_USB_OUT_SLEEP_ADDR);
+ ao_arch_release_interrupts();
+ return c;
+}
+
+void
+ao_usb_disable(void)
+{
+ ao_arch_block_interrupts();
+
+#if HAS_USB_PULLUP
+ ao_gpio_set(AO_USB_PULLUP_PORT, AO_USB_PULLUP_PIN, AO_USB_PULLUP, 0);
+#endif
+ /* Disable interrupts */
+ lpc_usb.inten = 0;
+
+ lpc_nvic_clear_enable(LPC_ISR_USB_IRQ_POS);
+
+ /* Disable the device */
+ lpc_usb.devcmdstat = 0;
+
+ /* Turn off USB clock */
+ lpc_scb.usbclkdiv = 0;
+
+ /* Disable USB PHY and PLL */
+ lpc_scb.pdruncfg |= ((1 << LPC_SCB_PDRUNCFG_USBPAD_PD) |
+ (1 << LPC_SCB_PDRUNCFG_USBPLL_PD));
+
+ /* Disable USB registers and RAM */
+ lpc_scb.sysahbclkctrl &= ~((1 << LPC_SCB_SYSAHBCLKCTRL_USB) |
+ (1 << LPC_SCB_SYSAHBCLKCTRL_USBRAM));
+
+ ao_arch_release_interrupts();
+}
+
+void
+ao_usb_enable(void)
+{
+ int t;
+
+ /* Enable USB pins */
+#if HAS_USB_CONNECT
+ lpc_ioconf.pio0_6 = ((LPC_IOCONF_FUNC_USB_CONNECT << LPC_IOCONF_FUNC) |
+ (LPC_IOCONF_MODE_INACTIVE << LPC_IOCONF_MODE) |
+ (0 << LPC_IOCONF_HYS) |
+ (0 << LPC_IOCONF_INV) |
+ (0 << LPC_IOCONF_OD) |
+ 0x80);
+#endif
+#if HAS_USB_VBUS
+ lpc_ioconf.pio0_3 = ((LPC_IOCONF_FUNC_USB_VBUS << LPC_IOCONF_FUNC) |
+ (LPC_IOCONF_MODE_INACTIVE << LPC_IOCONF_MODE) |
+ (0 << LPC_IOCONF_HYS) |
+ (0 << LPC_IOCONF_INV) |
+ (0 << LPC_IOCONF_OD) |
+ 0x80);
+#endif
+ /* Enable USB registers and RAM */
+ lpc_scb.sysahbclkctrl |= ((1 << LPC_SCB_SYSAHBCLKCTRL_USB) |
+ (1 << LPC_SCB_SYSAHBCLKCTRL_USBRAM));
+
+ /* Enable USB PHY */
+ lpc_scb.pdruncfg &= ~(1 << LPC_SCB_PDRUNCFG_USBPAD_PD);
+
+ /* Turn on USB PLL */
+ lpc_scb.pdruncfg &= ~(1 << LPC_SCB_PDRUNCFG_USBPLL_PD);
+
+ lpc_scb.usbpllclksel = (LPC_SCB_SYSPLLCLKSEL_SEL_SYSOSC << LPC_SCB_SYSPLLCLKSEL_SEL);
+ lpc_scb.usbpllclkuen = (0 << LPC_SCB_USBPLLCLKUEN_ENA);
+ lpc_scb.usbpllclkuen = (1 << LPC_SCB_USBPLLCLKUEN_ENA);
+ while (!(lpc_scb.usbpllclkuen & (1 << LPC_SCB_USBPLLCLKUEN_ENA)))
+ ;
+ lpc_scb.usbpllctrl = 0x23;
+ while (!(lpc_scb.usbpllstat & 1))
+ ;
+
+ lpc_scb.usbclksel = 0;
+ lpc_scb.usbclkuen = (0 << LPC_SCB_USBCLKUEN_ENA);
+ lpc_scb.usbclkuen = (1 << LPC_SCB_USBCLKUEN_ENA);
+ while (!(lpc_scb.usbclkuen & (1 << LPC_SCB_USBCLKUEN_ENA)))
+ ;
+
+ /* Turn on USB clock, use 48MHz clock unchanged */
+ lpc_scb.usbclkdiv = 1;
+
+ /* Configure interrupts */
+ ao_arch_block_interrupts();
+
+ /* Route all interrupts to the main isr */
+ lpc_usb.introuting = 0;
+
+ /* Configure NVIC */
+
+ lpc_nvic_set_enable(LPC_ISR_USB_IRQ_POS);
+ lpc_nvic_set_priority(LPC_ISR_USB_IRQ_POS, 0);
+
+ /* Clear any spurious interrupts */
+ lpc_usb.intstat = 0xffffffff;
+
+ debug ("ao_usb_enable\n");
+
+ /* Enable interrupts */
+ lpc_usb.inten = ((1 << LPC_USB_INT_EPOUT(0)) |
+ (1 << LPC_USB_INT_EPIN(0)) |
+ (1 << LPC_USB_INT_EPIN(AO_USB_INT_EP)) |
+ (1 << LPC_USB_INT_EPOUT(AO_USB_OUT_EP)) |
+ (1 << LPC_USB_INT_EPIN(AO_USB_IN_EP)) |
+ (1 << LPC_USB_INT_DEV));
+
+ ao_arch_release_interrupts();
+
+ lpc_usb.devcmdstat = 0;
+ for (t = 0; t < 1000; t++)
+ ao_arch_nop();
+
+ ao_usb_set_ep0();
+
+#if HAS_USB_PULLUP
+ ao_gpio_set(AO_USB_PULLUP_PORT, AO_USB_PULLUP_PIN, AO_USB_PULLUP, 1);
+#endif
+}
+
+#if USB_ECHO
+struct ao_task ao_usb_echo_task;
+
+static void
+ao_usb_echo(void)
+{
+ char c;
+
+ for (;;) {
+ c = ao_usb_getchar();
+ ao_usb_putchar(c);
+ ao_usb_flush();
+ }
+}
+#endif
+
+#if USB_DEBUG
+static void
+ao_usb_irq(void)
+{
+ printf ("control: %d out: %d in: %d int: %d reset: %d\n",
+ control_count, out_count, in_count, int_count, reset_count);
+}
+
+__code struct ao_cmds ao_usb_cmds[] = {
+ { ao_usb_irq, "I\0Show USB interrupt counts" },
+ { 0, NULL }
+};
+#endif
+
+void
+ao_usb_init(void)
+{
+#if HAS_USB_PULLUP
+ ao_enable_output(AO_USB_PULLUP_PORT, AO_USB_PULLUP_PIN, AO_USB_PULLUP, 0);
+#endif
+
+ ao_usb_enable();
+
+ debug ("ao_usb_init\n");
+#if USB_ECHO
+ ao_add_task(&ao_usb_echo_task, ao_usb_echo, "usb echo");
+#endif
+#if USB_DEBUG
+ ao_cmd_register(&ao_usb_cmds[0]);
+#endif
+#if USE_USB_STDIO
+ ao_add_stdio(_ao_usb_pollchar, ao_usb_putchar, ao_usb_flush);
+#endif
+}
+
+#if TX_DBG || RX_DBG
+
+struct ao_usb_dbg {
+ int line;
+ char *msg;
+ uint32_t value;
+ uint32_t primask;
+#if TX_DBG
+ uint16_t in_count;
+ uint32_t in_ep;
+ uint32_t in_pending;
+ uint32_t tx_count;
+ uint32_t in_flushed;
+#endif
+#if RX_DBG
+ uint8_t rx_count;
+ uint8_t rx_pos;
+ uint8_t out_avail;
+ uint32_t out_ep;
+#endif
+};
+
+#define NUM_USB_DBG 8
+
+static struct ao_usb_dbg dbg[NUM_USB_DBG];
+static int dbg_i;
+
+static void _dbg(int line, char *msg, uint32_t value)
+{
+ uint32_t primask;
+ dbg[dbg_i].line = line;
+ dbg[dbg_i].msg = msg;
+ dbg[dbg_i].value = value;
+ asm("mrs %0,primask" : "=&r" (primask));
+ dbg[dbg_i].primask = primask;
+#if TX_DBG
+ dbg[dbg_i].in_count = in_count;
+ dbg[dbg_i].in_ep = *ao_usb_epn_in(AO_USB_IN_EP);
+ dbg[dbg_i].in_pending = ao_usb_in_pending;
+ dbg[dbg_i].tx_count = ao_usb_tx_count;
+ dbg[dbg_i].in_flushed = ao_usb_in_flushed;
+#endif
+#if RX_DBG
+ dbg[dbg_i].rx_count = ao_usb_rx_count;
+ dbg[dbg_i].rx_pos = ao_usb_rx_pos;
+ dbg[dbg_i].out_avail = ao_usb_out_avail;
+ dbg[dbg_i].out_ep = *ao_usb_epn_out(AO_USB_OUT_EP);
+#endif
+ if (++dbg_i == NUM_USB_DBG)
+ dbg_i = 0;
+}
+#endif
--- /dev/null
+#!/usr/bin/env nickle
+
+/*
+ * Given a main clock frequency,
+ * compute USART clock freq and a table
+ * of USART config parameters for our target baud rates
+ */
+
+real main_clock = 0;
+real usart_clock = 0;
+
+real[] baud_rates = { 4800, 9600, 19200, 57600, 115200 };
+
+void
+compute_baud_rate(real rate) {
+ int divaddval;
+ int mulval;
+
+ real dl_est = usart_clock / (16 * rate);
+
+ if (dl_est == floor(dl_est)) {
+ divaddval = 0;
+ mulval = 1;
+ } else {
+ if (false) {
+
+ /* This is how the docs suggest doing it; this
+ * generates a rate which is reasonably close
+ */
+
+ real fr_est = 1.5;
+
+ /* Compute fractional estimate */
+ do {
+ dl_est = floor(usart_clock / (16 * rate * fr_est) + 0.5);
+ fr_est = usart_clock / (16 * rate * dl_est);
+ } while (fr_est <= 1.1 || 1.9 <= fr_est);
+
+ /* Given fractional estimate, compute divaddval/mulvals that work best */
+
+ real best_dist = 1000;
+ for (int tmp_divaddval = 1; tmp_divaddval < 15; tmp_divaddval++) {
+ for (int tmp_mulval = 1; tmp_mulval < 16; tmp_mulval++) {
+ real fr = 1 + tmp_divaddval / tmp_mulval;
+ real dist = abs(fr - fr_est);
+ if (dist < best_dist) {
+ divaddval = tmp_divaddval;
+ mulval = tmp_mulval;
+ best_dist = dist;
+ }
+ }
+ }
+ } else {
+
+ /* This exhaustively searches for the best match */
+
+ real my_best_dist = 1e20;
+ int my_best_dl;
+ int my_best_divaddval;
+ int my_best_mulval;
+ for (int my_dl = 1; my_dl < 1024; my_dl++) {
+ for (int my_mulval = 1; my_mulval < 16; my_mulval++) {
+ for (int my_divaddval = 0; my_divaddval < my_mulval; my_divaddval++) {
+ real my_rate = usart_clock / ((16 * my_dl) * (1 + my_divaddval/my_mulval));
+
+ real my_dist = abs(rate - my_rate);
+
+ if (my_dist == 0 && my_divaddval == 0) {
+ my_dist = -1;
+ }
+
+ if (my_dist < my_best_dist) {
+ my_best_dl = my_dl;
+ my_best_divaddval = my_divaddval;
+ my_best_mulval = my_mulval;
+ my_best_dist = my_dist;
+ }
+ }
+ }
+ }
+
+ dl_est = my_best_dl;
+ divaddval = my_best_divaddval;
+ mulval = my_best_mulval;
+ }
+ }
+
+ int dl = floor (dl_est);
+
+ real actual = usart_clock / ((16 * dl) * (1 + divaddval/mulval));
+
+ printf("\t[AO_SERIAL_SPEED_%d] = { /* actual = %8.2f */\n", floor(rate), actual);
+ printf("\t\t.dl = %d,\n", dl);
+ printf("\t\t.divaddval = %d,\n", divaddval);
+ printf("\t\t.mulval = %d\n", mulval);
+ printf("\t},\n");
+}
+
+void
+main() {
+ if (dim(argv) < 2) {
+ printf ("usage: %s <main-clock>\n", argv[0]);
+ exit(1);
+ }
+ main_clock = string_to_real(argv[1]);
+
+ for (int div = 0; div < 4; div++) {
+ if (main_clock / (1 << div) <= 12000000) {
+ usart_clock = main_clock / (1 << div);
+ break;
+ }
+ }
+
+ if (usart_clock == 0) {
+ printf ("can't get usart clock in range\n");
+ exit(1);
+ }
+
+ printf ("#define AO_LPC_USARTCLK %d\n\n", floor(usart_clock));
+ printf("static const struct {\n");
+ printf("\tuint16_t dl;\n");
+ printf("\tuint8_t divaddval;\n");
+ printf("\tuint8_t mulval;\n");
+ printf("} ao_usart_speeds[] = {\n");
+ for (int i = 0; i < dim(baud_rates); i++) {
+ compute_baud_rate(baud_rates[i]);
+ }
+ printf ("};\n");
+}
+
+main();
--- /dev/null
+#!/usr/bin/env nickle
+
+autoimport Process;
+
+int byteflip(int x) {
+ return ((x >> 24) & 0xff) | ((x >> 8) & 0xff00) | ((x << 8) & 0xff0000) | ((x << 24) & 0xff000000);
+}
+
+void main () {
+ file input = popen(popen_direction.read, true, "objdump",
+ "objdump", "-j", ".text",
+ "--start-address=0",
+ "--stop-address=0x20",
+ "-s", argv[1]);
+ int sum = 0;
+
+ void add_in(int addr, int value) {
+ if (addr < 0x1c) {
+ sum += value;
+ } else if (addr == 0x1c) {
+ printf ("-DCKSUM=0x%08x\n", -sum & 0xffffffff);
+ exit(0);
+ }
+ }
+ while (!File::end(input)) {
+ string line = File::fgets(input);
+ string[] words = String::wordsplit(line, " ");
+
+ if (dim(words) < 5)
+ continue;
+ if (words[0] == "0000" || words[0] == "0010") {
+ int addr = string_to_integer(words[0], 16);
+ for (int i = 0; i < 4; i++)
+ add_in(addr + i * 4, byteflip(string_to_integer(words[i+1], 16)));
+ }
+ }
+}
+
+main();
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _LPC_H_
+#define _LPC_H_
+
+#include <stdint.h>
+
+typedef volatile uint32_t vuint32_t;
+typedef volatile uint16_t vuint16_t;
+typedef volatile uint8_t vuint8_t;
+typedef volatile void * vvoid_t;
+
+struct lpc_ioconf {
+ vuint32_t pio0_0;
+ vuint32_t pio0_1;
+ vuint32_t pio0_2;
+ vuint32_t pio0_3;
+
+ vuint32_t pio0_4;
+ vuint32_t pio0_5;
+ vuint32_t pio0_6;
+ vuint32_t pio0_7;
+
+ vuint32_t pio0_8;
+ vuint32_t pio0_9;
+ vuint32_t pio0_10;
+ vuint32_t pio0_11;
+
+ vuint32_t pio0_12;
+ vuint32_t pio0_13;
+ vuint32_t pio0_14;
+ vuint32_t pio0_15;
+
+ vuint32_t pio0_16;
+ vuint32_t pio0_17;
+ vuint32_t pio0_18;
+ vuint32_t pio0_19;
+
+ vuint32_t pio0_20;
+ vuint32_t pio0_21;
+ vuint32_t pio0_22;
+ vuint32_t pio0_23;
+
+ vuint32_t pio1_0; /* 0x60 */
+ vuint32_t pio1_1;
+ vuint32_t pio1_2;
+ vuint32_t pio1_3;
+
+ vuint32_t pio1_4;
+ vuint32_t pio1_5;
+ vuint32_t pio1_6;
+ vuint32_t pio1_7;
+
+ vuint32_t pio1_8; /* 0x80 */
+ vuint32_t pio1_9;
+ vuint32_t pio1_10;
+ vuint32_t pio1_11;
+
+ vuint32_t pio1_12;
+ vuint32_t pio1_13;
+ vuint32_t pio1_14;
+ vuint32_t pio1_15;
+
+ vuint32_t pio1_16; /* 0xa0 */
+ vuint32_t pio1_17;
+ vuint32_t pio1_18;
+ vuint32_t pio1_19;
+
+ vuint32_t pio1_20;
+ vuint32_t pio1_21;
+ vuint32_t pio1_22;
+ vuint32_t pio1_23;
+
+ vuint32_t pio1_24; /* 0xc0 */
+ vuint32_t pio1_25;
+ vuint32_t pio1_26;
+ vuint32_t pio1_27;
+
+ vuint32_t pio1_28;
+ vuint32_t pio1_29;
+ vuint32_t pio1_30;
+ vuint32_t pio1_31;
+};
+
+extern struct lpc_ioconf lpc_ioconf;
+
+#define LPC_IOCONF_FUNC 0
+
+/* PIO0_0 */
+#define LPC_IOCONF_FUNC_RESET 0
+#define LPC_IOCONF_FUNC_PIO0_0 1
+
+/* PIO0_1 */
+#define LPC_IOCONF_FUNC_PIO0_1 0
+#define LPC_IOCONF_FUNC_CLKOUT 1
+#define LPC_IOCONF_FUNC_CT32B0_MAT2 2
+#define LPC_IOCONF_FUNC_USB_FTOGGLE 3
+
+/* PIO0_2 */
+#define LPC_IOCONF_FUNC_PIO0_2 0
+#define LPC_IOCONF_FUNC_SSEL0 1
+#define LPC_IOCONF_FUNC_CT16B0_CAP0 2
+
+/* PIO0_3 */
+#define LPC_IOCONF_FUNC_PIO0_3 0
+#define LPC_IOCONF_FUNC_USB_VBUS 1
+
+/* PIO0_4
+#define LPC_IOCONF_FUNC_PIO0_4 0
+#define LPC_IOCONF_FUNC_I2C_SCL 1
+
+/* PIO0_5 */
+#define LPC_IOCONF_FUNC_PIO0_5 0
+#define LPC_IOCONF_FUNC_I2C_SDA 1
+
+/* PIO0_6 */
+#define LPC_IOCONF_FUNC_PIO0_6 0
+#define LPC_IOCONF_FUNC_USB_CONNECT 1
+#define LPC_IOCONF_FUNC_PIO0_6_SCK0 2
+
+/* PIO0_7 */
+#define LPC_IOCONF_FUNC_PIO0_7 0
+#define LPC_IOCONF_FUNC_CTS 1
+
+/* PIO0_8 */
+#define LPC_IOCONF_FUNC_PIO0_8 0
+#define LPC_IOCONF_FUNC_MISO0 1
+#define LPC_IOCONF_FUNC_CT16B0_MAT0 2
+
+/* PIO0_9 */
+#define LPC_IOCONF_FUNC_PIO0_9 0
+#define LPC_IOCONF_FUNC_MOSI0 1
+#define LPC_IOCONF_FUNC_CT16B0_MAT1 2
+
+/* PIO0_10 */
+#define LPC_IOCONF_FUNC_SWCLK 0
+#define LPC_IOCONF_FUNC_PIO0_10 1
+#define LPC_IOCONF_FUNC_PIO0_10_SCK0 2
+#define LPC_IOCONF_FUNC_CT16B0_MAT2 3
+
+/* PIO0_11 */
+#define LPC_IOCONF_FUNC_TDI 0
+#define LPC_IOCONF_FUNC_PIO0_11 1
+#define LPC_IOCONF_FUNC_AD0 2
+#define LPC_IOCONF_FUNC_CT32B0_MAT3 3
+
+/* PIO0_12 */
+#define LPC_IOCONF_FUNC_TMS 0
+#define LPC_IOCONF_FUNC_PIO0_12 1
+#define LPC_IOCONF_FUNC_AD1 2
+#define LPC_IOCONF_FUNC_CT32B1_CAP0 3
+
+/* PIO0_13 */
+#define LPC_IOCONF_FUNC_TD0 0
+#define LPC_IOCONF_FUNC_PIO0_13 1
+#define LPC_IOCONF_FUNC_AD2 2
+#define LPC_IOCONF_FUNC_CT32B1_MAT0 3
+
+/* PIO0_14 */
+#define LPC_IOCONF_FUNC_TRST 0
+#define LPC_IOCONF_FUNC_PIO0_14 1
+#define LPC_IOCONF_FUNC_AD3 2
+#define LPC_IOCONF_FUNC_PIO0_14_CT32B1_MAT1 3
+
+/* PIO0_15 */
+#define LPC_IOCONF_FUNC_SWDIO 0
+#define LPC_IOCONF_FUNC_PIO0_15 1
+#define LPC_IOCONF_FUNC_AD4 2
+#define LPC_IOCONF_FUNC_CT32B1_MAT2 3
+
+/* PIO0_16 */
+#define LPC_IOCONF_FUNC_PIO0_16 0
+#define LPC_IOCONF_FUNC_AD5 1
+#define LPC_IOCONF_FUNC_CT32B1_MAT3 2
+
+/* PIO0_17 */
+#define LPC_IOCONF_FUNC_PIO0_17 0
+#define LPC_IOCONF_FUNC_RTS 1
+#define LPC_IOCONF_FUNC_CT32B0_CAP0 2
+#define LPC_IOCONF_FUNC_SCLK 3
+
+/* PIO0_18 */
+#define LPC_IOCONF_FUNC_PIO0_18 0
+#define LPC_IOCONF_FUNC_PIO0_18_RXD 1
+#define LPC_IOCONF_FUNC_PIO0_18_CT32B0_MAT0 2
+
+/* PIO0_19 */
+#define LPC_IOCONF_FUNC_PIO0_19 0
+#define LPC_IOCONF_FUNC_PIO0_19_TXD 1
+#define LPC_IOCONF_FUNC_PIO0_19_CT32B0_MAT1 2
+
+/* PIO0_20 */
+#define LPC_IOCONF_FUNC_PIO0_20 0
+#define LPC_IOCONF_FUNC_CT16B1_CAP0 1
+
+/* PIO0_21 */
+#define LPC_IOCONF_FUNC_PIO0_21 0
+#define LPC_IOCONF_FUNC_CT16B1_MAT0 1
+#define LPC_IOCONF_FUNC_PIO0_21_MOSI1 2
+
+/* PIO0_22 */
+#define LPC_IOCONF_FUNC_PIO0_22 0
+#define LPC_IOCONF_FUNC_AD6 1
+#define LPC_IOCONF_FUNC_CT16B1_MAT1 2
+#define LPC_IOCONF_FUNC_PIO0_22_MISO1 3
+
+/* PIO0_23 */
+#define LPC_IOCONF_FUNC_PIO0_23 0
+#define LPC_IOCONF_FUNC_AD7 1
+
+/* PIO1_0 */
+#define LPC_IOCONF_FUNC_PIO1_0 0
+#define LPC_IOCONF_FUNC_CT32B1_MAT1 1
+
+/* PIO1_1 */
+#define LPC_IOCONF_FUNC_PIO1_1 0
+#define LPC_IOCONF_FUNC_CT32B1_MAT1 1
+
+/* PIO1_2 */
+#define LPC_IOCONF_FUNC_PIO1_2 0
+#define LPC_IOCONF_FUNC_PIO1_2_CT32B1_MAT2 1
+
+/* PIO1_3*/
+#define LPC_IOCONF_FUNC_PIO1_3 0
+#define LPC_IOCONF_FUNC_PIO1_3_CT32B1_MAT3 1
+
+/* PIO1_4 */
+#define LPC_IOCONF_FUNC_PIO1_4 0
+#define LPC_IOCONF_FUNC_PIO1_4_CT32B1_CAP0 1
+
+/* PIO1_5 */
+#define LPC_IOCONF_FUNC_PIO1_5 0
+#define LPC_IOCONF_FUNC_CT32B1_CAP1 1
+
+/* PIO1_6 */
+#define LPC_IOCONF_FUNC_PIO1_6 0
+
+/* PIO1_7 */
+#define LPC_IOCONF_FUNC_PIO1_7 0
+
+/* PIO1_8 */
+#define LPC_IOCONF_FUNC_PIO1_8 0
+
+/* PIO1_9 */
+#define LPC_IOCONF_FUNC_PIO1_9 0
+
+/* PIO1_10 */
+#define LPC_IOCONF_FUNC_PIO1_10 0
+
+/* PIO1_11 */
+#define LPC_IOCONF_FUNC_PIO1_11 0
+
+/* PIO1_12 */
+#define LPC_IOCONF_FUNC_PIO1_12 0
+
+/* PIO1_13 */
+#define LPC_IOCONF_FUNC_PIO1_13 0
+#define LPC_IOCONF_FUNC_DTR 1
+#define LPC_IOCONF_FUNC_CT16B0_MAT0 2
+#define LPC_IOCONF_FUNC_PIO1_13_TXD 3
+
+/* PIO1_14 */
+#define LPC_IOCONF_FUNC_PIO1_14 0
+#define LPC_IOCONF_FUNC_DSR 1
+#define LPC_IOCONF_FUNC_CT16B0_MAT1 2
+#define LPC_IOCONF_FUNC_PIO1_13_RXD 3
+
+/* PIO1_15 */
+#define LPC_IOCONF_FUNC_PIO1_15 0
+#define LPC_IOCONF_FUNC_DCD 1
+#define LPC_IOCONF_FUNC_PIO1_15_CT16B0_MAT2 2
+#define LPC_IOCONF_FUNC_PIO1_15_SCK1 3
+
+/* PIO1_16 */
+#define LPC_IOCONF_FUNC_PIO1_16 0
+#define LPC_IOCONF_FUNC_RI 1
+#define LPC_IOCONF_FUNC_CT16B0_CAP0 2
+
+/* PIO1_17 */
+#define LPC_IOCONF_FUNC_PIO1_17 0
+#define LPC_IOCONF_FUNC_CT16B0_CAP1 1
+#define LPC_IOCONF_FUNC_PIO1_17_RXD 2
+
+/* PIO1_18 */
+#define LPC_IOCONF_FUNC_PIO1_18 0
+#define LPC_IOCONF_FUNC_CT16B1_CAP1 1
+#define LPC_IOCONF_FUNC_PIO1_18_TXD 2
+
+/* PIO1_19 */
+#define LPC_IOCONF_FUNC_PIO1_19 0
+#define LPC_IOCONF_FUNC_DTR 1
+#define LPC_IOCONF_FUNC_SSEL1 2
+
+/* PIO1_20 */
+#define LPC_IOCONF_FUNC_PIO1_20 0
+#define LPC_IOCONF_FUNC_DSR 1
+#define LPC_IOCONF_FUNC_PIO1_20_SCK1 2
+
+/* PIO1_21 */
+#define LPC_IOCONF_FUNC_PIO1_21 0
+#define LPC_IOCONF_FUNC_DCD 1
+#define LPC_IOCONF_FUNC_PIO1_21_MISO1 2
+
+/* PIO1_22 */
+#define LPC_IOCONF_FUNC_PIO1_22 0
+#define LPC_IOCONF_FUNC_RI 1
+#define LPC_IOCONF_FUNC_PIO1_22_MOSI1 2
+
+/* PIO1_23 */
+#define LPC_IOCONF_FUNC_PIO1_23 0
+#define LPC_IOCONF_FUNC_PIO1_23_CT16B1_MAT1 1
+#define LPC_IOCONF_FUNC_SSEL1 2
+
+/* PIO1_24 */
+#define LPC_IOCONF_FUNC_PIO1_24 0
+#define LPC_IOCONF_FUNC_PIO1_24_CT32B0_MAT0 1
+
+/* PIO1_25 */
+#define LPC_IOCONF_FUNC_PIO1_25 0
+#define LPC_IOCONF_FUNC_PIO1_25_CT32B0_MAT1 1
+
+/* PIO1_26 */
+#define LPC_IOCONF_FUNC_PIO1_26 0
+#define LPC_IOCONF_FUNC_PIO1_26_CT32B0_MAT2 1
+#define LPC_IOCONF_FUNC_PIO1_26_RXD 2
+
+/* PIO1_27 */
+#define LPC_IOCONF_FUNC_PIO1_27 0
+#define LPC_IOCONF_FUNC_PIO1_27_CT32B0_MAT3 1
+#define LPC_IOCONF_FUNC_PIO1_27_TXD 2
+
+/* PIO1_28 */
+#define LPC_IOCONF_FUNC_PIO1_28 0
+#define LPC_IOCONF_FUNC_PIO1_28_CT32B0_CAP0 1
+#define LPC_IOCONF_FUNC_PIO1_28_SCLK 2
+
+/* PIO1_29 */
+#define LPC_IOCONF_FUNC_PIO1_29 0
+#define LPC_IOCONF_FUNC_PIO1_29_SCK0 1
+#define LPC_IOCONF_FUNC_PIO1_29_CT32B0_CAP1 2
+
+/* PIO1_31 */
+#define LPC_IOCONF_FUNC_PIO1_31 0
+
+#define LPC_IOCONF_FUNC_MASK 0x7
+
+#define ao_lpc_alternate(func) (((func) << LPC_IOCONF_FUNC) | \
+ (LPC_IOCONF_MODE_INACTIVE << LPC_IOCONF_MODE) | \
+ (0 << LPC_IOCONF_HYS) | \
+ (0 << LPC_IOCONF_INV) | \
+ (0 << LPC_IOCONF_OD) | \
+ 0x80)
+
+#define LPC_IOCONF_MODE 3
+#define LPC_IOCONF_MODE_INACTIVE 0
+#define LPC_IOCONF_MODE_PULL_DOWN 1
+#define LPC_IOCONF_MODE_PULL_UP 2
+#define LPC_IOCONF_MODE_REPEATER 3
+#define LPC_IOCONF_MODE_MASK 3
+
+#define LPC_IOCONF_HYS 5
+
+#define LPC_IOCONF_INV 6
+#define LPC_IOCONF_ADMODE 7
+#define LPC_IOCONF_FILTR 8
+#define LPC_IOCONF_OD 10
+
+struct lpc_scb {
+ vuint32_t sysmemremap; /* 0x00 */
+ vuint32_t presetctrl;
+ vuint32_t syspllctrl;
+ vuint32_t syspllstat;
+
+ vuint32_t usbpllctrl; /* 0x10 */
+ vuint32_t usbpllstat;
+ uint32_t r18;
+ uint32_t r1c;
+
+ vuint32_t sysoscctrl; /* 0x20 */
+ vuint32_t wdtoscctrl;
+ uint32_t r28;
+ uint32_t r2c;
+
+ vuint32_t sysrststat; /* 0x30 */
+ uint32_t r34;
+ uint32_t r38;
+ uint32_t r3c;
+
+ vuint32_t syspllclksel; /* 0x40 */
+ vuint32_t syspllclkuen;
+ vuint32_t usbpllclksel;
+ vuint32_t usbpllclkuen;
+
+ uint32_t r50[8];
+
+ vuint32_t mainclksel; /* 0x70 */
+ vuint32_t mainclkuen;
+ vuint32_t sysahbclkdiv;
+ uint32_t r7c;
+
+ vuint32_t sysahbclkctrl; /* 0x80 */
+ uint32_t r84[3];
+
+ uint32_t r90; /* 0x90 */
+ vuint32_t ssp0clkdiv;
+ vuint32_t uartclkdiv;
+ vuint32_t ssp1clkdiv;
+
+ uint32_t ra0[8];
+
+ vuint32_t usbclksel; /* 0xc0 */
+ vuint32_t usbclkuen;
+ vuint32_t usbclkdiv;
+ uint32_t rcc;
+
+ uint32_t rd0[4];
+
+ vuint32_t clkoutsel; /* 0xe0 */
+ vuint32_t clkoutuen;
+ vuint32_t clkoutdiv;
+ uint32_t rec;
+
+ uint32_t rf0[4]; /* 0xf0 */
+
+ vuint32_t pioporcap0; /* 0x100 */
+ vuint32_t pioporcap1;
+ uint32_t r102[2];
+
+ uint32_t r110[4]; /* 0x110 */
+ uint32_t r120[4]; /* 0x120 */
+ uint32_t r130[4]; /* 0x130 */
+ uint32_t r140[4]; /* 0x140 */
+
+ vuint32_t bodctrl; /* 0x150 */
+ vuint32_t systckcal;
+ uint32_t r158[2];
+
+ uint32_t r160[4]; /* 0x160 */
+
+ vuint32_t irqlatency; /* 0x170 */
+ vuint32_t nmisrc;
+ vuint32_t pintsel[8];
+
+ vuint32_t usbclkctrl; /* 0x198 */
+ vuint32_t usbclkst;
+
+ uint32_t r1a0[6*4]; /* 0x1a0 */
+
+ uint32_t r200; /* 0x200 */
+ vuint32_t starterp0;
+ uint32_t r208[2];
+
+ uint32_t r210; /* 0x210 */
+ vuint32_t starterp1;
+ uint32_t r218[2];
+
+ uint32_t r220[4]; /* 0x220 */
+
+ vuint32_t pdsleepcfg; /* 0x230 */
+ vuint32_t pdawakecfg;
+ vuint32_t pdruncfg;
+ uint32_t r23c;
+
+ uint32_t r240[12 * 4]; /* 0x240 */
+
+ uint32_t r300[15 * 4]; /* 0x300 */
+
+ uint32_t r3f0; /* 0x3f0 */
+ vuint32_t device_id;
+};
+
+extern struct lpc_scb lpc_scb;
+
+#define LPC_SCB_SYSMEMREMAP_MAP 0
+# define LPC_SCB_SYSMEMREMAP_MAP_BOOT_LOADER 0
+# define LPC_SCB_SYSMEMREMAP_MAP_RAM 1
+# define LPC_SCB_SYSMEMREMAP_MAP_FLASH 2
+
+#define LPC_SCB_PRESETCTRL_SSP0_RST_N 0
+#define LPC_SCB_PRESETCTRL_I2C_RST_N 1
+#define LPC_SCB_PRESETCTRL_SSP1_RST_N 2
+
+#define LPC_SCB_SYSPLLCTRL_MSEL 0
+#define LPC_SCB_SYSPLLCTRL_PSEL 5
+#define LPC_SCB_SYSPLLCTRL_PSEL_1 0
+#define LPC_SCB_SYSPLLCTRL_PSEL_2 1
+#define LPC_SCB_SYSPLLCTRL_PSEL_4 2
+#define LPC_SCB_SYSPLLCTRL_PSEL_8 3
+#define LPC_SCB_SYSPLLCTRL_PSEL_MASK 3
+
+#define LPC_SCB_SYSPLLSTAT_LOCK 0
+
+#define LPC_SCB_USBPLLCTRL_MSEL 0
+#define LPC_SCB_USBPLLCTRL_PSEL 5
+#define LPC_SCB_USBPLLCTRL_PSEL_1 0
+#define LPC_SCB_USBPLLCTRL_PSEL_2 1
+#define LPC_SCB_USBPLLCTRL_PSEL_4 2
+#define LPC_SCB_USBPLLCTRL_PSEL_8 3
+#define LPC_SCB_USBPLLCTRL_PSEL_MASK 3
+
+#define LPC_SCB_USBPLLSTAT_LOCK 0
+
+#define LPC_SCB_SYSOSCCTRL_BYPASS 0
+#define LPC_SCB_SYSOSCCTRL_FREQRANGE 1
+#define LPC_SCB_SYSOSCCTRL_FREQRANGE_1_20 0
+#define LPC_SCB_SYSOSCCTRL_FREQRANGE_15_25 1
+
+#define LPC_SCB_WDTOSCCTRL_DIVSEL 0
+#define LPC_SCB_WDTOSCCTRL_DIVSEL_MASK 0x1f
+#define LPC_SCB_WDTOSCCTRL_FREQSEL 5
+#define LPC_SCB_WDTOSCCTRL_FREQSEL_0_6 1
+#define LPC_SCB_WDTOSCCTRL_FREQSEL_1_05 2
+#define LPC_SCB_WDTOSCCTRL_FREQSEL_1_4 3
+#define LPC_SCB_WDTOSCCTRL_FREQSEL_1_75 4
+#define LPC_SCB_WDTOSCCTRL_FREQSEL_2_1 5
+#define LPC_SCB_WDTOSCCTRL_FREQSEL_2_4 6
+#define LPC_SCB_WDTOSCCTRL_FREQSEL_2_7 7
+#define LPC_SCB_WDTOSCCTRL_FREQSEL_3_0 8
+#define LPC_SCB_WDTOSCCTRL_FREQSEL_3_25 9
+#define LPC_SCB_WDTOSCCTRL_FREQSEL_3_5 0x0a
+#define LPC_SCB_WDTOSCCTRL_FREQSEL_3_75 0x0b
+#define LPC_SCB_WDTOSCCTRL_FREQSEL_4_0 0x0c
+#define LPC_SCB_WDTOSCCTRL_FREQSEL_4_2 0x0d
+#define LPC_SCB_WDTOSCCTRL_FREQSEL_4_4 0x0e
+#define LPC_SCB_WDTOSCCTRL_FREQSEL_4_6 0x0f
+#define LPC_SCB_WDTOSCCTRL_FREQSEL_MASK 0x0f
+
+#define LPC_SCB_SYSRSTSTAT_POR 0
+#define LPC_SCB_SYSRSTSTAT_EXTRST 1
+#define LPC_SCB_SYSRSTSTAT_WDT 2
+#define LPC_SCB_SYSRSTSTAT_BOD 3
+#define LPC_SCB_SYSRSTSTAT_SYSRST 4
+
+#define LPC_SCB_SYSPLLCLKSEL_SEL 0
+#define LPC_SCB_SYSPLLCLKSEL_SEL_IRC 0
+#define LPC_SCB_SYSPLLCLKSEL_SEL_SYSOSC 1
+#define LPC_SCB_SYSPLLCLKSEL_SEL_MASK 3
+
+#define LPC_SCB_SYSPLLCLKUEN_ENA 0
+
+#define LPC_SCB_USBPLLCLKSEL_SEL 0
+#define LPC_SCB_USBPLLCLKSEL_SEL_IRC 0
+#define LPC_SCB_USBPLLCLKSEL_SEL_SYSOSC 1
+#define LPC_SCB_USBPLLCLKSEL_SEL_MASK 3
+
+#define LPC_SCB_USBPLLCLKUEN_ENA 0
+
+#define LPC_SCB_MAINCLKSEL_SEL 0
+#define LPC_SCB_MAINCLKSEL_SEL_IRC 0
+#define LPC_SCB_MAINCLKSEL_SEL_PLL_INPUT 1
+#define LPC_SCB_MAINCLKSEL_SEL_WATCHDOG 2
+#define LPC_SCB_MAINCLKSEL_SEL_PLL_OUTPUT 3
+#define LPC_SCB_MAINCLKSEL_SEL_MASK 3
+
+#define LPC_SCB_MAINCLKUEN_ENA 0
+
+#define LPC_SCB_SYSAHBCLKDIV_DIV 0
+
+#define LPC_SCB_SYSAHBCLKCTRL_SYS 0
+#define LPC_SCB_SYSAHBCLKCTRL_ROM 1
+#define LPC_SCB_SYSAHBCLKCTRL_RAM0 2
+#define LPC_SCB_SYSAHBCLKCTRL_FLASHREG 3
+#define LPC_SCB_SYSAHBCLKCTRL_FLASHARRAY 4
+#define LPC_SCB_SYSAHBCLKCTRL_I2C 5
+#define LPC_SCB_SYSAHBCLKCTRL_GPIO 6
+#define LPC_SCB_SYSAHBCLKCTRL_CT16B0 7
+#define LPC_SCB_SYSAHBCLKCTRL_CT16B1 8
+#define LPC_SCB_SYSAHBCLKCTRL_CT32B0 9
+#define LPC_SCB_SYSAHBCLKCTRL_CT32B1 10
+#define LPC_SCB_SYSAHBCLKCTRL_SSP0 11
+#define LPC_SCB_SYSAHBCLKCTRL_USART 12
+#define LPC_SCB_SYSAHBCLKCTRL_ADC 13
+#define LPC_SCB_SYSAHBCLKCTRL_USB 14
+#define LPC_SCB_SYSAHBCLKCTRL_WWDT 15
+#define LPC_SCB_SYSAHBCLKCTRL_IOCON 16
+#define LPC_SCB_SYSAHBCLKCTRL_SSP1 18
+#define LPC_SCB_SYSAHBCLKCTRL_PINT 19
+#define LPC_SCB_SYSAHBCLKCTRL_GROUP0INT 23
+#define LPC_SCB_SYSAHBCLKCTRL_GROUP1INT 24
+#define LPC_SCB_SYSAHBCLKCTRL_RAM1 26
+#define LPC_SCB_SYSAHBCLKCTRL_USBRAM 27
+
+#define LPC_SCB_SSP0CLKDIV_
+#define LPC_SCB_UARTCLKDIV_
+#define LPC_SCB_SSP1CLKDIV_
+
+#define LPC_SCB_USBCLKSEL_SEL 0
+#define LPC_SCB_USBCLKSEL_SEL_USB_PLL 0
+#define LPC_SCB_USBCLKSEL_SEL_MAIN_CLOCK 1
+
+#define LPC_SCB_USBCLKUEN_ENA 0
+#define LPC_SCB_USBCLKDIV_DIV 0
+
+#define LPC_SCB_CLKOUTSEL_SEL 0
+#define LPC_SCB_CLKOUTSEL_SEL_IRC 0
+#define LPC_SCB_CLKOUTSEL_SEL_SYSOSC 1
+#define LPC_SCB_CLKOUTSEL_SEL_LF 2
+#define LPC_SCB_CLKOUTSEL_SEL_MAIN_CLOCK 3
+
+#define LPC_SCB_CLKOUTUEN_ENA 0
+
+#define LPC_SCB_BOD_BODRSTLEV 0
+# define LPC_SCB_BOD_BODRSTLEV_1_46 0
+# define LPC_SCB_BOD_BODRSTLEV_2_06 1
+# define LPC_SCB_BOD_BODRSTLEV_2_35 2
+# define LPC_SCB_BOD_BODRSTLEV_2_63 3
+#define LPC_SCB_BOD_BODINTVAL 2
+# define LPC_SCB_BOD_BODINTVAL_RESERVED 0
+# define LPC_SCB_BOD_BODINTVAL_2_22 1
+# define LPC_SCB_BOD_BODINTVAL_2_52 2
+# define LPC_SCB_BOD_BODINTVAL_2_80 3
+#define LPC_SCB_BOD_BODRSTENA 4
+
+#define LPC_SCB_PDRUNCFG_IRCOUT_PD 0
+#define LPC_SCB_PDRUNCFG_IRC_PD 1
+#define LPC_SCB_PDRUNCFG_FLASH_PD 2
+#define LPC_SCB_PDRUNCFG_BOD_PD 3
+#define LPC_SCB_PDRUNCFG_ADC_PD 4
+#define LPC_SCB_PDRUNCFG_SYSOSC_PD 5
+#define LPC_SCB_PDRUNCFG_WDTOSC_PD 6
+#define LPC_SCB_PDRUNCFG_SYSPLL_PD 7
+#define LPC_SCB_PDRUNCFG_USBPLL_PD 8
+#define LPC_SCB_PDRUNCFG_USBPAD_PD 10
+
+struct lpc_flash {
+ uint32_t r0[4]; /* 0x0 */
+
+ vuint32_t flashcfg; /* 0x10 */
+};
+
+extern struct lpc_flash lpc_flash;
+
+struct lpc_gpio_pin {
+ vuint32_t isel; /* 0x00 */
+ vuint32_t ienr;
+ vuint32_t sienr;
+ vuint32_t cienr;
+
+ vuint32_t ienf; /* 0x10 */
+ vuint32_t sienf;
+ vuint32_t cienf;
+ vuint32_t rise;
+
+ vuint32_t fall; /* 0x20 */
+ vuint32_t ist;
+};
+
+extern struct lpc_gpio_pin lpc_gpio_pin;
+
+struct lpc_gpio_group0 {
+};
+
+extern struct lpc_gpio_group0 lpc_gpio_group0;
+
+struct lpc_gpio_group1 {
+};
+
+extern struct lpc_gpio_group1 lpc_gpio_group1;
+
+struct lpc_gpio {
+ vuint8_t byte[0x40]; /* 0x0000 */
+
+ uint8_t r0030[0x1000 - 0x40];
+
+ vuint32_t word[0x40]; /* 0x1000 */
+
+ uint8_t r1100[0x2000 - 0x1100];
+
+ vuint32_t dir[2]; /* 0x2000 */
+
+ uint8_t r2008[0x2080 - 0x2008];
+
+ vuint32_t mask[2]; /* 0x2080 */
+
+ uint8_t r2088[0x2100 - 0x2088];
+
+ vuint32_t pin[2]; /* 0x2100 */
+
+ uint8_t r2108[0x2200 - 0x2108];
+
+ vuint32_t set[2]; /* 0x2200 */
+
+ uint8_t r2208[0x2280 - 0x2208];
+
+ vuint32_t clr[2]; /* 0x2280 */
+
+ uint8_t r2288[0x2300 - 0x2288];
+
+ vuint32_t not[2]; /* 0x2300 */
+};
+
+extern struct lpc_gpio lpc_gpio;
+
+struct lpc_systick {
+ uint8_t r0000[0x10]; /* 0x0000 */
+
+ vuint32_t csr; /* 0x0010 */
+ vuint32_t rvr;
+ vuint32_t cvr;
+ vuint32_t calib;
+};
+
+extern struct lpc_systick lpc_systick;
+
+#define LPC_SYSTICK_CSR_ENABLE 0
+#define LPC_SYSTICK_CSR_TICKINT 1
+#define LPC_SYSTICK_CSR_CLKSOURCE 2
+#define LPC_SYSTICK_CSR_CLKSOURCE_CPU_OVER_2 0
+#define LPC_SYSTICK_CSR_CLKSOURCE_CPU 1
+#define LPC_SYSTICK_CSR_COUNTFLAG 16
+
+struct lpc_usart {
+ vuint32_t rbr_thr; /* 0x0000 */
+ vuint32_t ier;
+ vuint32_t iir_fcr;
+ vuint32_t lcr;
+
+ vuint32_t mcr; /* 0x0010 */
+ vuint32_t lsr;
+ vuint32_t msr;
+ vuint32_t scr;
+
+ vuint32_t acr; /* 0x0020 */
+ vuint32_t icr;
+ vuint32_t fdr;
+ vuint32_t osr;
+
+ vuint32_t ter; /* 0x0030 */
+ uint32_t r34[3];
+
+ vuint32_t hden; /* 0x0040 */
+ uint32_t r44;
+ vuint32_t scictrl;
+ vuint32_t rs485ctrl;
+
+ vuint32_t rs485addrmatch; /* 0x0050 */
+ vuint32_t rs485dly;
+ vuint32_t syncctrl;
+};
+
+extern struct lpc_usart lpc_usart;
+
+#define LPC_USART_IER_RBRINTEN 0
+#define LPC_USART_IER_THREINTEN 1
+#define LPC_USART_IER_RSLINTEN 2
+#define LPC_USART_IER_MSINTEN 3
+#define LPC_USART_IER_ABEOINTEN 8
+#define LPC_USART_IER_ABTOINTEN 9
+
+#define LPC_USART_IIR_INTSTATUS 0
+#define LPC_USART_IIR_INTID 1
+#define LPC_USART_IIR_INTID_RLS 3
+#define LPC_USART_IIR_INTID_RDA 2
+#define LPC_USART_IIR_INTID_CTI 6
+#define LPC_USART_IIR_INTID_THRE 1
+#define LPC_USART_IIR_INTID_MS 0
+#define LPC_USART_IIR_INTID_MASK 7
+#define LPC_USART_IIR_FIFOEN 6
+#define LPC_USART_IIR_ABEOINT 8
+#define LPC_USART_IIR_ABTOINT 9
+
+#define LPC_USART_FCR_FIFOEN 0
+#define LPC_USART_FCR_RXFIFORES 1
+#define LPC_USART_FCR_TXFIFORES 2
+#define LPC_USART_FCR_RXTL 6
+#define LPC_USART_FCR_RXTL_1 0
+#define LPC_USART_FCR_RXTL_4 1
+#define LPC_USART_FCR_RXTL_8 2
+#define LPC_USART_FCR_RXTL_14 3
+
+#define LPC_USART_LCR_WLS 0
+#define LPC_USART_LCR_WLS_5 0
+#define LPC_USART_LCR_WLS_6 1
+#define LPC_USART_LCR_WLS_7 2
+#define LPC_USART_LCR_WLS_8 3
+#define LPC_USART_LCR_WLS_MASK 3
+#define LPC_USART_LCR_SBS 2
+#define LPC_USART_LCR_SBS_1 0
+#define LPC_USART_LCR_SBS_2 1
+#define LPC_USART_LCR_SBS_MASK 1
+#define LPC_USART_LCR_PE 3
+#define LPC_USART_LCR_PS 4
+#define LPC_USART_LCR_PS_ODD 0
+#define LPC_USART_LCR_PS_EVEN 1
+#define LPC_USART_LCR_PS_ONE 2
+#define LPC_USART_LCR_PS_ZERO 3
+#define LPC_USART_LCR_PS_MASK 3
+#define LPC_USART_LCR_BC 6
+#define LPC_USART_LCR_DLAB 7
+
+#define LPC_USART_MCR_DTRCTRL 0
+#define LPC_USART_MCR_RTSCTRL 1
+#define LPC_USART_MCR_LMS 4
+#define LPC_USART_MCR_RTSEN 6
+#define LPC_USART_MCR_CTSEN 7
+
+#define LPC_USART_LSR_RDR 0
+#define LPC_USART_LSR_OE 1
+#define LPC_USART_LSR_PE 2
+#define LPC_USART_LSR_FE 3
+#define LPC_USART_LSR_BI 4
+#define LPC_USART_LSR_THRE 5
+#define LPC_USART_LSR_TEMT 6
+#define LPC_USART_LSR_RXFE 7
+#define LPC_USART_LSR_TXERR 8
+
+#define LPC_USART_MSR_DCTS 0
+#define LPC_USART_MSR_DDSR 1
+#define LPC_USART_MSR_TERI 2
+#define LPC_USART_MSR_DDCD 3
+#define LPC_USART_MSR_CTS 4
+#define LPC_USART_MSR_DSR 5
+#define LPC_USART_MSR_RI 6
+#define LPC_USART_MSR_DCD 7
+
+#define LPC_USART_ACR_START 0
+#define LPC_USART_ACR_MODE 1
+#define LPC_USART_ACR_AUTORESTART 2
+#define LPC_USART_ACR_ABEOINTCLR 8
+#define LPC_USART_ACR_ABTOINTCLR 9
+
+#define LPC_USART_FDR_DIVADDVAL 0
+#define LPC_USART_FDR_MULVAL 4
+
+#define LPC_USART_OSR_OSFRAC 1
+#define LPC_USART_OSR_OSINT 4
+#define LPC_USART_OSR_FDINT 8
+
+#define LPC_USART_TER_TXEN 7
+
+#define LPC_USART_HDEN_HDEN 0
+
+struct lpc_usb {
+ vuint32_t devcmdstat;
+ vuint32_t info;
+ vuint32_t epliststart;
+ vuint32_t databufstart;
+ vuint32_t lpm;
+ vuint32_t epskip;
+ vuint32_t epinuse;
+ vuint32_t epbufcfg;
+ vuint32_t intstat;
+ vuint32_t inten;
+ vuint32_t intsetstat;
+ vuint32_t introuting;
+ uint32_t r30;
+ vuint32_t eptoggle;
+} lpc_usb;
+
+extern struct lpc_usb lpc_usb;
+
+#define LPC_USB_DEVCMDSTAT_DEV_ADDR 0
+#define LPC_USB_DEVCMDSTAT_DEV_ADDR_MASK 0x7f
+#define LPC_USB_DEVCMDSTAT_DEV_EN 7
+#define LPC_USB_DEVCMDSTAT_SETUP 8
+#define LPC_USB_DEVCMDSTAT_PLL_ON 9
+#define LPC_USB_DEVCMDSTAT_LPM_SUP 11
+#define LPC_USB_DEVCMDSTAT_INTONNAK_AO 12
+#define LPC_USB_DEVCMDSTAT_INTONNAK_AI 13
+#define LPC_USB_DEVCMDSTAT_INTONNAK_CO 14
+#define LPC_USB_DEVCMDSTAT_INTONNAK_CI 15
+#define LPC_USB_DEVCMDSTAT_DCON 16
+#define LPC_USB_DEVCMDSTAT_DSUS 17
+#define LPC_USB_DEVCMDSTAT_LPM_SUS 19
+#define LPC_USB_DEVCMDSTAT_LPM_REWP 20
+#define LPC_USB_DEVCMDSTAT_DCON_C 24
+#define LPC_USB_DEVCMDSTAT_DSUS_C 25
+#define LPC_USB_DEVCMDSTAT_DRES_C 26
+#define LPC_USB_DEVCMDSTAT_VBUSDEBOUNCED 28
+
+#define LPC_USB_INFO_FRAME_NR 0
+#define LPC_USB_INFO_FRAME_NR_MASK 0x3ff
+#define LPC_USB_INFO_ERR_CODE 11
+#define LPC_USB_INFO_ERR_CODE_NO_ERROR 0
+#define LPC_USB_INFO_ERR_CODE_PID_ENCODING_ERROR 1
+#define LPC_USB_INFO_ERR_CODE_PID_UNKNOWN 2
+#define LPC_USB_INFO_ERR_CODE_PACKET_UNEXPECTED 3
+#define LPC_USB_INFO_ERR_CODE_TOKEN_CRC_ERROR 4
+#define LPC_USB_INFO_ERR_CODE_DATA_CRC_ERROR 5
+#define LPC_USB_INFO_ERR_CODE_TIME_OUT 6
+#define LPC_USB_INFO_ERR_CODE_BABBLE 7
+#define LPC_USB_INFO_ERR_CODE_TRUNCATED_EOP 8
+#define LPC_USB_INFO_ERR_CODE_SENT_RECEIVED_NAK 9
+#define LPC_USB_INFO_ERR_CODE_SENT_STALL 0xa
+#define LPC_USB_INFO_ERR_CODE_OVERRUN 0xb
+#define LPC_USB_INFO_ERR_CODE_SENT_EMPTY_PACKET 0xc
+#define LPC_USB_INFO_ERR_CODE_BITSTUFF_ERROR 0xd
+#define LPC_USB_INFO_ERR_CODE_SYNC_ERROR 0xe
+#define LPC_USB_INFO_ERR_CODE_WRONG_DATA_TOGGLE 0xf
+#define LPC_USB_INFO_ERR_CODE_MASK 0xf
+
+#define LPC_USB_EPLISTSTART_EP_LIST 0
+
+#define LPC_USB_DATABUFSTART_DA_BUF 0
+
+#define LPC_USB_LPM_HIRD_HW 0
+#define LPC_USB_LPM_HIRD_HW_MASK 0xf
+#define LPC_USB_LPM_HIRD_SW 4
+#define LPC_USB_LPM_HIRD_SW_MASK 0xf
+#define LPC_USB_LPM_DATA_PENDING 8
+
+#define LPC_USB_EPSKIP_SKIP 0
+
+#define LPC_USB_EPINUSE_BUF(ep) (ep)
+
+#define LPC_USB_EPBUFCFG_BUF_SB(ep) (ep)
+
+#define LPC_USB_INT_EPOUT(ep) ((ep) << 1)
+#define LPC_USB_INT_EPIN(ep) (((ep) << 1) + 1)
+
+#define LPC_USB_INT_FRAME 30
+#define LPC_USB_INT_DEV 31
+
+#define LPC_USB_INTIN_EP_INT_EN(ep) (ep)
+#define LPC_USB_INTIN_FRAME_INT_EN 30
+#define LPC_USB_INTIN_DEV_INT_EN 31
+
+#define LPC_USB_INTSETSTAT_EP_SET_INT(ep) (ep)
+#define LPC_USB_INTSETSTAT_FRAME_SET_INT 30
+#define LPC_USB_INTSETSTAT_DEV_SET_INT 31
+
+#define LPC_USB_INTROUTING_ROUTE_INT(ep) (ep)
+#define LPC_USB_INTROUTING_INT30 30
+#define LPC_USB_INTROUTING_INT31 31
+
+#define LPC_USB_EPTOGGLE_TOGGLE(ep) (ep)
+
+struct lpc_usb_epn {
+ vuint32_t out[2];
+ vuint32_t in[2];
+};
+
+struct lpc_usb_endpoint {
+ vuint32_t ep0_out;
+ vuint32_t setup;
+ vuint32_t ep0_in;
+ vuint32_t reserved_0c;
+ struct lpc_usb_epn epn[4];
+};
+
+/* Assigned in registers.ld to point at the base
+ * of USB ram
+ */
+
+extern uint8_t lpc_usb_sram[];
+
+#define LPC_USB_EP_ACTIVE 31
+#define LPC_USB_EP_DISABLED 30
+#define LPC_USB_EP_STALL 29
+#define LPC_USB_EP_TOGGLE_RESET 28
+#define LPC_USB_EP_RATE_FEEDBACK 27
+#define LPC_USB_EP_ENDPOINT_ISO 26
+#define LPC_USB_EP_NBYTES 16
+#define LPC_USB_EP_NBYTES_MASK 0x3ff
+#define LPC_USB_EP_OFFSET 0
+
+#define LPC_ISR_PIN_INT0_POS 0
+#define LPC_ISR_PIN_INT1_POS 1
+#define LPC_ISR_PIN_INT2_POS 2
+#define LPC_ISR_PIN_INT3_POS 3
+#define LPC_ISR_PIN_INT4_POS 4
+#define LPC_ISR_PIN_INT5_POS 5
+#define LPC_ISR_PIN_INT6_POS 6
+#define LPC_ISR_PIN_INT7_POS 7
+#define LPC_ISR_GINT0_POS 8
+#define LPC_ISR_GINT1_POS 9
+#define LPC_ISR_SSP1_POS 14
+#define LPC_ISR_I2C_POS 15
+#define LPC_ISR_CT16B0_POS 16
+#define LPC_ISR_CT16B1_POS 17
+#define LPC_ISR_CT32B0_POS 18
+#define LPC_ISR_CT32B1_POS 19
+#define LPC_ISR_SSP0_POS 20
+#define LPC_ISR_USART_POS 21
+#define LPC_ISR_USB_IRQ_POS 22
+#define LPC_ISR_USB_FIQ_POS 23
+#define LPC_ISR_ADC_POS 24
+#define LPC_ISR_WWDT_POS 25
+#define LPC_ISR_BOD_POS 26
+#define LPC_ISR_FLASH_POS 27
+#define LPC_ISR_USB_WAKEUP_POS 30
+
+struct lpc_nvic {
+ vuint32_t iser; /* 0x000 0xe000e100 Set Enable Register */
+
+ uint8_t _unused020[0x080 - 0x004];
+
+ vuint32_t icer; /* 0x080 0xe000e180 Clear Enable Register */
+
+ uint8_t _unused0a0[0x100 - 0x084];
+
+ vuint32_t ispr; /* 0x100 0xe000e200 Set Pending Register */
+
+ uint8_t _unused120[0x180 - 0x104];
+
+ vuint32_t icpr; /* 0x180 0xe000e280 Clear Pending Register */
+
+ uint8_t _unused1a0[0x300 - 0x184];
+
+ vuint32_t ipr[8]; /* 0x300 0xe000e400 Priority Register */
+};
+
+extern struct lpc_nvic lpc_nvic;
+
+static inline void
+lpc_nvic_set_enable(int irq) {
+ lpc_nvic.iser = (1 << irq);
+}
+
+static inline void
+lpc_nvic_clear_enable(int irq) {
+ lpc_nvic.icer = (1 << irq);
+}
+
+static inline int
+lpc_nvic_enabled(int irq) {
+ return (lpc_nvic.iser >> irq) & 1;
+}
+
+
+static inline void
+lpc_nvic_set_pending(int irq) {
+ lpc_nvic.ispr = (1 << irq);
+}
+
+static inline void
+lpc_nvic_clear_pending(int irq) {
+ lpc_nvic.icpr = (1 << irq);
+}
+
+static inline int
+lpc_nvic_pending(int irq) {
+ return (lpc_nvic.ispr >> irq) & 1;
+}
+
+#define IRQ_PRIO_REG(irq) ((irq) >> 2)
+#define IRQ_PRIO_BIT(irq) (((irq) & 3) << 3)
+#define IRQ_PRIO_MASK(irq) (0xff << IRQ_PRIO_BIT(irq))
+
+static inline void
+lpc_nvic_set_priority(int irq, uint8_t prio) {
+ int n = IRQ_PRIO_REG(irq);
+ uint32_t v;
+
+ v = lpc_nvic.ipr[n];
+ v &= ~IRQ_PRIO_MASK(irq);
+ v |= (prio) << IRQ_PRIO_BIT(irq);
+ lpc_nvic.ipr[n] = v;
+}
+
+static inline uint8_t
+lpc_nvic_get_priority(int irq) {
+ return (lpc_nvic.ipr[IRQ_PRIO_REG(irq)] >> IRQ_PRIO_BIT(irq)) & IRQ_PRIO_MASK(0);
+}
+
+struct arm_scb {
+ vuint32_t cpuid;
+ vuint32_t icsr;
+ uint32_t reserved08;
+ vuint32_t aircr;
+
+ vuint32_t scr;
+ vuint32_t ccr;
+ uint32_t reserved18;
+ vuint32_t shpr2;
+
+ vuint32_t shpr3;
+};
+
+extern struct arm_scb arm_scb;
+
+struct lpc_ssp {
+ vuint32_t cr0; /* 0x00 */
+ vuint32_t cr1;
+ vuint32_t dr;
+ vuint32_t sr;
+
+ vuint32_t cpsr; /* 0x10 */
+ vuint32_t imsc;
+ vuint32_t ris;
+ vuint32_t mis;
+
+ vuint32_t icr; /* 0x20 */
+};
+
+extern struct lpc_ssp lpc_ssp0, lpc_ssp1;
+
+#define LPC_NUM_SPI 2
+
+#define LPC_SSP_FIFOSIZE 8
+
+#define LPC_SSP_CR0_DSS 0
+#define LPC_SSP_CR0_DSS_4 0x3
+#define LPC_SSP_CR0_DSS_5 0x4
+#define LPC_SSP_CR0_DSS_6 0x5
+#define LPC_SSP_CR0_DSS_7 0x6
+#define LPC_SSP_CR0_DSS_8 0x7
+#define LPC_SSP_CR0_DSS_9 0x8
+#define LPC_SSP_CR0_DSS_10 0x9
+#define LPC_SSP_CR0_DSS_11 0xa
+#define LPC_SSP_CR0_DSS_12 0xb
+#define LPC_SSP_CR0_DSS_13 0xc
+#define LPC_SSP_CR0_DSS_14 0xd
+#define LPC_SSP_CR0_DSS_15 0xe
+#define LPC_SSP_CR0_DSS_16 0xf
+#define LPC_SSP_CR0_FRF 4
+#define LPC_SSP_CR0_FRF_SPI 0
+#define LPC_SSP_CR0_FRF_TI 1
+#define LPC_SSP_CR0_FRF_MICROWIRE 2
+#define LPC_SSP_CR0_CPOL 6
+#define LPC_SSP_CR0_CPOL_LOW 0
+#define LPC_SSP_CR0_CPOL_HIGH 1
+#define LPC_SSP_CR0_CPHA 7
+#define LPC_SSP_CR0_CPHA_FIRST 0
+#define LPC_SSP_CR0_CPHA_SECOND 1
+#define LPC_SSP_CR0_SCR 8
+
+#define LPC_SSP_CR1_LBM 0
+#define LPC_SSP_CR1_SSE 1
+#define LPC_SSP_CR1_MS 2
+#define LPC_SSP_CR1_MS_MASTER 0
+#define LPC_SSP_CR1_MS_SLAVE 1
+#define LPC_SSP_CR1_SOD 3
+
+#define LPC_SSP_SR_TFE 0
+#define LPC_SSP_SR_TNF 1
+#define LPC_SSP_SR_RNE 2
+#define LPC_SSP_SR_RFF 3
+#define LPC_SSP_SR_BSY 4
+
+#define LPC_SSP_IMSC_RORIM 0
+#define LPC_SSP_IMSC_RTIM 1
+#define LPC_SSP_IMSC_RXIM 2
+#define LPC_SSP_IMSC_TXIM 3
+
+#define LPC_SSP_RIS_RORRIS 0
+#define LPC_SSP_RIS_RTRIS 1
+#define LPC_SSP_RIS_RXRIS 2
+#define LPC_SSP_RIS_TXRIS 3
+
+#define LPC_SSP_MIS_RORMIS 0
+#define LPC_SSP_MIS_RTMIS 1
+#define LPC_SSP_MIS_RXMIS 2
+#define LPC_SSP_MIS_TXMIS 3
+
+#define LPC_SSP_ICR_RORIC 0
+#define LPC_SSP_ICR_RTIC 1
+
+struct lpc_adc {
+ vuint32_t cr; /* 0x00 */
+ vuint32_t gdr;
+ uint32_t r08;
+ vuint32_t inten;
+
+ vuint32_t dr[8]; /* 0x10 */
+
+ vuint32_t stat; /* 0x30 */
+};
+
+extern struct lpc_adc lpc_adc;
+
+#define LPC_ADC_CR_SEL 0
+#define LPC_ADC_CR_CLKDIV 8
+#define LPC_ADC_CR_BURST 16
+#define LPC_ADC_CR_CLKS 17
+#define LPC_ADC_CR_CLKS_11 0
+#define LPC_ADC_CR_CLKS_10 1
+#define LPC_ADC_CR_CLKS_9 2
+#define LPC_ADC_CR_CLKS_8 3
+#define LPC_ADC_CR_CLKS_7 4
+#define LPC_ADC_CR_CLKS_6 5
+#define LPC_ADC_CR_CLKS_5 6
+#define LPC_ADC_CR_CLKS_4 7
+#define LPC_ADC_CR_START 24
+#define LPC_ADC_CR_START_NONE 0
+#define LPC_ADC_CR_START_NOW 1
+
+#define LPC_ADC_GDR_CHN 24
+#define LPC_ADC_GDR_OVERRUN 30
+#define LPC_ADC_GDR_DONE 31
+
+#define LPC_ADC_INTEN_ADINTEN 0
+#define LPC_ADC_INTEN_ADGINTEN 8
+
+#define LPC_ADC_STAT_DONE 0
+#define LPC_ADC_STAT_OVERRUN 8
+#define LPC_ADC_STAT_ADINT 16
+
+struct lpc_ct32b {
+ vuint32_t ir; /* 0x00 */
+ vuint32_t tcr;
+ vuint32_t tc;
+ vuint32_t pr;
+
+ vuint32_t pc; /* 0x10 */
+ vuint32_t mcr;
+ vuint32_t mr[4]; /* 0x18 */
+ vuint32_t ccr; /* 0x28 */
+ vuint32_t cr0;
+
+ vuint32_t cr1_0; /* 0x30 (only for ct32b0 */
+ vuint32_t cr1_1; /* 0x34 (only for ct32b1 */
+ uint32_t r38;
+ vuint32_t emr;
+
+ uint32_t r40[12];
+
+ vuint32_t ctcr; /* 0x70 */
+ vuint32_t pwmc;
+};
+
+extern struct lpc_ct32b lpc_ct32b0, lpc_ct32b1;
+
+#define LPC_CT32B_TCR_CEN 0
+#define LPC_CT32B_TCR_CRST 1
+
+#define LPC_CT32B_MCR_MR0R 1
+
+#define LPC_CT32B_PWMC_PWMEN0 0
+#define LPC_CT32B_PWMC_PWMEN1 1
+#define LPC_CT32B_PWMC_PWMEN2 2
+#define LPC_CT32B_PWMC_PWMEN3 3
+
+#define LPC_CT32B_EMR_EMC0 4
+#define LPC_CT32B_EMR_EMC1 6
+#define LPC_CT32B_EMR_EMC2 8
+#define LPC_CT32B_EMR_EMC3 10
+
+#define LPC_CT32B_EMR_EMC_NOTHING 0
+#define LPC_CT32B_EMR_EMC_CLEAR 1
+#define LPC_CT32B_EMR_EMC_SET 2
+#define LPC_CT32B_EMR_EMC_TOGGLE 3
+
+#endif /* _LPC_H_ */
--- /dev/null
+lpc_usb_sram = 0x20004000;
+lpc_usb_endpoint = 0x20004700;
+lpc_usart = 0x40008000;
+lpc_ct32b0 = 0x40014000;
+lpc_ct32b1 = 0x40018000;
+lpc_adc = 0x4001c000;
+lpc_flash = 0x4003c000;
+lpc_ssp0 = 0x40040000;
+lpc_ioconf = 0x40044000;
+lpc_scb = 0x40048000;
+lpc_gpio_pin = 0x4004c000;
+lpc_ssp1 = 0x40058000;
+lpc_gpio_group0 = 0x4005c000;
+lpc_gpio_group1 = 0x40060000;
+lpc_usb = 0x40080000;
+lpc_gpio = 0x50000000;
+lpc_systick = 0xe000e000;
+lpc_nvic = 0xe000e100;
+arm_scb = 0xe000ed00;
--- /dev/null
+ao_product.h
+ao_serial_lpc.h
+*.elf
--- /dev/null
+#
+# AltOS build
+#
+#
+
+include ../lpc/Makefile.defs
+
+INC = \
+ ao.h \
+ ao_arch.h \
+ ao_arch_funcs.h \
+ ao_pins.h \
+ ao_product.h \
+ lpc.h
+
+#
+# Common AltOS sources
+#
+ALTOS_SRC = \
+ ao_interrupt.c \
+ ao_romconfig.c \
+ ao_product.c \
+ ao_panic.c \
+ ao_led_lpc.c \
+ ao_task.c \
+ ao_cmd.c \
+ ao_timer_lpc.c \
+ ao_serial_lpc.c \
+ ao_usb_lpc.c \
+ ao_stdio.c
+
+PRODUCT=LpcDemo-v0.0
+PRODUCT_DEF=-DLPC_DEMO
+IDPRODUCT=0x000a
+
+CFLAGS = $(PRODUCT_DEF) $(LPC_CFLAGS) -g -Os
+
+PROG=lpc-demo.elf
+
+SRC=$(ALTOS_SRC) ao_demo.c
+OBJ=$(SRC:.c=.o)
+
+all: $(PROG)
+
+LDFLAGS=-L../lpc -Wl,-Taltos.ld
+
+$(PROG): Makefile $(OBJ)
+ $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
+
+ao_product.h: ao-make-product.5c ../Version
+ $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@
+
+$(OBJ): $(INC)
+
+load: $(PROG)
+ lpc-load $(PROG)
+
+distclean: clean
+
+clean:
+ rm -f *.o $(PROG)
+ rm -f ao_product.h
+
+install:
+
+uninstall:
--- /dev/null
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+#include <ao_usb.h>
+
+int
+main(void)
+{
+ int i;
+ ao_led_init(LEDS_AVAILABLE);
+ ao_led_on(AO_LED_RED);
+ ao_clock_init();
+ ao_timer_init();
+
+ ao_serial_init();
+ ao_usb_init();
+ ao_cmd_init();
+ ao_task_init();
+
+ ao_start_scheduler();
+
+ for (;;) {
+ ao_led_off(AO_LED_RED);
+ for (;;)
+ if (ao_tick_count & 1)
+ break;
+ ao_led_on(AO_LED_RED);
+ for (;;)
+ if (!(ao_tick_count & 1))
+ break;
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#define HAS_BEEP 0
+#define HAS_LED 1
+
+/* Crystal on the board */
+#define AO_LPC_CLKIN 12000000
+
+/* Main clock frequency. 48MHz for USB so we don't use the USB PLL */
+#define AO_LPC_CLKOUT 48000000
+
+/* System clock frequency */
+#define AO_LPC_SYSCLK 24000000
+
+#define LED_PORT 0
+#define LED_PIN_RED 7
+
+#define AO_LED_RED (1 << LED_PIN_RED)
+
+#define LEDS_AVAILABLE AO_LED_RED
+
+#define HAS_USB 1
+
+#define HAS_USB_CONNECT 1
+#define HAS_USB_VBUS 1
+
+#define PACKET_HAS_SLAVE 0
+
+/* USART */
+
+#define HAS_SERIAL 1
+#define USE_SERIAL_0_STDIN 1
+#define SERIAL_0_18_19 1
+#define SERIAL_0_14_15 0
+#define SERIAL_0_17_18 0
+#define SERIAL_0_26_27 0
--- /dev/null
+/* ef_acos.c -- float version of e_acos.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+static const float
+#else
+static float
+#endif
+one = 1.0000000000e+00, /* 0x3F800000 */
+pi = 3.1415925026e+00, /* 0x40490fda */
+pio2_hi = 1.5707962513e+00, /* 0x3fc90fda */
+pio2_lo = 7.5497894159e-08, /* 0x33a22168 */
+pS0 = 1.6666667163e-01, /* 0x3e2aaaab */
+pS1 = -3.2556581497e-01, /* 0xbea6b090 */
+pS2 = 2.0121252537e-01, /* 0x3e4e0aa8 */
+pS3 = -4.0055535734e-02, /* 0xbd241146 */
+pS4 = 7.9153501429e-04, /* 0x3a4f7f04 */
+pS5 = 3.4793309169e-05, /* 0x3811ef08 */
+qS1 = -2.4033949375e+00, /* 0xc019d139 */
+qS2 = 2.0209457874e+00, /* 0x4001572d */
+qS3 = -6.8828397989e-01, /* 0xbf303361 */
+qS4 = 7.7038154006e-02; /* 0x3d9dc62e */
+
+#ifdef __STDC__
+ float __ieee754_acosf(float x)
+#else
+ float __ieee754_acosf(x)
+ float x;
+#endif
+{
+ float z,p,q,r,w,s,c,df;
+ __int32_t hx,ix;
+ GET_FLOAT_WORD(hx,x);
+ ix = hx&0x7fffffff;
+ if(ix==0x3f800000) { /* |x|==1 */
+ if(hx>0) return 0.0; /* acos(1) = 0 */
+ else return pi+(float)2.0*pio2_lo; /* acos(-1)= pi */
+ } else if(ix>0x3f800000) { /* |x| >= 1 */
+ return (x-x)/(x-x); /* acos(|x|>1) is NaN */
+ }
+ if(ix<0x3f000000) { /* |x| < 0.5 */
+ if(ix<=0x23000000) return pio2_hi+pio2_lo;/*if|x|<2**-57*/
+ z = x*x;
+ p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5)))));
+ q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4)));
+ r = p/q;
+ return pio2_hi - (x - (pio2_lo-x*r));
+ } else if (hx<0) { /* x < -0.5 */
+ z = (one+x)*(float)0.5;
+ p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5)))));
+ q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4)));
+ s = __ieee754_sqrtf(z);
+ r = p/q;
+ w = r*s-pio2_lo;
+ return pi - (float)2.0*(s+w);
+ } else { /* x > 0.5 */
+ __int32_t idf;
+ z = (one-x)*(float)0.5;
+ s = __ieee754_sqrtf(z);
+ df = s;
+ GET_FLOAT_WORD(idf,df);
+ SET_FLOAT_WORD(df,idf&0xfffff000);
+ c = (z-df*df)/(s+df);
+ p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5)))));
+ q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4)));
+ r = p/q;
+ w = r*s+c;
+ return (float)2.0*(df+w);
+ }
+}
--- /dev/null
+/* ef_rem_pio2.c -- float version of e_rem_pio2.c
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+/* __ieee754_rem_pio2f(x,y)
+ *
+ * return the remainder of x rem pi/2 in y[0]+y[1]
+ * use __kernel_rem_pio2f()
+ */
+
+#include "fdlibm.h"
+
+/*
+ * Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi
+ */
+#ifdef __STDC__
+static const __int32_t two_over_pi[] = {
+#else
+static __int32_t two_over_pi[] = {
+#endif
+0xA2, 0xF9, 0x83, 0x6E, 0x4E, 0x44, 0x15, 0x29, 0xFC,
+0x27, 0x57, 0xD1, 0xF5, 0x34, 0xDD, 0xC0, 0xDB, 0x62,
+0x95, 0x99, 0x3C, 0x43, 0x90, 0x41, 0xFE, 0x51, 0x63,
+0xAB, 0xDE, 0xBB, 0xC5, 0x61, 0xB7, 0x24, 0x6E, 0x3A,
+0x42, 0x4D, 0xD2, 0xE0, 0x06, 0x49, 0x2E, 0xEA, 0x09,
+0xD1, 0x92, 0x1C, 0xFE, 0x1D, 0xEB, 0x1C, 0xB1, 0x29,
+0xA7, 0x3E, 0xE8, 0x82, 0x35, 0xF5, 0x2E, 0xBB, 0x44,
+0x84, 0xE9, 0x9C, 0x70, 0x26, 0xB4, 0x5F, 0x7E, 0x41,
+0x39, 0x91, 0xD6, 0x39, 0x83, 0x53, 0x39, 0xF4, 0x9C,
+0x84, 0x5F, 0x8B, 0xBD, 0xF9, 0x28, 0x3B, 0x1F, 0xF8,
+0x97, 0xFF, 0xDE, 0x05, 0x98, 0x0F, 0xEF, 0x2F, 0x11,
+0x8B, 0x5A, 0x0A, 0x6D, 0x1F, 0x6D, 0x36, 0x7E, 0xCF,
+0x27, 0xCB, 0x09, 0xB7, 0x4F, 0x46, 0x3F, 0x66, 0x9E,
+0x5F, 0xEA, 0x2D, 0x75, 0x27, 0xBA, 0xC7, 0xEB, 0xE5,
+0xF1, 0x7B, 0x3D, 0x07, 0x39, 0xF7, 0x8A, 0x52, 0x92,
+0xEA, 0x6B, 0xFB, 0x5F, 0xB1, 0x1F, 0x8D, 0x5D, 0x08,
+0x56, 0x03, 0x30, 0x46, 0xFC, 0x7B, 0x6B, 0xAB, 0xF0,
+0xCF, 0xBC, 0x20, 0x9A, 0xF4, 0x36, 0x1D, 0xA9, 0xE3,
+0x91, 0x61, 0x5E, 0xE6, 0x1B, 0x08, 0x65, 0x99, 0x85,
+0x5F, 0x14, 0xA0, 0x68, 0x40, 0x8D, 0xFF, 0xD8, 0x80,
+0x4D, 0x73, 0x27, 0x31, 0x06, 0x06, 0x15, 0x56, 0xCA,
+0x73, 0xA8, 0xC9, 0x60, 0xE2, 0x7B, 0xC0, 0x8C, 0x6B,
+};
+
+/* This array is like the one in e_rem_pio2.c, but the numbers are
+ single precision and the last 8 bits are forced to 0. */
+#ifdef __STDC__
+static const __int32_t npio2_hw[] = {
+#else
+static __int32_t npio2_hw[] = {
+#endif
+0x3fc90f00, 0x40490f00, 0x4096cb00, 0x40c90f00, 0x40fb5300, 0x4116cb00,
+0x412fed00, 0x41490f00, 0x41623100, 0x417b5300, 0x418a3a00, 0x4196cb00,
+0x41a35c00, 0x41afed00, 0x41bc7e00, 0x41c90f00, 0x41d5a000, 0x41e23100,
+0x41eec200, 0x41fb5300, 0x4203f200, 0x420a3a00, 0x42108300, 0x4216cb00,
+0x421d1400, 0x42235c00, 0x4229a500, 0x422fed00, 0x42363600, 0x423c7e00,
+0x4242c700, 0x42490f00
+};
+
+/*
+ * invpio2: 24 bits of 2/pi
+ * pio2_1: first 17 bit of pi/2
+ * pio2_1t: pi/2 - pio2_1
+ * pio2_2: second 17 bit of pi/2
+ * pio2_2t: pi/2 - (pio2_1+pio2_2)
+ * pio2_3: third 17 bit of pi/2
+ * pio2_3t: pi/2 - (pio2_1+pio2_2+pio2_3)
+ */
+
+#ifdef __STDC__
+static const float
+#else
+static float
+#endif
+zero = 0.0000000000e+00, /* 0x00000000 */
+half = 5.0000000000e-01, /* 0x3f000000 */
+two8 = 2.5600000000e+02, /* 0x43800000 */
+invpio2 = 6.3661980629e-01, /* 0x3f22f984 */
+pio2_1 = 1.5707855225e+00, /* 0x3fc90f80 */
+pio2_1t = 1.0804334124e-05, /* 0x37354443 */
+pio2_2 = 1.0804273188e-05, /* 0x37354400 */
+pio2_2t = 6.0770999344e-11, /* 0x2e85a308 */
+pio2_3 = 6.0770943833e-11, /* 0x2e85a300 */
+pio2_3t = 6.1232342629e-17; /* 0x248d3132 */
+
+#ifdef __STDC__
+ __int32_t __ieee754_rem_pio2f(float x, float *y)
+#else
+ __int32_t __ieee754_rem_pio2f(x,y)
+ float x,y[];
+#endif
+{
+ float z,w,t,r,fn;
+ float tx[3];
+ __int32_t i,j,n,ix,hx;
+ int e0,nx;
+
+ GET_FLOAT_WORD(hx,x);
+ ix = hx&0x7fffffff;
+ if(ix<=0x3f490fd8) /* |x| ~<= pi/4 , no need for reduction */
+ {y[0] = x; y[1] = 0; return 0;}
+ if(ix<0x4016cbe4) { /* |x| < 3pi/4, special case with n=+-1 */
+ if(hx>0) {
+ z = x - pio2_1;
+ if((ix&0xfffffff0)!=0x3fc90fd0) { /* 24+24 bit pi OK */
+ y[0] = z - pio2_1t;
+ y[1] = (z-y[0])-pio2_1t;
+ } else { /* near pi/2, use 24+24+24 bit pi */
+ z -= pio2_2;
+ y[0] = z - pio2_2t;
+ y[1] = (z-y[0])-pio2_2t;
+ }
+ return 1;
+ } else { /* negative x */
+ z = x + pio2_1;
+ if((ix&0xfffffff0)!=0x3fc90fd0) { /* 24+24 bit pi OK */
+ y[0] = z + pio2_1t;
+ y[1] = (z-y[0])+pio2_1t;
+ } else { /* near pi/2, use 24+24+24 bit pi */
+ z += pio2_2;
+ y[0] = z + pio2_2t;
+ y[1] = (z-y[0])+pio2_2t;
+ }
+ return -1;
+ }
+ }
+ if(ix<=0x43490f80) { /* |x| ~<= 2^7*(pi/2), medium size */
+ t = fabsf(x);
+ n = (__int32_t) (t*invpio2+half);
+ fn = (float)n;
+ r = t-fn*pio2_1;
+ w = fn*pio2_1t; /* 1st round good to 40 bit */
+ if(n<32&&(ix&0xffffff00)!=npio2_hw[n-1]) {
+ y[0] = r-w; /* quick check no cancellation */
+ } else {
+ __uint32_t high;
+ j = ix>>23;
+ y[0] = r-w;
+ GET_FLOAT_WORD(high,y[0]);
+ i = j-((high>>23)&0xff);
+ if(i>8) { /* 2nd iteration needed, good to 57 */
+ t = r;
+ w = fn*pio2_2;
+ r = t-w;
+ w = fn*pio2_2t-((t-r)-w);
+ y[0] = r-w;
+ GET_FLOAT_WORD(high,y[0]);
+ i = j-((high>>23)&0xff);
+ if(i>25) { /* 3rd iteration need, 74 bits acc */
+ t = r; /* will cover all possible cases */
+ w = fn*pio2_3;
+ r = t-w;
+ w = fn*pio2_3t-((t-r)-w);
+ y[0] = r-w;
+ }
+ }
+ }
+ y[1] = (r-y[0])-w;
+ if(hx<0) {y[0] = -y[0]; y[1] = -y[1]; return -n;}
+ else return n;
+ }
+ /*
+ * all other (large) arguments
+ */
+ if(!FLT_UWORD_IS_FINITE(ix)) {
+ y[0]=y[1]=x-x; return 0;
+ }
+ /* set z = scalbn(|x|,ilogb(x)-7) */
+ e0 = (int)((ix>>23)-134); /* e0 = ilogb(z)-7; */
+ SET_FLOAT_WORD(z, ix - ((__int32_t)e0<<23));
+ for(i=0;i<2;i++) {
+ tx[i] = (float)((__int32_t)(z));
+ z = (z-tx[i])*two8;
+ }
+ tx[2] = z;
+ nx = 3;
+ while(tx[nx-1]==zero) nx--; /* skip zero term */
+ n = __kernel_rem_pio2f(tx,y,e0,nx,2,two_over_pi);
+ if(hx<0) {y[0] = -y[0]; y[1] = -y[1]; return -n;}
+ return n;
+}
--- /dev/null
+/* ef_sqrtf.c -- float version of e_sqrt.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+static const float one = 1.0, tiny=1.0e-30;
+#else
+static float one = 1.0, tiny=1.0e-30;
+#endif
+
+#ifdef __STDC__
+ float __ieee754_sqrtf(float x)
+#else
+ float __ieee754_sqrtf(x)
+ float x;
+#endif
+{
+ float z;
+ __uint32_t r,hx;
+ __int32_t ix,s,q,m,t,i;
+
+ GET_FLOAT_WORD(ix,x);
+ hx = ix&0x7fffffff;
+
+ /* take care of Inf and NaN */
+ if(!FLT_UWORD_IS_FINITE(hx))
+ return x*x+x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf
+ sqrt(-inf)=sNaN */
+ /* take care of zero and -ves */
+ if(FLT_UWORD_IS_ZERO(hx)) return x;/* sqrt(+-0) = +-0 */
+ if(ix<0) return (x-x)/(x-x); /* sqrt(-ve) = sNaN */
+
+ /* normalize x */
+ m = (ix>>23);
+ if(FLT_UWORD_IS_SUBNORMAL(hx)) { /* subnormal x */
+ for(i=0;(ix&0x00800000L)==0;i++) ix<<=1;
+ m -= i-1;
+ }
+ m -= 127; /* unbias exponent */
+ ix = (ix&0x007fffffL)|0x00800000L;
+ if(m&1) /* odd m, double x to make it even */
+ ix += ix;
+ m >>= 1; /* m = [m/2] */
+
+ /* generate sqrt(x) bit by bit */
+ ix += ix;
+ q = s = 0; /* q = sqrt(x) */
+ r = 0x01000000L; /* r = moving bit from right to left */
+
+ while(r!=0) {
+ t = s+r;
+ if(t<=ix) {
+ s = t+r;
+ ix -= t;
+ q += r;
+ }
+ ix += ix;
+ r>>=1;
+ }
+
+ /* use floating add to find out rounding direction */
+ if(ix!=0) {
+ z = one-tiny; /* trigger inexact flag */
+ if (z>=one) {
+ z = one+tiny;
+ if (z>one)
+ q += 2;
+ else
+ q += (q&1);
+ }
+ }
+ ix = (q>>1)+0x3f000000L;
+ ix += (m <<23);
+ SET_FLOAT_WORD(z,ix);
+ return z;
+}
--- /dev/null
+
+/* @(#)fdlibm.h 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* AltOS local */
+#include <math.h>
+#include <stdint.h>
+#define __int32_t int32_t
+#define __uint32_t uint32_t
+
+#define __ieee754_acosf acosf
+#define __ieee754_sqrtf sqrtf
+
+/* REDHAT LOCAL: Include files. */
+#include <math.h>
+/* #include <sys/types.h> */
+#include <machine/ieeefp.h>
+
+/* REDHAT LOCAL: Default to XOPEN_MODE. */
+#define _XOPEN_MODE
+
+/* Most routines need to check whether a float is finite, infinite, or not a
+ number, and many need to know whether the result of an operation will
+ overflow. These conditions depend on whether the largest exponent is
+ used for NaNs & infinities, or whether it's used for finite numbers. The
+ macros below wrap up that kind of information:
+
+ FLT_UWORD_IS_FINITE(X)
+ True if a positive float with bitmask X is finite.
+
+ FLT_UWORD_IS_NAN(X)
+ True if a positive float with bitmask X is not a number.
+
+ FLT_UWORD_IS_INFINITE(X)
+ True if a positive float with bitmask X is +infinity.
+
+ FLT_UWORD_MAX
+ The bitmask of FLT_MAX.
+
+ FLT_UWORD_HALF_MAX
+ The bitmask of FLT_MAX/2.
+
+ FLT_UWORD_EXP_MAX
+ The bitmask of the largest finite exponent (129 if the largest
+ exponent is used for finite numbers, 128 otherwise).
+
+ FLT_UWORD_LOG_MAX
+ The bitmask of log(FLT_MAX), rounded down. This value is the largest
+ input that can be passed to exp() without producing overflow.
+
+ FLT_UWORD_LOG_2MAX
+ The bitmask of log(2*FLT_MAX), rounded down. This value is the
+ largest input than can be passed to cosh() without producing
+ overflow.
+
+ FLT_LARGEST_EXP
+ The largest biased exponent that can be used for finite numbers
+ (255 if the largest exponent is used for finite numbers, 254
+ otherwise) */
+
+#ifdef _FLT_LARGEST_EXPONENT_IS_NORMAL
+#define FLT_UWORD_IS_FINITE(x) 1
+#define FLT_UWORD_IS_NAN(x) 0
+#define FLT_UWORD_IS_INFINITE(x) 0
+#define FLT_UWORD_MAX 0x7fffffff
+#define FLT_UWORD_EXP_MAX 0x43010000
+#define FLT_UWORD_LOG_MAX 0x42b2d4fc
+#define FLT_UWORD_LOG_2MAX 0x42b437e0
+#define HUGE ((float)0X1.FFFFFEP128)
+#else
+#define FLT_UWORD_IS_FINITE(x) ((x)<0x7f800000L)
+#define FLT_UWORD_IS_NAN(x) ((x)>0x7f800000L)
+#define FLT_UWORD_IS_INFINITE(x) ((x)==0x7f800000L)
+#define FLT_UWORD_MAX 0x7f7fffffL
+#define FLT_UWORD_EXP_MAX 0x43000000
+#define FLT_UWORD_LOG_MAX 0x42b17217
+#define FLT_UWORD_LOG_2MAX 0x42b2d4fc
+#define HUGE ((float)3.40282346638528860e+38)
+#endif
+#define FLT_UWORD_HALF_MAX (FLT_UWORD_MAX-(1L<<23))
+#define FLT_LARGEST_EXP (FLT_UWORD_MAX>>23)
+
+/* Many routines check for zero and subnormal numbers. Such things depend
+ on whether the target supports denormals or not:
+
+ FLT_UWORD_IS_ZERO(X)
+ True if a positive float with bitmask X is +0. Without denormals,
+ any float with a zero exponent is a +0 representation. With
+ denormals, the only +0 representation is a 0 bitmask.
+
+ FLT_UWORD_IS_SUBNORMAL(X)
+ True if a non-zero positive float with bitmask X is subnormal.
+ (Routines should check for zeros first.)
+
+ FLT_UWORD_MIN
+ The bitmask of the smallest float above +0. Call this number
+ REAL_FLT_MIN...
+
+ FLT_UWORD_EXP_MIN
+ The bitmask of the float representation of REAL_FLT_MIN's exponent.
+
+ FLT_UWORD_LOG_MIN
+ The bitmask of |log(REAL_FLT_MIN)|, rounding down.
+
+ FLT_SMALLEST_EXP
+ REAL_FLT_MIN's exponent - EXP_BIAS (1 if denormals are not supported,
+ -22 if they are).
+*/
+
+#ifdef _FLT_NO_DENORMALS
+#define FLT_UWORD_IS_ZERO(x) ((x)<0x00800000L)
+#define FLT_UWORD_IS_SUBNORMAL(x) 0
+#define FLT_UWORD_MIN 0x00800000
+#define FLT_UWORD_EXP_MIN 0x42fc0000
+#define FLT_UWORD_LOG_MIN 0x42aeac50
+#define FLT_SMALLEST_EXP 1
+#else
+#define FLT_UWORD_IS_ZERO(x) ((x)==0)
+#define FLT_UWORD_IS_SUBNORMAL(x) ((x)<0x00800000L)
+#define FLT_UWORD_MIN 0x00000001
+#define FLT_UWORD_EXP_MIN 0x43160000
+#define FLT_UWORD_LOG_MIN 0x42cff1b5
+#define FLT_SMALLEST_EXP -22
+#endif
+
+#ifdef __STDC__
+#undef __P
+#define __P(p) p
+#else
+#define __P(p) ()
+#endif
+
+/*
+ * set X_TLOSS = pi*2**52, which is possibly defined in <values.h>
+ * (one may replace the following line by "#include <values.h>")
+ */
+
+#define X_TLOSS 1.41484755040568800000e+16
+
+/* Functions that are not documented, and are not in <math.h>. */
+
+#ifdef _SCALB_INT
+extern double scalb __P((double, int));
+#else
+extern double scalb __P((double, double));
+#endif
+extern double significand __P((double));
+
+/* ieee style elementary functions */
+extern double __ieee754_sqrt __P((double));
+extern double __ieee754_acos __P((double));
+extern double __ieee754_acosh __P((double));
+extern double __ieee754_log __P((double));
+extern double __ieee754_atanh __P((double));
+extern double __ieee754_asin __P((double));
+extern double __ieee754_atan2 __P((double,double));
+extern double __ieee754_exp __P((double));
+extern double __ieee754_cosh __P((double));
+extern double __ieee754_fmod __P((double,double));
+extern double __ieee754_pow __P((double,double));
+extern double __ieee754_lgamma_r __P((double,int *));
+extern double __ieee754_gamma_r __P((double,int *));
+extern double __ieee754_log10 __P((double));
+extern double __ieee754_sinh __P((double));
+extern double __ieee754_hypot __P((double,double));
+extern double __ieee754_j0 __P((double));
+extern double __ieee754_j1 __P((double));
+extern double __ieee754_y0 __P((double));
+extern double __ieee754_y1 __P((double));
+extern double __ieee754_jn __P((int,double));
+extern double __ieee754_yn __P((int,double));
+extern double __ieee754_remainder __P((double,double));
+extern __int32_t __ieee754_rem_pio2 __P((double,double*));
+#ifdef _SCALB_INT
+extern double __ieee754_scalb __P((double,int));
+#else
+extern double __ieee754_scalb __P((double,double));
+#endif
+
+/* fdlibm kernel function */
+extern double __kernel_standard __P((double,double,int));
+extern double __kernel_sin __P((double,double,int));
+extern double __kernel_cos __P((double,double));
+extern double __kernel_tan __P((double,double,int));
+extern int __kernel_rem_pio2 __P((double*,double*,int,int,int,const __int32_t*));
+
+/* Undocumented float functions. */
+#ifdef _SCALB_INT
+extern float scalbf __P((float, int));
+#else
+extern float scalbf __P((float, float));
+#endif
+extern float significandf __P((float));
+
+/* ieee style elementary float functions */
+extern float __ieee754_sqrtf __P((float));
+extern float __ieee754_acosf __P((float));
+extern float __ieee754_acoshf __P((float));
+extern float __ieee754_logf __P((float));
+extern float __ieee754_atanhf __P((float));
+extern float __ieee754_asinf __P((float));
+extern float __ieee754_atan2f __P((float,float));
+extern float __ieee754_expf __P((float));
+extern float __ieee754_coshf __P((float));
+extern float __ieee754_fmodf __P((float,float));
+extern float __ieee754_powf __P((float,float));
+extern float __ieee754_lgammaf_r __P((float,int *));
+extern float __ieee754_gammaf_r __P((float,int *));
+extern float __ieee754_log10f __P((float));
+extern float __ieee754_sinhf __P((float));
+extern float __ieee754_hypotf __P((float,float));
+extern float __ieee754_j0f __P((float));
+extern float __ieee754_j1f __P((float));
+extern float __ieee754_y0f __P((float));
+extern float __ieee754_y1f __P((float));
+extern float __ieee754_jnf __P((int,float));
+extern float __ieee754_ynf __P((int,float));
+extern float __ieee754_remainderf __P((float,float));
+extern __int32_t __ieee754_rem_pio2f __P((float,float*));
+#ifdef _SCALB_INT
+extern float __ieee754_scalbf __P((float,int));
+#else
+extern float __ieee754_scalbf __P((float,float));
+#endif
+
+/* float versions of fdlibm kernel functions */
+extern float __kernel_sinf __P((float,float,int));
+extern float __kernel_cosf __P((float,float));
+extern float __kernel_tanf __P((float,float,int));
+extern int __kernel_rem_pio2f __P((float*,float*,int,int,int,const __int32_t*));
+
+/* The original code used statements like
+ n0 = ((*(int*)&one)>>29)^1; * index of high word *
+ ix0 = *(n0+(int*)&x); * high word of x *
+ ix1 = *((1-n0)+(int*)&x); * low word of x *
+ to dig two 32 bit words out of the 64 bit IEEE floating point
+ value. That is non-ANSI, and, moreover, the gcc instruction
+ scheduler gets it wrong. We instead use the following macros.
+ Unlike the original code, we determine the endianness at compile
+ time, not at run time; I don't see much benefit to selecting
+ endianness at run time. */
+
+#ifndef __IEEE_BIG_ENDIAN
+#ifndef __IEEE_LITTLE_ENDIAN
+ #error Must define endianness
+#endif
+#endif
+
+/* A union which permits us to convert between a double and two 32 bit
+ ints. */
+
+#ifdef __IEEE_BIG_ENDIAN
+
+typedef union
+{
+ double value;
+ struct
+ {
+ __uint32_t msw;
+ __uint32_t lsw;
+ } parts;
+} ieee_double_shape_type;
+
+#endif
+
+#ifdef __IEEE_LITTLE_ENDIAN
+
+typedef union
+{
+ double value;
+ struct
+ {
+ __uint32_t lsw;
+ __uint32_t msw;
+ } parts;
+} ieee_double_shape_type;
+
+#endif
+
+/* Get two 32 bit ints from a double. */
+
+#define EXTRACT_WORDS(ix0,ix1,d) \
+do { \
+ ieee_double_shape_type ew_u; \
+ ew_u.value = (d); \
+ (ix0) = ew_u.parts.msw; \
+ (ix1) = ew_u.parts.lsw; \
+} while (0)
+
+/* Get the more significant 32 bit int from a double. */
+
+#define GET_HIGH_WORD(i,d) \
+do { \
+ ieee_double_shape_type gh_u; \
+ gh_u.value = (d); \
+ (i) = gh_u.parts.msw; \
+} while (0)
+
+/* Get the less significant 32 bit int from a double. */
+
+#define GET_LOW_WORD(i,d) \
+do { \
+ ieee_double_shape_type gl_u; \
+ gl_u.value = (d); \
+ (i) = gl_u.parts.lsw; \
+} while (0)
+
+/* Set a double from two 32 bit ints. */
+
+#define INSERT_WORDS(d,ix0,ix1) \
+do { \
+ ieee_double_shape_type iw_u; \
+ iw_u.parts.msw = (ix0); \
+ iw_u.parts.lsw = (ix1); \
+ (d) = iw_u.value; \
+} while (0)
+
+/* Set the more significant 32 bits of a double from an int. */
+
+#define SET_HIGH_WORD(d,v) \
+do { \
+ ieee_double_shape_type sh_u; \
+ sh_u.value = (d); \
+ sh_u.parts.msw = (v); \
+ (d) = sh_u.value; \
+} while (0)
+
+/* Set the less significant 32 bits of a double from an int. */
+
+#define SET_LOW_WORD(d,v) \
+do { \
+ ieee_double_shape_type sl_u; \
+ sl_u.value = (d); \
+ sl_u.parts.lsw = (v); \
+ (d) = sl_u.value; \
+} while (0)
+
+/* A union which permits us to convert between a float and a 32 bit
+ int. */
+
+typedef union
+{
+ float value;
+ __uint32_t word;
+} ieee_float_shape_type;
+
+/* Get a 32 bit int from a float. */
+
+#define GET_FLOAT_WORD(i,d) \
+do { \
+ ieee_float_shape_type gf_u; \
+ gf_u.value = (d); \
+ (i) = gf_u.word; \
+} while (0)
+
+/* Set a float from a 32 bit int. */
+
+#define SET_FLOAT_WORD(d,i) \
+do { \
+ ieee_float_shape_type sf_u; \
+ sf_u.word = (i); \
+ (d) = sf_u.value; \
+} while (0)
+
+/* Macros to avoid undefined behaviour that can arise if the amount
+ of a shift is exactly equal to the size of the shifted operand. */
+
+#define SAFE_LEFT_SHIFT(op,amt) \
+ (((amt) < 8 * sizeof(op)) ? ((op) << (amt)) : 0)
+
+#define SAFE_RIGHT_SHIFT(op,amt) \
+ (((amt) < 8 * sizeof(op)) ? ((op) >> (amt)) : 0)
+
+#ifdef _COMPLEX_H
+
+/*
+ * Quoting from ISO/IEC 9899:TC2:
+ *
+ * 6.2.5.13 Types
+ * Each complex type has the same representation and alignment requirements as
+ * an array type containing exactly two elements of the corresponding real type;
+ * the first element is equal to the real part, and the second element to the
+ * imaginary part, of the complex number.
+ */
+typedef union {
+ float complex z;
+ float parts[2];
+} float_complex;
+
+typedef union {
+ double complex z;
+ double parts[2];
+} double_complex;
+
+typedef union {
+ long double complex z;
+ long double parts[2];
+} long_double_complex;
+
+#define REAL_PART(z) ((z).parts[0])
+#define IMAG_PART(z) ((z).parts[1])
+
+#endif /* _COMPLEX_H */
+
--- /dev/null
+#ifndef _IEEE_FP_H_
+#define _IEEE_FP_H_
+
+#include "_ansi.h"
+
+#include <machine/ieeefp.h>
+
+_BEGIN_STD_C
+
+/* FIXME FIXME FIXME:
+ Neither of __ieee_{float,double}_shape_tape seem to be used anywhere
+ except in libm/test. If that is the case, please delete these from here.
+ If that is not the case, please insert documentation here describing why
+ they're needed. */
+
+#ifdef __IEEE_BIG_ENDIAN
+
+typedef union
+{
+ double value;
+ struct
+ {
+ unsigned int sign : 1;
+ unsigned int exponent: 11;
+ unsigned int fraction0:4;
+ unsigned int fraction1:16;
+ unsigned int fraction2:16;
+ unsigned int fraction3:16;
+
+ } number;
+ struct
+ {
+ unsigned int sign : 1;
+ unsigned int exponent: 11;
+ unsigned int quiet:1;
+ unsigned int function0:3;
+ unsigned int function1:16;
+ unsigned int function2:16;
+ unsigned int function3:16;
+ } nan;
+ struct
+ {
+ unsigned long msw;
+ unsigned long lsw;
+ } parts;
+ long aslong[2];
+} __ieee_double_shape_type;
+
+#endif
+
+#ifdef __IEEE_LITTLE_ENDIAN
+
+typedef union
+{
+ double value;
+ struct
+ {
+#ifdef __SMALL_BITFIELDS
+ unsigned int fraction3:16;
+ unsigned int fraction2:16;
+ unsigned int fraction1:16;
+ unsigned int fraction0: 4;
+#else
+ unsigned int fraction1:32;
+ unsigned int fraction0:20;
+#endif
+ unsigned int exponent :11;
+ unsigned int sign : 1;
+ } number;
+ struct
+ {
+#ifdef __SMALL_BITFIELDS
+ unsigned int function3:16;
+ unsigned int function2:16;
+ unsigned int function1:16;
+ unsigned int function0:3;
+#else
+ unsigned int function1:32;
+ unsigned int function0:19;
+#endif
+ unsigned int quiet:1;
+ unsigned int exponent: 11;
+ unsigned int sign : 1;
+ } nan;
+ struct
+ {
+ unsigned long lsw;
+ unsigned long msw;
+ } parts;
+
+ long aslong[2];
+
+} __ieee_double_shape_type;
+
+#endif
+
+#ifdef __IEEE_BIG_ENDIAN
+
+typedef union
+{
+ float value;
+ struct
+ {
+ unsigned int sign : 1;
+ unsigned int exponent: 8;
+ unsigned int fraction0: 7;
+ unsigned int fraction1: 16;
+ } number;
+ struct
+ {
+ unsigned int sign:1;
+ unsigned int exponent:8;
+ unsigned int quiet:1;
+ unsigned int function0:6;
+ unsigned int function1:16;
+ } nan;
+ long p1;
+
+} __ieee_float_shape_type;
+
+#endif
+
+#ifdef __IEEE_LITTLE_ENDIAN
+
+typedef union
+{
+ float value;
+ struct
+ {
+ unsigned int fraction0: 7;
+ unsigned int fraction1: 16;
+ unsigned int exponent: 8;
+ unsigned int sign : 1;
+ } number;
+ struct
+ {
+ unsigned int function1:16;
+ unsigned int function0:6;
+ unsigned int quiet:1;
+ unsigned int exponent:8;
+ unsigned int sign:1;
+ } nan;
+ long p1;
+
+} __ieee_float_shape_type;
+
+#endif
+
+
+
+
+
+/* FLOATING ROUNDING */
+
+typedef int fp_rnd;
+#define FP_RN 0 /* Round to nearest */
+#define FP_RM 1 /* Round down */
+#define FP_RP 2 /* Round up */
+#define FP_RZ 3 /* Round to zero (trunate) */
+
+fp_rnd _EXFUN(fpgetround,(void));
+fp_rnd _EXFUN(fpsetround, (fp_rnd));
+
+/* EXCEPTIONS */
+
+typedef int fp_except;
+#define FP_X_INV 0x10 /* Invalid operation */
+#define FP_X_DX 0x80 /* Divide by zero */
+#define FP_X_OFL 0x04 /* Overflow exception */
+#define FP_X_UFL 0x02 /* Underflow exception */
+#define FP_X_IMP 0x01 /* imprecise exception */
+
+fp_except _EXFUN(fpgetmask,(void));
+fp_except _EXFUN(fpsetmask,(fp_except));
+fp_except _EXFUN(fpgetsticky,(void));
+fp_except _EXFUN(fpsetsticky, (fp_except));
+
+/* INTEGER ROUNDING */
+
+typedef int fp_rdi;
+#define FP_RDI_TOZ 0 /* Round to Zero */
+#define FP_RDI_RD 1 /* Follow float mode */
+
+fp_rdi _EXFUN(fpgetroundtoi,(void));
+fp_rdi _EXFUN(fpsetroundtoi,(fp_rdi));
+
+#undef isnan
+#undef isinf
+
+int _EXFUN(isnan, (double));
+int _EXFUN(isinf, (double));
+int _EXFUN(finite, (double));
+
+
+
+int _EXFUN(isnanf, (float));
+int _EXFUN(isinff, (float));
+int _EXFUN(finitef, (float));
+
+#define __IEEE_DBL_EXPBIAS 1023
+#define __IEEE_FLT_EXPBIAS 127
+
+#define __IEEE_DBL_EXPLEN 11
+#define __IEEE_FLT_EXPLEN 8
+
+
+#define __IEEE_DBL_FRACLEN (64 - (__IEEE_DBL_EXPLEN + 1))
+#define __IEEE_FLT_FRACLEN (32 - (__IEEE_FLT_EXPLEN + 1))
+
+#define __IEEE_DBL_MAXPOWTWO ((double)(1L << 32 - 2) * (1L << (32-11) - 32 + 1))
+#define __IEEE_FLT_MAXPOWTWO ((float)(1L << (32-8) - 1))
+
+#define __IEEE_DBL_NAN_EXP 0x7ff
+#define __IEEE_FLT_NAN_EXP 0xff
+
+#ifndef __ieeefp_isnanf
+#define __ieeefp_isnanf(x) (((*(long *)&(x) & 0x7f800000L)==0x7f800000L) && \
+ ((*(long *)&(x) & 0x007fffffL)!=0000000000L))
+#endif
+#define isnanf(x) __ieeefp_isnanf(x)
+
+#ifndef __ieeefp_isinff
+#define __ieeefp_isinff(x) (((*(long *)&(x) & 0x7f800000L)==0x7f800000L) && \
+ ((*(long *)&(x) & 0x007fffffL)==0000000000L))
+#endif
+#define isinff(x) __ieeefp_isinff(x)
+
+#ifndef __ieeefp_finitef
+#define __ieeefp_finitef(x) (((*(long *)&(x) & 0x7f800000L)!=0x7f800000L))
+#endif
+#define finitef(x) __ieeefp_finitef(x)
+
+#ifdef _DOUBLE_IS_32BITS
+#undef __IEEE_DBL_EXPBIAS
+#define __IEEE_DBL_EXPBIAS __IEEE_FLT_EXPBIAS
+
+#undef __IEEE_DBL_EXPLEN
+#define __IEEE_DBL_EXPLEN __IEEE_FLT_EXPLEN
+
+#undef __IEEE_DBL_FRACLEN
+#define __IEEE_DBL_FRACLEN __IEEE_FLT_FRACLEN
+
+#undef __IEEE_DBL_MAXPOWTWO
+#define __IEEE_DBL_MAXPOWTWO __IEEE_FLT_MAXPOWTWO
+
+#undef __IEEE_DBL_NAN_EXP
+#define __IEEE_DBL_NAN_EXP __IEEE_FLT_NAN_EXP
+
+#undef __ieee_double_shape_type
+#define __ieee_double_shape_type __ieee_float_shape_type
+
+#endif /* _DOUBLE_IS_32BITS */
+
+_END_STD_C
+
+#endif /* _IEEE_FP_H_ */
--- /dev/null
+/* kf_cos.c -- float version of k_cos.c
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+static const float
+#else
+static float
+#endif
+one = 1.0000000000e+00, /* 0x3f800000 */
+C1 = 4.1666667908e-02, /* 0x3d2aaaab */
+C2 = -1.3888889225e-03, /* 0xbab60b61 */
+C3 = 2.4801587642e-05, /* 0x37d00d01 */
+C4 = -2.7557314297e-07, /* 0xb493f27c */
+C5 = 2.0875723372e-09, /* 0x310f74f6 */
+C6 = -1.1359647598e-11; /* 0xad47d74e */
+
+#ifdef __STDC__
+ float __kernel_cosf(float x, float y)
+#else
+ float __kernel_cosf(x, y)
+ float x,y;
+#endif
+{
+ float a,hz,z,r,qx;
+ __int32_t ix;
+ GET_FLOAT_WORD(ix,x);
+ ix &= 0x7fffffff; /* ix = |x|'s high word*/
+ if(ix<0x32000000) { /* if x < 2**27 */
+ if(((int)x)==0) return one; /* generate inexact */
+ }
+ z = x*x;
+ r = z*(C1+z*(C2+z*(C3+z*(C4+z*(C5+z*C6)))));
+ if(ix < 0x3e99999a) /* if |x| < 0.3 */
+ return one - ((float)0.5*z - (z*r - x*y));
+ else {
+ if(ix > 0x3f480000) { /* x > 0.78125 */
+ qx = (float)0.28125;
+ } else {
+ SET_FLOAT_WORD(qx,ix-0x01000000); /* x/4 */
+ }
+ hz = (float)0.5*z-qx;
+ a = one-qx;
+ return a - (hz - (z*r-x*y));
+ }
+}
--- /dev/null
+/* kf_rem_pio2.c -- float version of k_rem_pio2.c
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "fdlibm.h"
+
+/* In the float version, the input parameter x contains 8 bit
+ integers, not 24 bit integers. 113 bit precision is not supported. */
+
+#ifdef __STDC__
+static const int init_jk[] = {4,7,9}; /* initial value for jk */
+#else
+static int init_jk[] = {4,7,9};
+#endif
+
+#ifdef __STDC__
+static const float PIo2[] = {
+#else
+static float PIo2[] = {
+#endif
+ 1.5703125000e+00, /* 0x3fc90000 */
+ 4.5776367188e-04, /* 0x39f00000 */
+ 2.5987625122e-05, /* 0x37da0000 */
+ 7.5437128544e-08, /* 0x33a20000 */
+ 6.0026650317e-11, /* 0x2e840000 */
+ 7.3896444519e-13, /* 0x2b500000 */
+ 5.3845816694e-15, /* 0x27c20000 */
+ 5.6378512969e-18, /* 0x22d00000 */
+ 8.3009228831e-20, /* 0x1fc40000 */
+ 3.2756352257e-22, /* 0x1bc60000 */
+ 6.3331015649e-25, /* 0x17440000 */
+};
+
+#ifdef __STDC__
+static const float
+#else
+static float
+#endif
+zero = 0.0,
+one = 1.0,
+two8 = 2.5600000000e+02, /* 0x43800000 */
+twon8 = 3.9062500000e-03; /* 0x3b800000 */
+
+#ifdef __STDC__
+ int __kernel_rem_pio2f(float *x, float *y, int e0, int nx, int prec, const __int32_t *ipio2)
+#else
+ int __kernel_rem_pio2f(x,y,e0,nx,prec,ipio2)
+ float x[], y[]; int e0,nx,prec; __int32_t ipio2[];
+#endif
+{
+ __int32_t jz,jx,jv,jp,jk,carry,n,iq[20],i,j,k,m,q0,ih;
+ float z,fw,f[20],fq[20],q[20];
+
+ /* initialize jk*/
+ jk = init_jk[prec];
+ jp = jk;
+
+ /* determine jx,jv,q0, note that 3>q0 */
+ jx = nx-1;
+ jv = (e0-3)/8; if(jv<0) jv=0;
+ q0 = e0-8*(jv+1);
+
+ /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */
+ j = jv-jx; m = jx+jk;
+ for(i=0;i<=m;i++,j++) f[i] = (j<0)? zero : (float) ipio2[j];
+
+ /* compute q[0],q[1],...q[jk] */
+ for (i=0;i<=jk;i++) {
+ for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j]; q[i] = fw;
+ }
+
+ jz = jk;
+recompute:
+ /* distill q[] into iq[] reversingly */
+ for(i=0,j=jz,z=q[jz];j>0;i++,j--) {
+ fw = (float)((__int32_t)(twon8* z));
+ iq[i] = (__int32_t)(z-two8*fw);
+ z = q[j-1]+fw;
+ }
+
+ /* compute n */
+ z = scalbnf(z,(int)q0); /* actual value of z */
+ z -= (float)8.0*floorf(z*(float)0.125); /* trim off integer >= 8 */
+ n = (__int32_t) z;
+ z -= (float)n;
+ ih = 0;
+ if(q0>0) { /* need iq[jz-1] to determine n */
+ i = (iq[jz-1]>>(8-q0)); n += i;
+ iq[jz-1] -= i<<(8-q0);
+ ih = iq[jz-1]>>(7-q0);
+ }
+ else if(q0==0) ih = iq[jz-1]>>8;
+ else if(z>=(float)0.5) ih=2;
+
+ if(ih>0) { /* q > 0.5 */
+ n += 1; carry = 0;
+ for(i=0;i<jz ;i++) { /* compute 1-q */
+ j = iq[i];
+ if(carry==0) {
+ if(j!=0) {
+ carry = 1; iq[i] = 0x100- j;
+ }
+ } else iq[i] = 0xff - j;
+ }
+ if(q0>0) { /* rare case: chance is 1 in 12 */
+ switch(q0) {
+ case 1:
+ iq[jz-1] &= 0x7f; break;
+ case 2:
+ iq[jz-1] &= 0x3f; break;
+ }
+ }
+ if(ih==2) {
+ z = one - z;
+ if(carry!=0) z -= scalbnf(one,(int)q0);
+ }
+ }
+
+ /* check if recomputation is needed */
+ if(z==zero) {
+ j = 0;
+ for (i=jz-1;i>=jk;i--) j |= iq[i];
+ if(j==0) { /* need recomputation */
+ for(k=1;iq[jk-k]==0;k++); /* k = no. of terms needed */
+
+ for(i=jz+1;i<=jz+k;i++) { /* add q[jz+1] to q[jz+k] */
+ f[jx+i] = (float) ipio2[jv+i];
+ for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j];
+ q[i] = fw;
+ }
+ jz += k;
+ goto recompute;
+ }
+ }
+
+ /* chop off zero terms */
+ if(z==(float)0.0) {
+ jz -= 1; q0 -= 8;
+ while(iq[jz]==0) { jz--; q0-=8;}
+ } else { /* break z into 8-bit if necessary */
+ z = scalbnf(z,-(int)q0);
+ if(z>=two8) {
+ fw = (float)((__int32_t)(twon8*z));
+ iq[jz] = (__int32_t)(z-two8*fw);
+ jz += 1; q0 += 8;
+ iq[jz] = (__int32_t) fw;
+ } else iq[jz] = (__int32_t) z ;
+ }
+
+ /* convert integer "bit" chunk to floating-point value */
+ fw = scalbnf(one,(int)q0);
+ for(i=jz;i>=0;i--) {
+ q[i] = fw*(float)iq[i]; fw*=twon8;
+ }
+
+ /* compute PIo2[0,...,jp]*q[jz,...,0] */
+ for(i=jz;i>=0;i--) {
+ for(fw=0.0,k=0;k<=jp&&k<=jz-i;k++) fw += PIo2[k]*q[i+k];
+ fq[jz-i] = fw;
+ }
+
+ /* compress fq[] into y[] */
+ switch(prec) {
+ case 0:
+ fw = 0.0;
+ for (i=jz;i>=0;i--) fw += fq[i];
+ y[0] = (ih==0)? fw: -fw;
+ break;
+ case 1:
+ case 2:
+ fw = 0.0;
+ for (i=jz;i>=0;i--) fw += fq[i];
+ y[0] = (ih==0)? fw: -fw;
+ fw = fq[0]-fw;
+ for (i=1;i<=jz;i++) fw += fq[i];
+ y[1] = (ih==0)? fw: -fw;
+ break;
+ case 3: /* painful */
+ for (i=jz;i>0;i--) {
+ fw = fq[i-1]+fq[i];
+ fq[i] += fq[i-1]-fw;
+ fq[i-1] = fw;
+ }
+ for (i=jz;i>1;i--) {
+ fw = fq[i-1]+fq[i];
+ fq[i] += fq[i-1]-fw;
+ fq[i-1] = fw;
+ }
+ for (fw=0.0,i=jz;i>=2;i--) fw += fq[i];
+ if(ih==0) {
+ y[0] = fq[0]; y[1] = fq[1]; y[2] = fw;
+ } else {
+ y[0] = -fq[0]; y[1] = -fq[1]; y[2] = -fw;
+ }
+ }
+ return n&7;
+}
--- /dev/null
+/* kf_sin.c -- float version of k_sin.c
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+static const float
+#else
+static float
+#endif
+half = 5.0000000000e-01,/* 0x3f000000 */
+S1 = -1.6666667163e-01, /* 0xbe2aaaab */
+S2 = 8.3333337680e-03, /* 0x3c088889 */
+S3 = -1.9841270114e-04, /* 0xb9500d01 */
+S4 = 2.7557314297e-06, /* 0x3638ef1b */
+S5 = -2.5050759689e-08, /* 0xb2d72f34 */
+S6 = 1.5896910177e-10; /* 0x2f2ec9d3 */
+
+#ifdef __STDC__
+ float __kernel_sinf(float x, float y, int iy)
+#else
+ float __kernel_sinf(x, y, iy)
+ float x,y; int iy; /* iy=0 if y is zero */
+#endif
+{
+ float z,r,v;
+ __int32_t ix;
+ GET_FLOAT_WORD(ix,x);
+ ix &= 0x7fffffff; /* high word of x */
+ if(ix<0x32000000) /* |x| < 2**-27 */
+ {if((int)x==0) return x;} /* generate inexact */
+ z = x*x;
+ v = z*x;
+ r = S2+z*(S3+z*(S4+z*(S5+z*S6)));
+ if(iy==0) return x+v*(S1+z*r);
+ else return x-((z*(half*y-v*r)-y)-v*S1);
+}
--- /dev/null
+#ifndef __IEEE_BIG_ENDIAN
+#ifndef __IEEE_LITTLE_ENDIAN
+
+/* This file can define macros to choose variations of the IEEE float
+ format:
+
+ _FLT_LARGEST_EXPONENT_IS_NORMAL
+
+ Defined if the float format uses the largest exponent for finite
+ numbers rather than NaN and infinity representations. Such a
+ format cannot represent NaNs or infinities at all, but it's FLT_MAX
+ is twice the IEEE value.
+
+ _FLT_NO_DENORMALS
+
+ Defined if the float format does not support IEEE denormals. Every
+ float with a zero exponent is taken to be a zero representation.
+
+ ??? At the moment, there are no equivalent macros above for doubles and
+ the macros are not fully supported by --enable-newlib-hw-fp.
+
+ __IEEE_BIG_ENDIAN
+
+ Defined if the float format is big endian. This is mutually exclusive
+ with __IEEE_LITTLE_ENDIAN.
+
+ __IEEE_LITTLE_ENDIAN
+
+ Defined if the float format is little endian. This is mutually exclusive
+ with __IEEE_BIG_ENDIAN.
+
+ Note that one of __IEEE_BIG_ENDIAN or __IEEE_LITTLE_ENDIAN must be specified for a
+ platform or error will occur.
+
+ __IEEE_BYTES_LITTLE_ENDIAN
+
+ This flag is used in conjunction with __IEEE_BIG_ENDIAN to describe a situation
+ whereby multiple words of an IEEE floating point are in big endian order, but the
+ words themselves are little endian with respect to the bytes.
+
+ _DOUBLE_IS_32BITS
+
+ This is used on platforms that support double by using the 32-bit IEEE
+ float type.
+
+ _FLOAT_ARG
+
+ This represents what type a float arg is passed as. It is used when the type is
+ not promoted to double.
+
+*/
+
+#if (defined(__arm__) || defined(__thumb__)) && !defined(__MAVERICK__)
+/* ARM traditionally used big-endian words; and within those words the
+ byte ordering was big or little endian depending upon the target.
+ Modern floating-point formats are naturally ordered; in this case
+ __VFP_FP__ will be defined, even if soft-float. */
+#ifdef __VFP_FP__
+# ifdef __ARMEL__
+# define __IEEE_LITTLE_ENDIAN
+# else
+# define __IEEE_BIG_ENDIAN
+# endif
+#else
+# define __IEEE_BIG_ENDIAN
+# ifdef __ARMEL__
+# define __IEEE_BYTES_LITTLE_ENDIAN
+# endif
+#endif
+#endif
+
+#ifdef __hppa__
+#define __IEEE_BIG_ENDIAN
+#endif
+
+#ifdef __SPU__
+#define __IEEE_BIG_ENDIAN
+
+#define isfinite(__y) \
+ (__extension__ ({int __cy; \
+ (sizeof (__y) == sizeof (float)) ? (1) : \
+ (__cy = fpclassify(__y)) != FP_INFINITE && __cy != FP_NAN;}))
+
+#define isinf(__x) ((sizeof (__x) == sizeof (float)) ? (0) : __isinfd(__x))
+#define isnan(__x) ((sizeof (__x) == sizeof (float)) ? (0) : __isnand(__x))
+
+/*
+ * Macros for use in ieeefp.h. We can't just define the real ones here
+ * (like those above) as we have name space issues when this is *not*
+ * included via generic the ieeefp.h.
+ */
+#define __ieeefp_isnanf(x) 0
+#define __ieeefp_isinff(x) 0
+#define __ieeefp_finitef(x) 1
+#endif
+
+#ifdef __sparc__
+#ifdef __LITTLE_ENDIAN_DATA__
+#define __IEEE_LITTLE_ENDIAN
+#else
+#define __IEEE_BIG_ENDIAN
+#endif
+#endif
+
+#if defined(__m68k__) || defined(__mc68000__)
+#define __IEEE_BIG_ENDIAN
+#endif
+
+#if defined(__mc68hc11__) || defined(__mc68hc12__) || defined(__mc68hc1x__)
+#define __IEEE_BIG_ENDIAN
+#ifdef __HAVE_SHORT_DOUBLE__
+# define _DOUBLE_IS_32BITS
+#endif
+#endif
+
+#if defined (__H8300__) || defined (__H8300H__) || defined (__H8300S__) || defined (__H8500__) || defined (__H8300SX__)
+#define __IEEE_BIG_ENDIAN
+#define _FLOAT_ARG float
+#define _DOUBLE_IS_32BITS
+#endif
+
+#if defined (__xc16x__) || defined (__xc16xL__) || defined (__xc16xS__)
+#define __IEEE_LITTLE_ENDIAN
+#define _FLOAT_ARG float
+#define _DOUBLE_IS_32BITS
+#endif
+
+
+#ifdef __sh__
+#ifdef __LITTLE_ENDIAN__
+#define __IEEE_LITTLE_ENDIAN
+#else
+#define __IEEE_BIG_ENDIAN
+#endif
+#if defined(__SH2E__) || defined(__SH3E__) || defined(__SH4_SINGLE_ONLY__) || defined(__SH2A_SINGLE_ONLY__)
+#define _DOUBLE_IS_32BITS
+#endif
+#endif
+
+#ifdef _AM29K
+#define __IEEE_BIG_ENDIAN
+#endif
+
+#ifdef _WIN32
+#define __IEEE_LITTLE_ENDIAN
+#endif
+
+#ifdef __i386__
+#define __IEEE_LITTLE_ENDIAN
+#endif
+
+#ifdef __i960__
+#define __IEEE_LITTLE_ENDIAN
+#endif
+
+#ifdef __lm32__
+#define __IEEE_BIG_ENDIAN
+#endif
+
+#ifdef __M32R__
+#define __IEEE_BIG_ENDIAN
+#endif
+
+#if defined(_C4x) || defined(_C3x)
+#define __IEEE_BIG_ENDIAN
+#define _DOUBLE_IS_32BITS
+#endif
+
+#ifdef __TMS320C6X__
+#ifdef _BIG_ENDIAN
+#define __IEEE_BIG_ENDIAN
+#else
+#define __IEEE_LITTLE_ENDIAN
+#endif
+#endif
+
+#ifdef __TIC80__
+#define __IEEE_LITTLE_ENDIAN
+#endif
+
+#ifdef __MIPSEL__
+#define __IEEE_LITTLE_ENDIAN
+#endif
+#ifdef __MIPSEB__
+#define __IEEE_BIG_ENDIAN
+#endif
+
+#ifdef __MMIX__
+#define __IEEE_BIG_ENDIAN
+#endif
+
+#ifdef __D30V__
+#define __IEEE_BIG_ENDIAN
+#endif
+
+/* necv70 was __IEEE_LITTLE_ENDIAN. */
+
+#ifdef __W65__
+#define __IEEE_LITTLE_ENDIAN
+#define _DOUBLE_IS_32BITS
+#endif
+
+#if defined(__Z8001__) || defined(__Z8002__)
+#define __IEEE_BIG_ENDIAN
+#endif
+
+#ifdef __m88k__
+#define __IEEE_BIG_ENDIAN
+#endif
+
+#ifdef __mn10300__
+#define __IEEE_LITTLE_ENDIAN
+#endif
+
+#ifdef __mn10200__
+#define __IEEE_LITTLE_ENDIAN
+#define _DOUBLE_IS_32BITS
+#endif
+
+#ifdef __v800
+#define __IEEE_LITTLE_ENDIAN
+#endif
+
+#ifdef __v850
+#define __IEEE_LITTLE_ENDIAN
+#endif
+
+#ifdef __D10V__
+#define __IEEE_BIG_ENDIAN
+#if __DOUBLE__ == 32
+#define _DOUBLE_IS_32BITS
+#endif
+#endif
+
+#ifdef __PPC__
+#if (defined(_BIG_ENDIAN) && _BIG_ENDIAN) || (defined(_AIX) && _AIX)
+#define __IEEE_BIG_ENDIAN
+#else
+#if (defined(_LITTLE_ENDIAN) && _LITTLE_ENDIAN) || (defined(__sun__) && __sun__) || (defined(_WIN32) && _WIN32)
+#define __IEEE_LITTLE_ENDIAN
+#endif
+#endif
+#endif
+
+#ifdef __xstormy16__
+#define __IEEE_LITTLE_ENDIAN
+#endif
+
+#ifdef __arc__
+#ifdef __big_endian__
+#define __IEEE_BIG_ENDIAN
+#else
+#define __IEEE_LITTLE_ENDIAN
+#endif
+#endif
+
+#ifdef __CRX__
+#define __IEEE_LITTLE_ENDIAN
+#endif
+
+#ifdef __fr30__
+#define __IEEE_BIG_ENDIAN
+#endif
+
+#ifdef __mcore__
+#define __IEEE_BIG_ENDIAN
+#endif
+
+#ifdef __mt__
+#define __IEEE_BIG_ENDIAN
+#endif
+
+#ifdef __frv__
+#define __IEEE_BIG_ENDIAN
+#endif
+
+#ifdef __moxie__
+#define __IEEE_BIG_ENDIAN
+#endif
+
+#ifdef __ia64__
+#ifdef __BIG_ENDIAN__
+#define __IEEE_BIG_ENDIAN
+#else
+#define __IEEE_LITTLE_ENDIAN
+#endif
+#endif
+
+#ifdef __AVR__
+#define __IEEE_LITTLE_ENDIAN
+#define _DOUBLE_IS_32BITS
+#endif
+
+#if defined(__or32__) || defined(__or1k__) || defined(__or16__)
+#define __IEEE_BIG_ENDIAN
+#endif
+
+#ifdef __IP2K__
+#define __IEEE_BIG_ENDIAN
+#define __SMALL_BITFIELDS
+#define _DOUBLE_IS_32BITS
+#endif
+
+#ifdef __iq2000__
+#define __IEEE_BIG_ENDIAN
+#endif
+
+#ifdef __MAVERICK__
+#ifdef __ARMEL__
+# define __IEEE_LITTLE_ENDIAN
+#else /* must be __ARMEB__ */
+# define __IEEE_BIG_ENDIAN
+#endif /* __ARMEL__ */
+#endif /* __MAVERICK__ */
+
+#ifdef __m32c__
+#define __IEEE_LITTLE_ENDIAN
+#define __SMALL_BITFIELDS
+#endif
+
+#ifdef __CRIS__
+#define __IEEE_LITTLE_ENDIAN
+#endif
+
+#ifdef __BFIN__
+#define __IEEE_LITTLE_ENDIAN
+#endif
+
+#ifdef __x86_64__
+#define __IEEE_LITTLE_ENDIAN
+#endif
+
+#ifdef __mep__
+#ifdef __LITTLE_ENDIAN__
+#define __IEEE_LITTLE_ENDIAN
+#else
+#define __IEEE_BIG_ENDIAN
+#endif
+#endif
+
+#ifdef __MICROBLAZE__
+#define __IEEE_BIG_ENDIAN
+#endif
+
+#ifdef __RL78__
+#define __IEEE_LITTLE_ENDIAN
+#define __SMALL_BITFIELDS /* 16 Bit INT */
+#define _DOUBLE_IS_32BITS
+#endif
+
+#ifdef __RX__
+
+#ifdef __RX_BIG_ENDIAN__
+#define __IEEE_BIG_ENDIAN
+#else
+#define __IEEE_LITTLE_ENDIAN
+#endif
+
+#ifndef __RX_64BIT_DOUBLES__
+#define _DOUBLE_IS_32BITS
+#endif
+
+#ifdef __RX_16BIT_INTS__
+#define __SMALL_BITFIELDS
+#endif
+
+#endif
+
+#if (defined(__CR16__) || defined(__CR16C__) ||defined(__CR16CP__))
+#define __IEEE_LITTLE_ENDIAN
+#define __SMALL_BITFIELDS /* 16 Bit INT */
+#endif
+
+#ifndef __IEEE_BIG_ENDIAN
+#ifndef __IEEE_LITTLE_ENDIAN
+#error Endianess not declared!!
+#endif /* not __IEEE_LITTLE_ENDIAN */
+#endif /* not __IEEE_BIG_ENDIAN */
+
+#endif /* not __IEEE_LITTLE_ENDIAN */
+#endif /* not __IEEE_BIG_ENDIAN */
+
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _MATH_H_
+#define _MATH_H_
+
+float acosf(float x);
+
+float cosf(float x);
+
+float sinf(float x);
+
+float sqrtf(float x);
+
+float fabsf(float x);
+
+float floorf(float x);
+
+float scalbnf(float x, int n);
+
+float copysignf(float x, float y);
+
+#endif
--- /dev/null
+/* sf_copysign.c -- float version of s_copysign.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * copysignf(float x, float y)
+ * copysignf(x,y) returns a value with the magnitude of x and
+ * with the sign bit of y.
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+ float copysignf(float x, float y)
+#else
+ float copysignf(x,y)
+ float x,y;
+#endif
+{
+ __uint32_t ix,iy;
+ GET_FLOAT_WORD(ix,x);
+ GET_FLOAT_WORD(iy,y);
+ SET_FLOAT_WORD(x,(ix&0x7fffffff)|(iy&0x80000000));
+ return x;
+}
+
+#ifdef _DOUBLE_IS_32BITS
+
+#ifdef __STDC__
+ double copysign(double x, double y)
+#else
+ double copysign(x,y)
+ double x,y;
+#endif
+{
+ return (double) copysignf((float) x, (float) y);
+}
+
+#endif /* defined(_DOUBLE_IS_32BITS) */
--- /dev/null
+/* sf_cos.c -- float version of s_cos.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+static const float one=1.0;
+#else
+static float one=1.0;
+#endif
+
+#ifdef __STDC__
+ float cosf(float x)
+#else
+ float cosf(x)
+ float x;
+#endif
+{
+ float y[2],z=0.0;
+ __int32_t n,ix;
+
+ GET_FLOAT_WORD(ix,x);
+
+ /* |x| ~< pi/4 */
+ ix &= 0x7fffffff;
+ if(ix <= 0x3f490fd8) return __kernel_cosf(x,z);
+
+ /* cos(Inf or NaN) is NaN */
+ else if (!FLT_UWORD_IS_FINITE(ix)) return x-x;
+
+ /* argument reduction needed */
+ else {
+ n = __ieee754_rem_pio2f(x,y);
+ switch(n&3) {
+ case 0: return __kernel_cosf(y[0],y[1]);
+ case 1: return -__kernel_sinf(y[0],y[1],1);
+ case 2: return -__kernel_cosf(y[0],y[1]);
+ default:
+ return __kernel_sinf(y[0],y[1],1);
+ }
+ }
+}
+
+#ifdef _DOUBLE_IS_32BITS
+
+#ifdef __STDC__
+ double cos(double x)
+#else
+ double cos(x)
+ double x;
+#endif
+{
+ return (double) cosf((float) x);
+}
+
+#endif /* defined(_DOUBLE_IS_32BITS) */
--- /dev/null
+/* sf_fabs.c -- float version of s_fabs.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * fabsf(x) returns the absolute value of x.
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+ float fabsf(float x)
+#else
+ float fabsf(x)
+ float x;
+#endif
+{
+ __uint32_t ix;
+ GET_FLOAT_WORD(ix,x);
+ SET_FLOAT_WORD(x,ix&0x7fffffff);
+ return x;
+}
+
+#ifdef _DOUBLE_IS_32BITS
+
+#ifdef __STDC__
+ double fabs(double x)
+#else
+ double fabs(x)
+ double x;
+#endif
+{
+ return (double) fabsf((float) x);
+}
+
+#endif /* defined(_DOUBLE_IS_32BITS) */
--- /dev/null
+/* sf_floor.c -- float version of s_floor.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * floorf(x)
+ * Return x rounded toward -inf to integral value
+ * Method:
+ * Bit twiddling.
+ * Exception:
+ * Inexact flag raised if x not equal to floorf(x).
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+static const float huge = 1.0e30;
+#else
+static float huge = 1.0e30;
+#endif
+
+#ifdef __STDC__
+ float floorf(float x)
+#else
+ float floorf(x)
+ float x;
+#endif
+{
+ __int32_t i0,j0;
+ __uint32_t i,ix;
+ GET_FLOAT_WORD(i0,x);
+ ix = (i0&0x7fffffff);
+ j0 = (ix>>23)-0x7f;
+ if(j0<23) {
+ if(j0<0) { /* raise inexact if x != 0 */
+ if(huge+x>(float)0.0) {/* return 0*sign(x) if |x|<1 */
+ if(i0>=0) {i0=0;}
+ else if(!FLT_UWORD_IS_ZERO(ix))
+ { i0=0xbf800000;}
+ }
+ } else {
+ i = (0x007fffff)>>j0;
+ if((i0&i)==0) return x; /* x is integral */
+ if(huge+x>(float)0.0) { /* raise inexact flag */
+ if(i0<0) i0 += (0x00800000)>>j0;
+ i0 &= (~i);
+ }
+ }
+ } else {
+ if(!FLT_UWORD_IS_FINITE(ix)) return x+x; /* inf or NaN */
+ else return x; /* x is integral */
+ }
+ SET_FLOAT_WORD(x,i0);
+ return x;
+}
+
+#ifdef _DOUBLE_IS_32BITS
+
+#ifdef __STDC__
+ double floor(double x)
+#else
+ double floor(x)
+ double x;
+#endif
+{
+ return (double) floorf((float) x);
+}
+
+#endif /* defined(_DOUBLE_IS_32BITS) */
--- /dev/null
+/* sf_scalbn.c -- float version of s_scalbn.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "fdlibm.h"
+#include <limits.h>
+#include <float.h>
+
+#if INT_MAX > 50000
+#define OVERFLOW_INT 50000
+#else
+#define OVERFLOW_INT 30000
+#endif
+
+#ifdef __STDC__
+static const float
+#else
+static float
+#endif
+two25 = 3.355443200e+07, /* 0x4c000000 */
+twom25 = 2.9802322388e-08, /* 0x33000000 */
+huge = 1.0e+30,
+tiny = 1.0e-30;
+
+#ifdef __STDC__
+ float scalbnf (float x, int n)
+#else
+ float scalbnf (x,n)
+ float x; int n;
+#endif
+{
+ __int32_t k,ix;
+ __uint32_t hx;
+
+ GET_FLOAT_WORD(ix,x);
+ hx = ix&0x7fffffff;
+ k = hx>>23; /* extract exponent */
+ if (FLT_UWORD_IS_ZERO(hx))
+ return x;
+ if (!FLT_UWORD_IS_FINITE(hx))
+ return x+x; /* NaN or Inf */
+ if (FLT_UWORD_IS_SUBNORMAL(hx)) {
+ x *= two25;
+ GET_FLOAT_WORD(ix,x);
+ k = ((ix&0x7f800000)>>23) - 25;
+ if (n< -50000) return tiny*x; /*underflow*/
+ }
+ k = k+n;
+ if (k > FLT_LARGEST_EXP) return huge*copysignf(huge,x); /* overflow */
+ if (k > 0) /* normal result */
+ {SET_FLOAT_WORD(x,(ix&0x807fffff)|(k<<23)); return x;}
+ if (k < FLT_SMALLEST_EXP) {
+ if (n > OVERFLOW_INT) /* in case integer overflow in n+k */
+ return huge*copysignf(huge,x); /*overflow*/
+ else return tiny*copysignf(tiny,x); /*underflow*/
+ }
+ k += 25; /* subnormal result */
+ SET_FLOAT_WORD(x,(ix&0x807fffff)|(k<<23));
+ return x*twom25;
+}
+
+#ifdef _DOUBLE_IS_32BITS
+
+#ifdef __STDC__
+ double scalbn(double x, int n)
+#else
+ double scalbn(x,n)
+ double x;
+ int n;
+#endif
+{
+ return (double) scalbnf((float) x, n);
+}
+
+#endif /* defined(_DOUBLE_IS_32BITS) */
--- /dev/null
+/* sf_sin.c -- float version of s_sin.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+ float sinf(float x)
+#else
+ float sinf(x)
+ float x;
+#endif
+{
+ float y[2],z=0.0;
+ __int32_t n,ix;
+
+ GET_FLOAT_WORD(ix,x);
+
+ /* |x| ~< pi/4 */
+ ix &= 0x7fffffff;
+ if(ix <= 0x3f490fd8) return __kernel_sinf(x,z,0);
+
+ /* sin(Inf or NaN) is NaN */
+ else if (!FLT_UWORD_IS_FINITE(ix)) return x-x;
+
+ /* argument reduction needed */
+ else {
+ n = __ieee754_rem_pio2f(x,y);
+ switch(n&3) {
+ case 0: return __kernel_sinf(y[0],y[1],1);
+ case 1: return __kernel_cosf(y[0],y[1]);
+ case 2: return -__kernel_sinf(y[0],y[1],1);
+ default:
+ return -__kernel_cosf(y[0],y[1]);
+ }
+ }
+}
+
+#ifdef _DOUBLE_IS_32BITS
+
+#ifdef __STDC__
+ double sin(double x)
+#else
+ double sin(x)
+ double x;
+#endif
+{
+ return (double) sinf((float) x);
+}
+
+#endif /* defined(_DOUBLE_IS_32BITS) */
PROGNAME=megadongle-v0.1
PROG=$(PROGNAME)-$(VERSION).elf
+HEX=$(PROGNAME)-$(VERSION).ihx
SRC=$(ALTOS_SRC) ao_megadongle.c
OBJ=$(SRC:.c=.o)
-all: $(PROG)
+all: $(PROG) $(HEX)
$(PROG): Makefile $(OBJ) altos.ld
- $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(SAT_CLIB) -lgcc
+ $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
$(OBJ): $(INC)
distclean: clean
clean:
- rm -f *.o $(PROGNAME)-*.elf
+ rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx
rm -f ao_product.h
install:
# Tiny AltOS build
#
#
-vpath % ../attiny:../drivers:../core:..
+vpath % ../attiny:../drivers:../core:../product:..
vpath ao-make-product.5c ../util
vpath make-altitude-pa ../util
+include ../avr/Makefile.defs
+
MCU=attiny85
DUDECPUTYPE=t85
#PROGRAMMER=stk500v2 -P usb
-PROGRAMMER=usbtiny
-LOADCMD=avrdude
LOADSLOW=-i 32 -B 32
LOADARG=-p $(DUDECPUTYPE) -c $(PROGRAMMER) -e -U flash:w:
-CC=avr-gcc
-OBJCOPY=avr-objcopy
-ifndef VERSION
-include ../Version
-endif
+#LDFLAGS=-L$(LDSCRIPTS) -Tavr25.x
ALTOS_SRC = \
ao_micropeak.c \
ao_ms5607.c \
ao_exti.c \
ao_convert_pa.c \
- ao_report_tiny.c \
+ ao_report_micro.c \
ao_notask.c \
ao_eeprom_tiny.c \
ao_panic.c \
IDPRODUCT=0
PRODUCT=MicroPeak-v0.1
PRODUCT_DEF=-DMICROPEAK
-CFLAGS = $(PRODUCT_DEF) -I. -I../attiny -I../core -I.. -I../drivers
+CFLAGS = $(PRODUCT_DEF) -I. -I../attiny -I../core -I.. -I../drivers -I../product
CFLAGS += -g -mmcu=$(MCU) -Wall -Wstrict-prototypes -O2 -mcall-prologues -DATTINY
NICKLE=nickle
+++ /dev/null
-/*
- * Copyright © 2012 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-#include <ao.h>
-#include <ao_async.h>
-
-#define AO_ASYNC_BAUD 38400l
-#define AO_ASYNC_DELAY (uint8_t) (1000000l / AO_ASYNC_BAUD)
-
-#define LED_PORT PORTB
-
-void
-ao_async_start(void)
-{
- LED_PORT |= (1 << AO_LED_SERIAL);
-}
-
-void
-ao_async_stop(void)
-{
- LED_PORT &= ~(1 << AO_LED_SERIAL);
-}
-
-void
-ao_async_byte(uint8_t byte)
-{
- uint8_t b;
- uint16_t w;
-
- /* start data stop */
- w = (0x000 << 0) | (byte << 1) | (0x001 << 9);
-
- ao_arch_block_interrupts();
- for (b = 0; b < 10; b++) {
- uint8_t v = LED_PORT & ~(1 << AO_LED_SERIAL);
- v |= (w & 1) << AO_LED_SERIAL;
- LED_PORT = v;
- w >>= 1;
-
- /* Carefully timed to hit around 9600 baud */
- asm volatile ("nop");
- asm volatile ("nop");
-
- asm volatile ("nop");
- asm volatile ("nop");
- asm volatile ("nop");
- asm volatile ("nop");
- asm volatile ("nop");
-
- asm volatile ("nop");
- asm volatile ("nop");
- asm volatile ("nop");
- asm volatile ("nop");
- asm volatile ("nop");
- }
- ao_arch_release_interrupts();
-}
+++ /dev/null
-/*
- * Copyright © 2012 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-#ifndef _AO_ASYNC_H_
-#define _AO_ASYNC_H_
-
-void
-ao_async_start(void);
-
-void
-ao_async_stop(void);
-
-void
-ao_async_byte(uint8_t byte);
-
-#endif /* _AO_ASYNC_H_ */
+++ /dev/null
-/*
- * Copyright © 2012 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-#include <ao.h>
-#include <ao_micropeak.h>
-#include <ao_log_micro.h>
-#include <ao_async.h>
-
-static uint16_t ao_log_offset = STARTING_LOG_OFFSET;
-
-void
-ao_log_micro_save(void)
-{
- uint16_t n_samples = (ao_log_offset - STARTING_LOG_OFFSET) / sizeof (uint16_t);
- ao_eeprom_write(PA_GROUND_OFFSET, &pa_ground, sizeof (pa_ground));
- ao_eeprom_write(PA_MIN_OFFSET, &pa_min, sizeof (pa_min));
- ao_eeprom_write(N_SAMPLES_OFFSET, &n_samples, sizeof (n_samples));
-}
-
-void
-ao_log_micro_restore(void)
-{
- ao_eeprom_read(PA_GROUND_OFFSET, &pa_ground, sizeof (pa_ground));
- ao_eeprom_read(PA_MIN_OFFSET, &pa_min, sizeof (pa_min));
-}
-
-void
-ao_log_micro_data(void)
-{
- uint16_t low_bits = pa;
-
- if (ao_log_offset < MAX_LOG_OFFSET) {
- ao_eeprom_write(ao_log_offset, &low_bits, sizeof (low_bits));
- ao_log_offset += sizeof (low_bits);
- }
-}
-
-#define POLY 0x8408
-
-static uint16_t
-ao_log_micro_crc(uint16_t crc, uint8_t byte)
-{
- uint8_t i;
-
- for (i = 0; i < 8; i++) {
- if ((crc & 0x0001) ^ (byte & 0x0001))
- crc = (crc >> 1) ^ POLY;
- else
- crc = crc >> 1;
- byte >>= 1;
- }
- return crc;
-}
-
-static void
-ao_log_hex_nibble(uint8_t b)
-{
- if (b < 10)
- ao_async_byte('0' + b);
- else
- ao_async_byte('a' - 10 + b);
-}
-
-static void
-ao_log_hex(uint8_t b)
-{
- ao_log_hex_nibble(b>>4);
- ao_log_hex_nibble(b&0xf);
-}
-
-static void
-ao_log_newline(void)
-{
- ao_async_byte('\r');
- ao_async_byte('\n');
-}
-
-void
-ao_log_micro_dump(void)
-{
- uint16_t n_samples;
- uint16_t nbytes;
- uint8_t byte;
- uint16_t b;
- uint16_t crc = 0xffff;
-
- ao_eeprom_read(N_SAMPLES_OFFSET, &n_samples, sizeof (n_samples));
- if (n_samples == 0xffff)
- n_samples = 0;
- nbytes = STARTING_LOG_OFFSET + sizeof (uint16_t) * n_samples;
- ao_async_start();
- ao_async_byte('M');
- ao_async_byte('P');
- for (b = 0; b < nbytes; b++) {
- if ((b & 0xf) == 0)
- ao_log_newline();
- ao_eeprom_read(b, &byte, 1);
- ao_log_hex(byte);
- crc = ao_log_micro_crc(crc, byte);
- }
- ao_log_newline();
- crc = ~crc;
- ao_log_hex(crc >> 8);
- ao_log_hex(crc);
- ao_log_newline();
- ao_async_stop();
-}
+++ /dev/null
-/*
- * Copyright © 2012 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-#ifndef _AO_LOG_MICRO_H_
-#define _AO_LOG_MICRO_H_
-
-#define PA_GROUND_OFFSET 0
-#define PA_MIN_OFFSET 4
-#define N_SAMPLES_OFFSET 8
-#define STARTING_LOG_OFFSET 10
-#define MAX_LOG_OFFSET 512
-
-void
-ao_log_micro_save(void);
-
-void
-ao_log_micro_restore(void);
-
-void
-ao_log_micro_data(void);
-
-void
-ao_log_micro_dump(void);
-
-#endif /* _AO_LOG_MICRO_H_ */
+++ /dev/null
-/*
- * Copyright © 2013 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-#ifndef AO_FLIGHT_TEST
-#include <ao.h>
-#endif
-#include <ao_micropeak.h>
-#include <ao_log_micro.h>
-
-uint32_t pa;
-uint32_t pa_ground;
-uint32_t pa_min;
-
-static void
-ao_microsample(void)
-{
- ao_pa_get();
- ao_microkalman_predict();
- ao_microkalman_correct();
-}
-
-#define NUM_PA_HIST 16
-
-#define SKIP_PA_HIST(i,j) (((i) + (j)) & (NUM_PA_HIST - 1))
-
-static uint32_t pa_hist[NUM_PA_HIST];
-
-void
-ao_microflight(void)
-{
- int16_t sample_count;
- uint16_t time;
- uint32_t pa_interval_min, pa_interval_max;
- int32_t pa_diff;
- uint8_t h, i;
- uint8_t accel_lock = 0;
- uint32_t pa_sum = 0;
-
- /* Wait for motion, averaging values to get ground pressure */
-
- time = ao_time();
- ao_pa_get();
- ao_microkalman_init();
- pa_ground = pa;
- sample_count = 0;
- h = 0;
- for (;;) {
- time += SAMPLE_SLEEP;
- if (sample_count == 0)
- ao_led_on(AO_LED_REPORT);
- ao_delay_until(time);
- ao_microsample();
- if (sample_count == 0)
- ao_led_off(AO_LED_REPORT);
- pa_hist[h] = pa;
- h = SKIP_PA_HIST(h,1);
- pa_diff = pa_ground - ao_pa;
-
- /* Check for a significant pressure change */
- if (pa_diff > BOOST_DETECT)
- break;
-
- if (sample_count < GROUND_AVG * 2) {
- if (sample_count < GROUND_AVG)
- pa_sum += pa;
- ++sample_count;
- } else {
- pa_ground = pa_sum >> GROUND_AVG_SHIFT;
- pa_sum = 0;
- sample_count = 0;
- }
- }
-
- /* Go back and find the first sample a decent interval above the ground */
- pa_min = pa_ground - LAND_DETECT;
- for (i = SKIP_PA_HIST(h,2); i != h; i = SKIP_PA_HIST(i,2)) {
- if (pa_hist[i] < pa_min)
- break;
- }
-
- /* Log the remaining samples so we get a complete history since leaving the ground */
- for (; i != h; i = SKIP_PA_HIST(i,2)) {
- pa = pa_hist[i];
- ao_log_micro_data();
- }
-
- /* Now sit around until the pressure is stable again and record the max */
-
- sample_count = 0;
- pa_min = ao_pa;
- pa_interval_min = ao_pa;
- pa_interval_max = ao_pa;
- for (;;) {
- time += SAMPLE_SLEEP;
- ao_delay_until(time);
- if ((sample_count & 3) == 0)
- ao_led_on(AO_LED_REPORT);
- ao_microsample();
- if ((sample_count & 3) == 0)
- ao_led_off(AO_LED_REPORT);
- if (sample_count & 1)
- ao_log_micro_data();
-
- /* If accelerating upwards, don't look for min pressure */
- if (ao_pa_accel < ACCEL_LOCK_PA)
- accel_lock = ACCEL_LOCK_TIME;
- else if (accel_lock)
- --accel_lock;
- else if (ao_pa < pa_min)
- pa_min = ao_pa;
-
- if (sample_count == (GROUND_AVG - 1)) {
- pa_diff = pa_interval_max - pa_interval_min;
-
- /* Check to see if the pressure is now stable */
- if (pa_diff < LAND_DETECT)
- break;
- sample_count = 0;
- pa_interval_min = ao_pa;
- pa_interval_max = ao_pa;
- } else {
- if (ao_pa < pa_interval_min)
- pa_interval_min = ao_pa;
- if (ao_pa > pa_interval_max)
- pa_interval_max = ao_pa;
- ++sample_count;
- }
- }
-}
+++ /dev/null
-/*
- * Copyright © 2013 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-#ifndef AO_FLIGHT_TEST
-#include <ao.h>
-#endif
-#include <ao_micropeak.h>
-
-#define FIX_BITS 16
-
-#define to_fix16(x) ((int16_t) ((x) * 65536.0 + 0.5))
-#define to_fix32(x) ((int32_t) ((x) * 65536.0 + 0.5))
-#define from_fix8(x) ((x) >> 8)
-#define from_fix(x) ((x) >> 16)
-#define fix8_to_fix16(x) ((x) << 8)
-#define fix16_to_fix8(x) ((x) >> 8)
-
-#include <ao_kalman.h>
-
-/* Basic time step (96ms) */
-#define AO_MK_STEP to_fix16(0.096)
-/* step ** 2 / 2 */
-#define AO_MK_STEP_2_2 to_fix16(0.004608)
-
-uint32_t ao_k_pa; /* 24.8 fixed point */
-int32_t ao_k_pa_speed; /* 16.16 fixed point */
-int32_t ao_k_pa_accel; /* 16.16 fixed point */
-
-uint32_t ao_pa; /* integer portion */
-int16_t ao_pa_speed; /* integer portion */
-int16_t ao_pa_accel; /* integer portion */
-
-void
-ao_microkalman_init(void)
-{
- ao_pa = pa;
- ao_k_pa = pa << 8;
-}
-
-void
-ao_microkalman_predict(void)
-{
- ao_k_pa += fix16_to_fix8((int32_t) ao_pa_speed * AO_MK_STEP + (int32_t) ao_pa_accel * AO_MK_STEP_2_2);
- ao_k_pa_speed += (int32_t) ao_pa_accel * AO_MK_STEP;
-}
-
-void
-ao_microkalman_correct(void)
-{
- int16_t e; /* Height error in Pa */
-
- e = pa - from_fix8(ao_k_pa);
-
- ao_k_pa += fix16_to_fix8((int32_t) e * AO_MK_BARO_K0_10);
- ao_k_pa_speed += (int32_t) e * AO_MK_BARO_K1_10;
- ao_k_pa_accel += (int32_t) e * AO_MK_BARO_K2_10;
- ao_pa = from_fix8(ao_k_pa);
- ao_pa_speed = from_fix(ao_k_pa_speed);
- ao_pa_accel = from_fix(ao_k_pa_accel);
-}
+++ /dev/null
-/*
- * Copyright © 2012 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-#include <ao.h>
-#include <ao_micropeak.h>
-#include <ao_ms5607.h>
-#include <ao_log_micro.h>
-#include <ao_async.h>
-
-static struct ao_ms5607_sample sample;
-static struct ao_ms5607_value value;
-
-alt_t ground_alt, max_alt;
-alt_t ao_max_height;
-
-void
-ao_pa_get(void)
-{
- ao_ms5607_sample(&sample);
- ao_ms5607_convert(&sample, &value);
- pa = value.pres;
-}
-
-static void
-ao_compute_height(void)
-{
- ground_alt = ao_pa_to_altitude(pa_ground);
- max_alt = ao_pa_to_altitude(pa_min);
- ao_max_height = max_alt - ground_alt;
-}
-
-static void
-ao_pips(void)
-{
- uint8_t i;
- for (i = 0; i < 10; i++) {
- ao_led_toggle(AO_LED_REPORT);
- ao_delay(AO_MS_TO_TICKS(80));
- }
- ao_delay(AO_MS_TO_TICKS(200));
-}
-
-int
-main(void)
-{
- ao_led_init(LEDS_AVAILABLE);
- ao_timer_init();
-
- /* Init external hardware */
- ao_spi_init();
- ao_ms5607_init();
- ao_ms5607_setup();
-
- /* Give the person a second to get their finger out of the way */
- ao_delay(AO_MS_TO_TICKS(1000));
-
- ao_log_micro_restore();
- ao_compute_height();
- ao_report_altitude();
- ao_pips();
- ao_log_micro_dump();
-
- ao_delay(BOOST_DELAY);
-
- ao_microflight();
-
- ao_log_micro_save();
- ao_compute_height();
- ao_report_altitude();
- for (;;) {
- cli();
- set_sleep_mode(SLEEP_MODE_PWR_DOWN);
- sleep_mode();
- }
-}
+++ /dev/null
-/*
- * Copyright © 2012 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-#ifndef _AO_MICROPEAK_H_
-#define _AO_MICROPEAK_H_
-
-#define SAMPLE_SLEEP AO_MS_TO_TICKS(96)
-
-/* 16 sample, or about two seconds worth */
-#define GROUND_AVG_SHIFT 4
-#define GROUND_AVG (1 << GROUND_AVG_SHIFT)
-
-/* Pressure change (in Pa) to detect boost */
-#define BOOST_DETECT 120 /* 10m at sea level, 12m at 2000m */
-
-/* Wait after power on before doing anything to give the user time to assemble the rocket */
-#define BOOST_DELAY AO_SEC_TO_TICKS(30)
-
-/* Pressure change (in Pa) to detect landing */
-#define LAND_DETECT 24 /* 2m at sea level, 2.4m at 2000m */
-
-/* Current sensor pressure value */
-extern uint32_t pa;
-
-/* Average pressure value on ground */
-extern uint32_t pa_ground;
-
-/* Minimum recorded filtered pressure value */
-extern uint32_t pa_min;
-
-/* Pressure values converted to altitudes */
-extern alt_t ground_alt, max_alt;
-
-/* max_alt - ground_alt */
-extern alt_t ao_max_height;
-
-void
-ao_pa_get(void);
-
-void
-ao_microflight(void);
-
-#define ACCEL_LOCK_PA -20
-#define ACCEL_LOCK_TIME 10
-
-extern uint32_t ao_k_pa; /* 24.8 fixed point */
-extern int32_t ao_k_pa_speed; /* 16.16 fixed point */
-extern int32_t ao_k_pa_accel; /* 16.16 fixed point */
-
-extern uint32_t ao_pa; /* integer portion */
-extern int16_t ao_pa_speed; /* integer portion */
-extern int16_t ao_pa_accel; /* integer portion */
-
-void
-ao_microkalman_init(void);
-
-void
-ao_microkalman_predict(void);
-
-void
-ao_microkalman_correct(void);
-
-#endif
-
+++ /dev/null
-/*
- * Copyright © 2012 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-#include <ao.h>
-
-#define mid(time) ao_led_for(AO_LED_REPORT, time)
-#define pause(time) ao_delay(time)
-
-static void
-ao_report_digit(uint8_t digit) __reentrant
-{
- if (!digit) {
- mid(AO_MS_TO_TICKS(1000));
- pause(AO_MS_TO_TICKS(300));
- } else {
- while (digit--) {
- mid(AO_MS_TO_TICKS(300));
- pause(AO_MS_TO_TICKS(300));
- }
- }
- pause(AO_MS_TO_TICKS(1000));
-}
-
-void
-ao_report_altitude(void)
-{
- __pdata alt_t agl = ao_max_height;
- static __xdata uint8_t digits[11];
- __pdata uint8_t ndigits, i;
-
- if (agl < 0)
- agl = 0;
- ndigits = 0;
- do {
- digits[ndigits++] = agl % 10;
- agl /= 10;
- } while (agl);
-
- i = ndigits;
- do
- ao_report_digit(digits[--i]);
- while (i != 0);
-}
--- /dev/null
+ao_product.h
+nanopeak-*
--- /dev/null
+#
+# Tiny AltOS build
+#
+#
+vpath % ../attiny:../drivers:../core:../product:..
+vpath ao-make-product.5c ../util
+vpath make-altitude-pa ../util
+
+include ../avr/Makefile.defs
+
+MCU=attiny85
+DUDECPUTYPE=t85
+#PROGRAMMER=stk500v2 -P usb
+LOADSLOW=-i 32 -B 32
+LOADARG=-p $(DUDECPUTYPE) -c $(PROGRAMMER) -e -U flash:w:
+
+#LDFLAGS=-L$(LDSCRIPTS) -Tavr25.x
+
+ALTOS_SRC = \
+ ao_micropeak.c \
+ ao_spi_attiny.c \
+ ao_led.c \
+ ao_clock.c \
+ ao_ms5607.c \
+ ao_exti.c \
+ ao_convert_pa.c \
+ ao_report_micro.c \
+ ao_notask.c \
+ ao_eeprom_tiny.c \
+ ao_panic.c \
+ ao_log_micro.c \
+ ao_async.c \
+ ao_microflight.c \
+ ao_microkalman.c
+
+INC=\
+ ao.h \
+ ao_pins.h \
+ ao_arch.h \
+ ao_arch_funcs.h \
+ ao_exti.h \
+ ao_ms5607.h \
+ ao_log_micro.h \
+ ao_micropeak.h \
+ altitude-pa.h
+
+IDPRODUCT=0
+PRODUCT=NanoPeak-v0.1
+PRODUCT_DEF=-DNANOPEAK
+CFLAGS = $(PRODUCT_DEF) -I. -I../attiny -I../core -I.. -I../drivers -I../product
+CFLAGS += -g -mmcu=$(MCU) -Wall -Wstrict-prototypes -O2 -mcall-prologues -DATTINY
+
+NICKLE=nickle
+
+PROG=nanopeak-v0.1
+
+SRC=$(ALTOS_SRC)
+OBJ=$(SRC:.c=.o)
+
+V=0
+# The user has explicitly enabled quiet compilation.
+ifeq ($(V),0)
+quiet = @printf " $1 $2 $@\n"; $($1)
+endif
+# Otherwise, print the full command line.
+quiet ?= $($1)
+
+all: $(PROG) $(PROG).hex
+
+CHECK=sh ../util/check-avr-mem
+
+$(PROG): Makefile $(OBJ)
+ $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ)
+ $(call quiet,CHECK) $(PROG) || ($(RM) -f $(PROG); exit 1)
+
+$(PROG).hex: $(PROG)
+ avr-size $(PROG)
+ $(OBJCOPY) -R .eeprom -O ihex $(PROG) $@
+
+
+load: $(PROG).hex
+ $(LOADCMD) $(LOADARG)$(PROG).hex
+
+load-slow: $(PROG).hex
+ $(LOADCMD) $(LOADSLOW) $(LOADARG)$(PROG).hex
+
+ao_product.h: ao-make-product.5c ../Version
+ $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@
+
+ao_product.o: ao_product.c ao_product.h
+
+%.o : %.c $(INC)
+ $(call quiet,CC) -c $(CFLAGS) $<
+
+distclean: clean
+
+clean:
+ rm -f *.o $(PROG) $(PROG).hex
+ rm -f ao_product.h
+
+../altitude-pa.h: make-altitude-pa
+ nickle $< > $@
+
+install:
+
+uninstall:
+
+$(OBJ): ao_product.h $(INC)
--- /dev/null
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_PINS_H_
+#define _AO_PINS_H_
+#include <avr/pgmspace.h>
+
+#define AO_LED_ORANGE (1<<3)
+#define AO_LED_SERIAL 3
+#define AO_LED_PANIC AO_LED_ORANGE
+#define AO_LED_REPORT AO_LED_ORANGE
+#define LEDS_AVAILABLE (AO_LED_ORANGE)
+#define USE_SERIAL_1_STDIN 0
+#define HAS_USB 0
+#define PACKET_HAS_SLAVE 0
+#define HAS_SERIAL_1 0
+#define HAS_TASK 0
+#define HAS_MS5607 1
+#define HAS_MS5611 0
+#define HAS_EEPROM 0
+#define HAS_BEEP 0
+#define AVR_CLOCK 250000UL
+
+/* SPI */
+#define SPI_PORT PORTB
+#define SPI_PIN PINB
+#define SPI_DIR DDRB
+#define AO_MS5607_CS_PORT PORTB
+#define AO_MS5607_CS_PIN 4
+
+/* MS5607 */
+#define AO_MS5607_SPI_INDEX 0
+#define AO_MS5607_MISO_PORT PORTB
+#define AO_MS5607_MISO_PIN 0
+#define AO_MS5607_BARO_OVERSAMPLE 4096
+#define AO_MS5607_TEMP_OVERSAMPLE 1024
+
+/* I2C */
+#define I2C_PORT PORTB
+#define I2C_PIN PINB
+#define I2C_DIR DDRB
+#define I2C_PIN_SCL PINB2
+#define I2C_PIN_SDA PINB0
+
+#define AO_CONST_ATTRIB PROGMEM
+typedef int32_t alt_t;
+#define FETCH_ALT(o) ((alt_t) pgm_read_dword(&altitude_table[o]))
+
+#define AO_ALT_VALUE(x) ((x) * (alt_t) 10)
+
+#endif /* _AO_PINS_H_ */
# Otherwise, print the full command line.
quiet ?= $($1)
-all: ../$(PROG)
+all: $(PROG)
-../$(PROG): $(REL) Makefile
+$(PROG): $(REL) Makefile
$(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) ..
$(call quiet,CHECK_STACK) ../cc1111/ao_arch.h $(PMEM) || rm $@
# Otherwise, print the full command line.
quiet ?= $($1)
-all: ../$(PROG)
+all: $(PROG)
-../$(PROG): $(REL) Makefile
+$(PROG): $(REL) Makefile
$(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) ..
$(call quiet,CHECK_STACK) ../cc1111/ao_arch.h $(PMEM) || rm $@
# Otherwise, print the full command line.
quiet ?= $($1)
-all: ../$(PROG)
+all: $(PROG)
-../$(PROG): $(REL) Makefile
- $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) ..
+$(PROG): $(REL) Makefile
+ $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL)
$(call quiet,CHECK_STACK) ../cc1111/ao_arch.h $(PMEM) || rm $@
ao_product.h: ao-make-product.5c ../Version
# Otherwise, print the full command line.
quiet ?= $($1)
-all: ../$(PROG)
+all: $(PROG)
-../$(PROG): $(REL) Makefile
- $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) ..
+$(PROG): $(REL) Makefile
+ $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL)
$(call quiet,CHECK_STACK) ../cc1111/ao_arch.h $(PMEM) || rm $@
ao_product.h: ao-make-product.5c ../Version
# Otherwise, print the full command line.
quiet ?= $($1)
-all: ../$(PROG)
+all: $(PROG)
-../$(PROG): $(REL) Makefile
+$(PROG): $(REL) Makefile
$(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) ..
$(call quiet,CHECK_STACK) ../cc1111/ao_arch.h $(PMEM) || rm $@
#define HAS_VERSION 0
#define AO_BOOT_CHAIN 1
-#define AO_BOOT_PIN 1
+
+#define IS_FLASH_LOADER 1
#endif /* _AO_FLASH_PINS_H_ */
ao_block_erase(void)
{
uint32_t addr = ao_get_hex32();
- uint32_t *p = (uint32_t *) addr;
+ void *p = (void *) addr;
ao_flash_erase_page(p);
}
ao_block_write(void)
{
uint32_t addr = ao_get_hex32();
- uint32_t *p = (uint32_t *) addr;
- union {
- uint8_t data8[256];
- uint32_t data32[64];
- } u;
+ void *p = (void *) addr;
+ uint8_t data[256];
uint16_t i;
if (addr < (uint32_t) AO_BOOT_APPLICATION_BASE) {
return;
}
for (i = 0; i < 256; i++)
- u.data8[i] = ao_usb_getchar();
- ao_flash_page(p, u.data32);
+ data[i] = ao_usb_getchar();
+ ao_flash_page(p, (void *) data);
}
static void
--- /dev/null
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+#include <ao_micropeak.h>
+#include <ao_ms5607.h>
+#include <ao_log_micro.h>
+#include <ao_async.h>
+
+static struct ao_ms5607_sample sample;
+static struct ao_ms5607_value value;
+
+alt_t ground_alt, max_alt;
+alt_t ao_max_height;
+
+void
+ao_pa_get(void)
+{
+ ao_ms5607_sample(&sample);
+ ao_ms5607_convert(&sample, &value);
+ pa = value.pres;
+}
+
+static void
+ao_compute_height(void)
+{
+ ground_alt = ao_pa_to_altitude(pa_ground);
+ max_alt = ao_pa_to_altitude(pa_min);
+ ao_max_height = max_alt - ground_alt;
+}
+
+static void
+ao_pips(void)
+{
+ uint8_t i;
+ for (i = 0; i < 10; i++) {
+ ao_led_toggle(AO_LED_REPORT);
+ ao_delay(AO_MS_TO_TICKS(80));
+ }
+ ao_delay(AO_MS_TO_TICKS(200));
+}
+
+int
+main(void)
+{
+ ao_led_init(LEDS_AVAILABLE);
+ ao_timer_init();
+
+ /* Init external hardware */
+ ao_spi_init();
+ ao_ms5607_init();
+ ao_ms5607_setup();
+
+ /* Give the person a second to get their finger out of the way */
+ ao_delay(AO_MS_TO_TICKS(1000));
+
+ ao_log_micro_restore();
+ ao_compute_height();
+ ao_report_altitude();
+ ao_pips();
+ ao_log_micro_dump();
+
+ ao_delay(BOOST_DELAY);
+
+ ao_microflight();
+
+ ao_log_micro_save();
+ ao_compute_height();
+ ao_report_altitude();
+ for (;;) {
+ cli();
+ set_sleep_mode(SLEEP_MODE_PWR_DOWN);
+ sleep_mode();
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_MICROPEAK_H_
+#define _AO_MICROPEAK_H_
+
+#define SAMPLE_SLEEP AO_MS_TO_TICKS(96)
+
+/* 64 sample, or about six seconds worth */
+#define GROUND_AVG_SHIFT 6
+#define GROUND_AVG (1 << GROUND_AVG_SHIFT)
+
+/* Pressure change (in Pa) to detect boost */
+#define BOOST_DETECT 360 /* 30m at sea level, 36m at 2000m */
+
+/* Wait after power on before doing anything to give the user time to assemble the rocket */
+#define BOOST_DELAY AO_SEC_TO_TICKS(60)
+
+/* Pressure change (in Pa) to detect landing */
+#define LAND_DETECT 24 /* 2m at sea level, 2.4m at 2000m */
+
+/* Current sensor pressure value */
+extern uint32_t pa;
+
+/* Average pressure value on ground */
+extern uint32_t pa_ground;
+
+/* Minimum recorded filtered pressure value */
+extern uint32_t pa_min;
+
+/* Pressure values converted to altitudes */
+extern alt_t ground_alt, max_alt;
+
+/* max_alt - ground_alt */
+extern alt_t ao_max_height;
+
+void
+ao_pa_get(void);
+
+void
+ao_microflight(void);
+
+#define ACCEL_LOCK_PA -20
+#define ACCEL_LOCK_TIME 10
+
+extern uint32_t ao_k_pa; /* 24.8 fixed point */
+extern int32_t ao_k_pa_speed; /* 16.16 fixed point */
+extern int32_t ao_k_pa_accel; /* 16.16 fixed point */
+
+extern uint32_t ao_pa; /* integer portion */
+extern int16_t ao_pa_speed; /* integer portion */
+extern int16_t ao_pa_accel; /* integer portion */
+
+void
+ao_microkalman_init(void);
+
+void
+ao_microkalman_predict(void);
+
+void
+ao_microkalman_correct(void);
+
+#endif
+
for (;;) {
while (ao_gps_tick == gps_tick)
- ao_sleep(&ao_gps_data);
+ ao_sleep(&ao_gps_new);
gps_tick = ao_gps_tick;
ao_gps_progress = (ao_gps_progress + 1) & 3;
}
# Otherwise, print the full command line.
quiet ?= $($1)
-all: ../$(PROG)
+all: $(PROG)
-../$(PROG): $(REL) Makefile
- $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) ..
+$(PROG): $(REL) Makefile
+ $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL)
$(call quiet,CHECK_STACK) ../cc1111/ao_arch.h $(PMEM) || rm $@
ao_product.h: ao-make-product.5c ../Version
ifndef VERSION
include ../Version
endif
+TOPDIR=..
+include $(TOPDIR)/Makedefs
CC=arm-none-eabi-gcc
OBJCOPY=arm-none-eabi-objcopy
-PDCLIB=/opt/cortex
-C_LIB=$(PDCLIB)/lib/pdclib-cortex-m3.a
-C_INC=-I$(PDCLIB)/include
+C_LIB=$(PDCLIB_LIBS_M3)
-DEF_CFLAGS=-g -std=gnu99 -Os -mlittle-endian -mthumb -ffreestanding -nostdlib -I. -I../../src/stm $(C_INC)
+DEF_CFLAGS=-g -std=gnu99 -Os -mlittle-endian -mthumb -ffreestanding -nostdlib -I. -I../stm $(PDCLIB_INCLUDES)
# to run from SRAM
LD_FLAGS_RAM=-L../stm -Wl,-Taltos-ram.ld
%.bin: %.elf
$(OBJCOPY) -O binary $^ $@
-bringup.elf: $(OBJ) $(C_LIB) bringup.ld
+bringup.elf: $(OBJ) bringup.ld
$(CC) $(CFLAGS) $(LD_FLAGS) -o $@ $(OBJ) $(C_LIB) -lgcc
-bringup-ram.elf: $(OBJ) $(C_LIB) altos-ram.ld
+bringup-ram.elf: $(OBJ) altos-ram.ld
$(CC) $(CFLAGS) $(LD_FLAGS_RAM) -o $@ $(OBJ) $(C_LIB) -lgcc
clean:
ao_data.c \
ao_i2c_stm.c \
ao_usb_stm.c \
- ao_exti_stm.c \
- ao_event.c \
- ao_quadrature.c \
- ao_button.c
+ ao_exti_stm.c
PRODUCT=StmDemo-v0.0
PRODUCT_DEF=-DSTM_DEMO
LDFLAGS=-L../stm -Wl,-Taltos.ld
$(ELF): Makefile $(OBJ)
- $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $@ $(OBJ) $(SAT_CLIB) -lgcc
+ $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $@ $(OBJ) $(LIBS)
ao_product.h: ao-make-product.5c ../Version
$(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@
distclean: clean
clean:
- rm -f *.o $(PROG)
+ rm -f *.o *.elf *.ihx
rm -f ao_product.h
install:
printf ("temp: %d\n", temp);
}
+#if 0
static void
ao_event(void)
{
}
}
+#endif
__code struct ao_cmds ao_demo_cmds[] = {
{ ao_dma_test, "D\0DMA test" },
{ ao_spi_read, "R\0SPI read" },
{ ao_i2c_write, "i\0I2C write" },
{ ao_temp, "t\0Show temp" },
- { ao_event, "e\0Monitor event queue" },
+/* { ao_event, "e\0Monitor event queue" }, */
{ 0, NULL }
};
LDFLAGS=-L../stm -Wl,-Taltos-loader.ld
$(PROG): Makefile $(OBJ)
- $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(SAT_CLIB) -lgcc
+ $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
ao_product.h: ao-make-product.5c ../Version
$(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@
.elf.ihx:
objcopy -O ihex $*.elf $@
-CC=arm-none-eabi-gcc
-SAT=/opt/cortex
-SAT_CLIB=$(SAT)/lib/pdclib-cortex-m3.a
-SAT_CFLAGS=-I$(SAT)/include
-
ifndef VERSION
include $(TOPDIR)/Version
endif
+include $(TOPDIR)/Makedefs
+
+CC=$(ARM_CC)
+LIBS=$(PDCLIB_LIBS_M3) -lgcc
-AO_CFLAGS=-I. -I$(TOPDIR)/stm -I$(TOPDIR)/core -I$(TOPDIR)/drivers -I$(TOPDIR)/product -I$(TOPDIR)
+AO_CFLAGS=-I. -I$(TOPDIR)/stm -I$(TOPDIR)/core -I$(TOPDIR)/drivers -I$(TOPDIR)/product -I$(TOPDIR) $(PDCLIB_INCLUDES)
STM_CFLAGS=-std=gnu99 -mlittle-endian -mcpu=cortex-m3 -mthumb -ffreestanding -nostdlib $(AO_CFLAGS) $(SAT_CFLAGS)
LDFLAGS=-L$(TOPDIR)/stm -Wl,-Taltos-loader.ld
OBJ=$(SRC:.c=.o)
-PRODUCT=AltosFlash-$(VERSION)
+PRODUCT=AltosFlash
PRODUCT_DEF=-DALTOS_FLASH
IDPRODUCT=0x000a
PROG=$(HARDWARE)-$(PROGNAME)-$(VERSION).elf
$(PROG): Makefile $(OBJ) altos-loader.ld
- $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(SAT_CLIB) -lgcc
+ $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
ao_product.h: ao-make-product.5c $(TOPDIR)/Version
$(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@
distclean: clean
clean:
- rm -f *.o $(PROG)
+ rm -f *.o $(HARDWARE)-$(PROGNAME)-*.elf
rm -f ao_product.h
install:
-vpath % ../stm:../product:../drivers:../core:../util:../kalman:../aes:..
+vpath % ../stm:../product:../drivers:../core:../util:../kalman:../aes:../math:..
vpath make-altitude ../util
vpath make-kalman ../util
vpath kalman.5c ../kalman
.SUFFIXES: .elf .ihx
.elf.ihx:
- objcopy -O ihex $*.elf $@
+ $(ELFTOHEX) --output=$@ $*.elf
-CC=arm-none-eabi-gcc
-SAT=/opt/cortex
-SAT_CLIB=$(SAT)/lib/pdclib-cortex-m3.a
-SAT_CFLAGS=-I$(SAT)/include
+ifndef TOPDIR
+TOPDIR=..
+endif
ifndef VERSION
-include ../Version
+include $(TOPDIR)/Version
endif
+include $(TOPDIR)/Makedefs
+
+CC=$(ARM_CC)
+LIBS=$(PDCLIB_LIBS_M3) -lgcc
-AO_CFLAGS=-I. -I../stm -I../core -I../drivers -I..
-STM_CFLAGS=-std=gnu99 -mlittle-endian -mcpu=cortex-m3 -mthumb -ffreestanding -nostdlib $(AO_CFLAGS) $(SAT_CFLAGS)
+AO_CFLAGS=-I. -I../stm -I../core -I../drivers -I../math -I.. $(PDCLIB_INCLUDES)
+STM_CFLAGS=-std=gnu99 -mlittle-endian -mcpu=cortex-m3 -mthumb -ffreestanding -nostdlib $(AO_CFLAGS)
LDFLAGS=-L../stm -Wl,-Taltos.ld
NICKLE=nickle
+ELFTOHEX=$(TOPDIR)/../ao-tools/ao-elftohex/ao-elftohex
V=0
# The user has explicitly enabled quiet compilation.
ao_romconfig.o(.romconfig*)
ao_product.o(.romconfig*)
- *(.text) /* Executable code */
+ *(.text*) /* Executable code */
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
*(.rodata*) /* Constants */
- __text_end__ = .;
} > rom
+ __text_end__ = .;
/* Boot data which must live at the start of ram so that
* the application and bootloader share the same addresses.
.textram BLOCK(8): {
__data_start__ = .;
__text_ram_start__ = .;
- *(.text.ram)
+ *(.ramtext)
__text_ram_end = .;
} >ram AT>rom
uint8_t i;
ao_data_get(&packet);
+#ifdef AO_ADC_DUMP
+ AO_ADC_DUMP(&packet);
+#else
printf("tick: %5u", packet.tick);
d = (int16_t *) (&packet.adc);
for (i = 0; i < AO_NUM_ADC; i++)
printf (" %2d: %5d", i, d[i]);
printf("\n");
+#endif
}
__code struct ao_cmds ao_adc_cmds[] = {
#define AO_TICK_SIGNED int16_t
#endif
+#define AO_PORT_TYPE uint16_t
+
/* Various definitions to make GCC look more like SDCC */
#define ao_arch_naked_declare __attribute__((naked))
void
ao_spi_init(void);
+#define ao_spi_set_cs(reg,mask) ((reg)->bsrr = ((uint32_t) (mask)) << 16)
+#define ao_spi_clr_cs(reg,mask) ((reg)->bsrr = (mask))
+
#define ao_spi_get_mask(reg,mask,bus, speed) do { \
ao_spi_get(bus, speed); \
- (reg)->bsrr = ((uint32_t) mask) << 16; \
+ ao_spi_set_cs(reg,mask); \
} while (0)
#define ao_spi_put_mask(reg,mask,bus) do { \
- (reg)->bsrr = mask; \
+ ao_spi_clr_cs(reg,mask); \
ao_spi_put(bus); \
} while (0)
/* Restore APSR */
asm("pop {r0}");
- asm("msr apsr,r0");
+ asm("msr apsr_nczvq,r0");
/* Restore general registers */
asm("pop {r0-r12,lr}\n");
asm("bx lr");
}
+#ifndef HAS_SAMPLE_PROFILE
+#define HAS_SAMPLE_PROFILE 0
+#endif
+
+#if !HAS_SAMPLE_PROFILE
#define HAS_ARCH_START_SCHEDULER 1
static inline void ao_arch_start_scheduler(void) {
asm("mrs %0,control" : "=&r" (control));
control |= (1 << 1);
asm("msr control,%0" : : "r" (control));
+ asm("isb");
}
+#endif
#define ao_arch_isr_stack()
#endif
-#define ao_arch_wait_interrupt() do { \
- asm(".global ao_idle_loc\n\twfi\nao_idle_loc:"); \
- ao_arch_release_interrupts(); \
- ao_arch_block_interrupts(); \
+#define ao_arch_wait_interrupt() do { \
+ asm("\twfi\n"); \
+ ao_arch_release_interrupts(); \
+ asm(".global ao_idle_loc\nao_idle_loc:"); \
+ ao_arch_block_interrupts(); \
} while (0)
#define ao_arch_critical(b) do { \
#include "ao.h"
+#ifndef BEEPER_CHANNEL
+#define BEEPER_CHANNEL 1
+#endif
+
void
ao_beep(uint8_t beep)
{
* is enabled and active high.
*/
+#if BEEPER_CHANNEL == 1
stm_tim3.ccmr1 = ((0 << STM_TIM234_CCMR1_OC2CE) |
(STM_TIM234_CCMR1_OC2M_FROZEN << STM_TIM234_CCMR1_OC2M) |
(0 << STM_TIM234_CCMR1_OC2PE) |
(0 << STM_TIM234_CCMR1_OC1FE) |
(STM_TIM234_CCMR1_CC1S_OUTPUT << STM_TIM234_CCMR1_CC1S));
-
stm_tim3.ccer = ((0 << STM_TIM234_CCER_CC4NP) |
(0 << STM_TIM234_CCER_CC4P) |
(0 << STM_TIM234_CCER_CC4E) |
(0 << STM_TIM234_CCER_CC1NP) |
(0 << STM_TIM234_CCER_CC1P) |
(1 << STM_TIM234_CCER_CC1E));
+#endif
+#if BEEPER_CHANNEL == 4
+ stm_tim3.ccmr2 = ((0 << STM_TIM234_CCMR2_OC4CE) |
+ (STM_TIM234_CCMR2_OC4M_TOGGLE << STM_TIM234_CCMR2_OC4M) |
+ (0 << STM_TIM234_CCMR2_OC4PE) |
+ (0 << STM_TIM234_CCMR2_OC4FE) |
+ (STM_TIM234_CCMR2_CC4S_OUTPUT << STM_TIM234_CCMR2_CC4S) |
+
+ (0 << STM_TIM234_CCMR2_OC3CE) |
+ (STM_TIM234_CCMR2_OC3M_FROZEN << STM_TIM234_CCMR2_OC3M) |
+ (0 << STM_TIM234_CCMR2_OC3PE) |
+ (0 << STM_TIM234_CCMR2_OC3FE) |
+ (STM_TIM234_CCMR2_CC3S_OUTPUT << STM_TIM234_CCMR2_CC3S));
+
+ stm_tim3.ccer = ((0 << STM_TIM234_CCER_CC4NP) |
+ (0 << STM_TIM234_CCER_CC4P) |
+ (1 << STM_TIM234_CCER_CC4E) |
+ (0 << STM_TIM234_CCER_CC3NP) |
+ (0 << STM_TIM234_CCER_CC3P) |
+ (0 << STM_TIM234_CCER_CC3E) |
+ (0 << STM_TIM234_CCER_CC2NP) |
+ (0 << STM_TIM234_CCER_CC2P) |
+ (0 << STM_TIM234_CCER_CC2E) |
+ (0 << STM_TIM234_CCER_CC1NP) |
+ (0 << STM_TIM234_CCER_CC1P) |
+ (0 << STM_TIM234_CCER_CC1E));
+#endif
/* 5. Enable the counter by setting the CEN bit in the TIMx_CR1 register. */
void
ao_beep_init(void)
{
- /* Our beeper is on PC6, which is hooked to TIM3_CH1,
- * which is on PC6
- */
+#if BEEPER_CHANNEL == 1
+ /* Our beeper is on PC6, which is hooked to TIM3_CH1.
+ */
stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOCEN);
stm_afr_set(&stm_gpioc, 6, STM_AFR_AF2);
+#endif
+#if BEEPER_CHANNEL == 4
+
+ /* Our beeper is on PB1, which is hooked to TIM3_CH4.
+ */
+ stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOBEN);
+
+ stm_afr_set(&stm_gpiob, 1, STM_AFR_AF2);
+#endif
/* Leave the timer off until requested */
+++ /dev/null
-/*
- * Copyright © 2012 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-#include <ao.h>
-#include <ao_data.h>
-
-volatile __xdata struct ao_data ao_data_ring[AO_DATA_RING];
-volatile __data uint8_t ao_data_head;
-volatile __data uint8_t ao_data_present;
-
-void
-ao_data_get(__xdata struct ao_data *packet)
-{
-#if HAS_FLIGHT
- uint8_t i = ao_data_ring_prev(ao_sample_data);
-#else
- uint8_t i = ao_data_ring_prev(ao_data_head);
-#endif
- memcpy(packet, (void *) &ao_data_ring[i], sizeof (struct ao_data));
-}
*/
#include <ao.h>
-#include <ao_storage.h>
+#include <ao_eeprom.h>
/* Total bytes of available storage */
-ao_pos_t ao_storage_total = 4096;
-
-/* Block size - device is erased in these units. */
-ao_pos_t ao_storage_block = 1024;
-
-/* Byte offset of config block. Will be ao_storage_block bytes long */
-ao_pos_t ao_storage_config = 0;
-
-/* Storage unit size - device reads and writes must be within blocks of this size. */
-uint16_t ao_storage_unit = 1024;
+const ao_pos_t ao_eeprom_total = 4096;
/* Location of eeprom in address space */
#define stm_eeprom ((uint8_t *) 0x08080000)
* the same contents, or append to an existing page easily enough
*/
-/*
- * Erase the specified sector
- */
-uint8_t
-ao_storage_erase(ao_pos_t pos) __reentrant
-{
- /* Not necessary */
- return 1;
-}
-
static void
ao_intflash_unlock(void)
{
}
/*
- * Write to flash
+ * Write to eeprom
*/
uint8_t
-ao_storage_device_write(ao_pos_t pos32, __xdata void *v, uint16_t len) __reentrant
+ao_eeprom_write(ao_pos_t pos32, __xdata void *v, uint16_t len)
{
uint16_t pos = pos32;
__xdata uint8_t *d = v;
- if (pos >= ao_storage_total || pos + len > ao_storage_total)
+ if (pos >= ao_eeprom_total || pos + len > ao_eeprom_total)
return 0;
ao_intflash_unlock();
}
/*
- * Read from flash
+ * Read from eeprom
*/
uint8_t
-ao_storage_device_read(ao_pos_t pos, __xdata void *v, uint16_t len) __reentrant
+ao_eeprom_read(ao_pos_t pos, __xdata void *v, uint16_t len)
{
uint8_t *d = v;
- if (pos >= ao_storage_total || pos + len > ao_storage_total)
+ if (pos >= ao_eeprom_total || pos + len > ao_eeprom_total)
return 0;
while (len--)
*d++ = ao_intflash_read(pos++);
return 1;
}
-void
-ao_storage_flush(void) __reentrant
-{
-}
-
-void
-ao_storage_setup(void)
-{
-}
-
-void
-ao_storage_device_info(void) __reentrant
-{
- uint8_t i;
- printf ("Using internal flash\n");
-}
+/*
+ * Initialize eeprom
+ */
void
-ao_storage_device_init(void)
+ao_eeprom_init(void)
{
+ /* Nothing to do here */
}
#define AO_EXTI_PRIORITY_LOW 16
#define AO_EXTI_PRIORITY_MED 0
#define AO_EXTI_PRIORITY_HIGH 32
+#define AO_EXTI_PIN_NOCONFIGURE 64
void
ao_exti_setup(struct stm_gpio *gpio, uint8_t pin, uint8_t mode, void (*callback)());
/* configure gpio to interrupt routing */
stm_exticr_set(gpio, pin);
- /* configure pin as input, setting selected pull-up/down mode */
- stm_moder_set(gpio, pin, STM_MODER_INPUT);
- switch (mode & (AO_EXTI_MODE_PULL_UP|AO_EXTI_MODE_PULL_DOWN)) {
- case 0:
- default:
- pupdr = STM_PUPDR_NONE;
- break;
- case AO_EXTI_MODE_PULL_UP:
- pupdr = STM_PUPDR_PULL_UP;
- break;
- case AO_EXTI_MODE_PULL_DOWN:
- pupdr = STM_PUPDR_PULL_DOWN;
- break;
+ if (!(mode & AO_EXTI_PIN_NOCONFIGURE)) {
+ /* configure pin as input, setting selected pull-up/down mode */
+ stm_moder_set(gpio, pin, STM_MODER_INPUT);
+ switch (mode & (AO_EXTI_MODE_PULL_UP|AO_EXTI_MODE_PULL_DOWN)) {
+ case 0:
+ default:
+ pupdr = STM_PUPDR_NONE;
+ break;
+ case AO_EXTI_MODE_PULL_UP:
+ pupdr = STM_PUPDR_PULL_UP;
+ break;
+ case AO_EXTI_MODE_PULL_DOWN:
+ pupdr = STM_PUPDR_PULL_DOWN;
+ break;
+ }
+ stm_pupdr_set(gpio, pin, pupdr);
}
- stm_pupdr_set(gpio, pin, pupdr);
/* Set interrupt mask and rising/falling mode */
stm_exti.imr &= ~mask;
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include <ao.h>
+#include <ao_fast_timer.h>
+
+static void (*ao_fast_timer_callback[AO_FAST_TIMER_MAX])(void);
+static uint8_t ao_fast_timer_count;
+static uint8_t ao_fast_timer_users;
+
+static void
+ao_fast_timer_enable(void)
+{
+ stm_tim6.cr1 = ((0 << STM_TIM67_CR1_ARPE) |
+ (0 << STM_TIM67_CR1_OPM) |
+ (1 << STM_TIM67_CR1_URS) |
+ (0 << STM_TIM67_CR1_UDIS) |
+ (1 << STM_TIM67_CR1_CEN));
+}
+
+static void
+ao_fast_timer_disable(void)
+{
+ stm_tim6.cr1 = ((0 << STM_TIM67_CR1_ARPE) |
+ (0 << STM_TIM67_CR1_OPM) |
+ (1 << STM_TIM67_CR1_URS) |
+ (0 << STM_TIM67_CR1_UDIS) |
+ (0 << STM_TIM67_CR1_CEN));
+}
+
+void
+ao_fast_timer_on(void (*callback)(void))
+{
+ ao_fast_timer_callback[ao_fast_timer_count] = callback;
+ if (!ao_fast_timer_count++)
+ ao_fast_timer_enable();
+}
+
+void
+ao_fast_timer_off(void (*callback)(void))
+{
+ uint8_t n;
+
+ for (n = 0; n < ao_fast_timer_count; n++)
+ if (ao_fast_timer_callback[n] == callback) {
+ for (; n < ao_fast_timer_count-1; n++) {
+ ao_fast_timer_callback[n] = ao_fast_timer_callback[n+1];
+ }
+ if (!--ao_fast_timer_count)
+ ao_fast_timer_disable();
+ break;
+ }
+}
+
+void stm_tim6_isr(void)
+{
+ uint8_t i;
+ if (stm_tim6.sr & (1 << STM_TIM67_SR_UIF)) {
+ stm_tim6.sr = 0;
+
+ for (i = 0; i < ao_fast_timer_count; i++)
+ (*ao_fast_timer_callback[i])();
+ }
+}
+
+/*
+ * According to the STM clock-configuration, timers run
+ * twice as fast as the APB1 clock *if* the APB1 prescaler
+ * is greater than 1.
+ */
+
+#if AO_APB1_PRESCALER > 1
+#define TIMER_23467_SCALER 2
+#else
+#define TIMER_23467_SCALER 1
+#endif
+
+#define TIMER_10kHz ((AO_PCLK1 * TIMER_23467_SCALER) / 10000)
+
+void
+ao_fast_timer_init(void)
+{
+ if (!ao_fast_timer_users) {
+ stm_nvic_set_enable(STM_ISR_TIM6_POS);
+ stm_nvic_set_priority(STM_ISR_TIM6_POS, AO_STM_NVIC_CLOCK_PRIORITY);
+
+ /* Turn on timer 6 */
+ stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_TIM6EN);
+
+ stm_tim6.psc = TIMER_10kHz;
+ stm_tim6.arr = 9;
+ stm_tim6.cnt = 0;
+
+ /* Enable update interrupt */
+ stm_tim6.dier = (1 << STM_TIM67_DIER_UIE);
+
+ /* Poke timer to reload values */
+ stm_tim6.egr |= (1 << STM_TIM67_EGR_UG);
+
+ stm_tim6.cr2 = (STM_TIM67_CR2_MMS_RESET << STM_TIM67_CR2_MMS);
+ ao_fast_timer_disable();
+ }
+ if (ao_fast_timer_users == AO_FAST_TIMER_MAX)
+ ao_panic(AO_PANIC_FAST_TIMER);
+ ao_fast_timer_users++;
+}
+
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_FAST_TIMER_H_
+#define _AO_FAST_TIMER_H_
+
+void
+ao_fast_timer_init(void);
+
+#ifndef AO_FAST_TIMER_MAX
+#define AO_FAST_TIMER_MAX 2
+#endif
+
+void
+ao_fast_timer_on(void (*callback)(void));
+
+void
+ao_fast_timer_off(void (*callback)(void));
+
+#endif /* _AO_FAST_TIMER_H_ */
;
}
-static void __attribute__ ((section(".text.ram"),noinline))
+static void __attribute__ ((section(".ramtext"),noinline))
_ao_flash_erase_page(uint32_t *page)
{
stm_flash.pecr |= (1 << STM_FLASH_PECR_ERASE) | (1 << STM_FLASH_PECR_PROG);
ao_flash_lock();
}
-static void __attribute__ ((section(".text.ram"), noinline))
+static void __attribute__ ((section(".ramtext"), noinline))
_ao_flash_half_page(uint32_t *dst, uint32_t *src)
{
uint8_t i;
}
#endif
-/*
- * According to the STM clock-configuration, timers run
- * twice as fast as the APB1 clock *if* the APB1 prescaler
- * is greater than 1.
- */
-
-#if AO_APB1_PRESCALER > 1
-#define TIMER_23467_SCALER 2
-#else
-#define TIMER_23467_SCALER 1
-#endif
-
-#define TIMER_10kHz ((AO_PCLK1 * TIMER_23467_SCALER) / 10000)
-
#define SYSTICK_RELOAD (AO_SYSTICK / 100 - 1)
void
/* Switch to MSI while messing about */
stm_rcc.cr |= (1 << STM_RCC_CR_MSION);
while (!(stm_rcc.cr & (1 << STM_RCC_CR_MSIRDY)))
- asm("nop");
+ ao_arch_nop();
+
+ stm_rcc.cfgr = (stm_rcc.cfgr & ~(STM_RCC_CFGR_SW_MASK << STM_RCC_CFGR_SW)) |
+ (STM_RCC_CFGR_SW_MSI << STM_RCC_CFGR_SW);
+
+ /* wait for system to switch to MSI */
+ while ((stm_rcc.cfgr & (STM_RCC_CFGR_SWS_MASK << STM_RCC_CFGR_SWS)) !=
+ (STM_RCC_CFGR_SWS_MSI << STM_RCC_CFGR_SWS))
+ ao_arch_nop();
/* reset SW, HPRE, PPRE1, PPRE2, MCOSEL and MCOPRE */
stm_rcc.cfgr &= (uint32_t)0x88FFC00C;
stm_flash.acr |= (1 << STM_FLASH_ACR_PRFEN);
/* Enable 1 wait state so the CPU can run at 32MHz */
- /* (haven't managed to run the CPU at 32MHz yet, it's at 16MHz) */
stm_flash.acr |= (1 << STM_FLASH_ACR_LATENCY);
/* Enable power interface clock */
}
static void
-ao_usb_ep0_in_start(uint8_t max)
+ao_usb_ep0_in_start(uint16_t max)
{
/* Don't send more than asked for */
if (ao_usb_ep0_in_len > max)
stm_usb.cntr = (1 << STM_USB_CNTR_PDWN) | (1 << STM_USB_CNTR_FRES);
/* Disable the interface */
- stm_rcc.apb1enr &+ ~(1 << STM_RCC_APB1ENR_USBEN);
+ stm_rcc.apb1enr &= ~(1 << STM_RCC_APB1ENR_USBEN);
ao_arch_release_interrupts();
}
return (gpio->idr >> pin) & 1;
}
+static inline uint16_t
+stm_gpio_get_all(struct stm_gpio *gpio) {
+ return gpio->idr;
+}
+
extern struct stm_gpio stm_gpioa;
extern struct stm_gpio stm_gpiob;
extern struct stm_gpio stm_gpioc;
#define STM_TIM234_CCMR1_CC1S_INPUT_TRC 3
#define STM_TIM234_CCMR1_CC1S_MASK 3
-#define STM_TIM234_CCMR2_OC2CE 15
+#define STM_TIM234_CCMR2_OC4CE 15
#define STM_TIM234_CCMR2_OC4M 12
#define STM_TIM234_CCMR2_OC4M_FROZEN 0
#define STM_TIM234_CCMR2_OC4M_SET_HIGH_ON_MATCH 1
all: $(PROG)
$(PROG): $(REL) Makefile
- $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) ..
+ $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL)
$(call quiet,CHECK_STACK) ../cc1111/ao_arch.h $(PMEM) || rm $@
ao_product.h: ao-make-product.5c ../Version
#if HAS_GPS
/* Record current GPS position by waking up GPS log tasks */
- ao_wakeup(&ao_gps_data);
- ao_wakeup(&ao_gps_tracking_data);
+ ao_gps_new = AO_GPS_NEW_DATA | AO_GPS_NEW_TRACKING;
+ ao_wakeup(&ao_gps_new);
#endif
ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
all: $(PROG)
$(PROG): $(REL) Makefile
- $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) ..
+ $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL)
$(call quiet,CHECK_STACK) ../cc1111/ao_arch.h $(PMEM) || rm $@
ao_product.h: ao-make-product.5c ../Version
# Otherwise, print the full command line.
quiet ?= $($1)
-all: ../$(PROG)
+all: $(PROG)
-../$(PROG): $(REL) Makefile
- $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) ..
+$(PROG): $(REL) Makefile
+ $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL)
$(call quiet,CHECK_STACK) ../cc1111/ao_arch.h $(PMEM) || rm $@
ao_product.h: ao-make-product.5c ../Version
#define AO_LED_CONTINUITY(c) (1 << ((c) + 2))
#define AO_LED_CONTINUITY_MASK (0xc)
-#define AO_LED_RX 0x10
-#define AO_LED_TX 0x20
-#define AO_LED_ARMED 0x40
-#define AO_LED_POWER 0x80
-
-#define AO_LED_RED AO_LED_TX
-#define AO_LED_GREEN AO_LED_RX
+#define AO_LED_ARMED 0x10
+#define AO_LED_RED 0x20
+#define AO_LED_AMBER 0x40
+#define AO_LED_GREEN 0x80
#define LEDS_AVAILABLE (0xff)
#define HAS_EXTERNAL_TEMP 0
--- /dev/null
+telefire-*
+ao_product.h
--- /dev/null
+--directory=../cc1111:../product:../core:../drivers:.
+
--- /dev/null
+#
+# TeleFire build file
+#
+
+TELEFIRE_VER=0.2
+TELEFIRE_DEF=0_2
+
+vpath %.c ..:../core:../cc1111:../drivers:../product
+vpath %.h ..:../core:../cc1111:../drivers:../product
+vpath ao-make-product.5c ../util
+
+ifndef VERSION
+include ../Version
+endif
+
+INC = \
+ ao.h \
+ ao_pins.h \
+ ao_arch.h \
+ ao_arch_funcs.h \
+ ao_pad.h \
+ cc1111.h \
+ ao_product.h
+
+CORE_SRC = \
+ ao_cmd.c \
+ ao_config.c \
+ ao_convert.c \
+ ao_mutex.c \
+ ao_panic.c \
+ ao_stdio.c \
+ ao_storage.c \
+ ao_task.c \
+ ao_freq.c
+
+CC1111_SRC = \
+ ao_adc.c \
+ ao_aes.c \
+ ao_beep.c \
+ ao_dma.c \
+ ao_intflash.c \
+ ao_radio.c \
+ ao_radio_cmac.c \
+ ao_romconfig.c \
+ ao_serial.c \
+ ao_spi.c \
+ ao_string.c \
+ ao_timer.c \
+ ao_usb.c \
+ _bp.c
+
+DRIVER_SRC = \
+ ao_pca9922.c \
+ ao_74hc165.c \
+ ao_pad.c \
+ ao_radio_cmac_cmd.c
+
+PRODUCT_SRC = \
+ ao_telefire.c
+
+SRC = \
+ $(CORE_SRC) \
+ $(CC1111_SRC) \
+ $(DRIVER_SRC) \
+ $(PRODUCT_SRC)
+
+PROGNAME = telefire-v$(TELEFIRE_VER)
+PROG = $(PROGNAME)-$(VERSION).ihx
+PRODUCT=TeleFire-v$(TELEFIRE_VER)
+PRODUCT_DEF=-DTELEFIRE_V_$(TELEFIRE_DEF)
+IDPRODUCT=0x000f
+CODESIZE=0x6700
+
+include ../cc1111/Makefile.cc1111
+
+NICKLE=nickle
+CHECK_STACK=sh ../util/check-stack
+
+V=0
+# The user has explicitly enabled quiet compilation.
+ifeq ($(V),0)
+quiet = @printf " $1 $2 $@\n"; $($1)
+endif
+# Otherwise, print the full command line.
+quiet ?= $($1)
+
+all: $(PROG)
+
+$(PROG): $(REL) Makefile
+ $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL)
+ $(call quiet,CHECK_STACK) ../cc1111/ao_arch.h $(PMEM) || rm $@
+
+ao_product.h: ao-make-product.5c ../Version
+ $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@
+
+distclean: clean
+
+clean: clean-cc1111
+
+install:
+
+uninstall:
+
--- /dev/null
+/*
+ * 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.
+ */
+
+#ifndef _AO_PINS_H_
+#define _AO_PINS_H_
+
+#define HAS_RADIO 1
+
+#define HAS_FLIGHT 0
+#define HAS_USB 1
+#define HAS_BEEP 0
+#define HAS_GPS 0
+#define HAS_SERIAL_1 0
+#define HAS_ADC 1
+#define HAS_DBG 0
+#define HAS_EEPROM 1
+#define HAS_LOG 0
+#define HAS_PAD 1
+#define USE_INTERNAL_FLASH 1
+#define DBG_ON_P1 0
+#define IGNITE_ON_P2 0
+#define IGNITE_ON_P1 1
+#define IGNITE_ON_P0 0
+#define PACKET_HAS_MASTER 0
+#define PACKET_HAS_SLAVE 0
+
+#define AO_LED_CONTINUITY(c) (1 << (c))
+#define AO_LED_CONTINUITY_MASK (0xf)
+#define AO_LED_ARMED 0x10
+#define AO_LED_RED 0x20
+#define AO_LED_AMBER 0x40
+#define AO_LED_GREEN 0x80
+
+#define LEDS_AVAILABLE (0xff)
+#define HAS_EXTERNAL_TEMP 0
+#define HAS_ACCEL_REF 0
+#define SPI_CS_ON_P1 1
+#define HAS_AES 1
+#define DMA_SHARE_AES_RADIO 1
+
+#define SPI_CS_PORT P1
+#define SPI_CS_SEL P1SEL
+#define SPI_CS_DIR P1DIR
+
+#define SPI_CONST 0x00
+
+#define HAS_SPI_0 0
+#define HAS_SPI_1 1
+#define SPI_1_ALT_1 0
+#define SPI_1_ALT_2 1
+
+#define HAS_74HC165 1
+#define AO_74HC165_CS_PORT P1
+#define AO_74HC165_CS_PIN 4
+#define AO_74HC165_CS P1_4
+
+#define AO_PCA9922_CS_PORT P2
+#define AO_PCA9922_CS_PIN 0
+#define AO_PCA9922_CS P2_0
+
+#define AO_PAD_NUM 4
+#define AO_PAD_PORT P1
+#define AO_PAD_DIR P1DIR
+
+#define AO_PAD_PIN_0 0
+#define AO_PAD_0 P1_0
+#define AO_PAD_ADC_0 0
+
+#define AO_PAD_PIN_1 1
+#define AO_PAD_1 P1_1
+#define AO_PAD_ADC_1 1
+
+#define AO_PAD_PIN_2 2
+#define AO_PAD_2 P1_2
+#define AO_PAD_ADC_2 2
+
+#define AO_PAD_PIN_3 3
+#define AO_PAD_3 P1_3
+#define AO_PAD_ADC_3 3
+
+#define AO_PAD_ALL_PINS ((1 << AO_PAD_PIN_0) | (1 << AO_PAD_PIN_1) | (1 << AO_PAD_PIN_2) | (1 << AO_PAD_PIN_3))
+#define AO_PAD_ALL_CHANNELS ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3))
+
+#define AO_SIREN_PORT P2
+#define AO_SIREN_DIR P2DIR
+#define AO_SIREN_PIN 3
+#define AO_SIREN P2_3
+
+#define AO_STROBE_PORT P2
+#define AO_STROBE_DIR P2DIR
+#define AO_STROBE_PIN 4
+#define AO_STROBE P2_4
+
+/* test these values with real igniters */
+#define AO_PAD_RELAY_CLOSED 3524
+#define AO_PAD_NO_IGNITER 16904
+#define AO_PAD_GOOD_IGNITER 22514
+
+#define AO_PAD_ADC_PYRO 4
+#define AO_PAD_ADC_BATT 5
+
+#define AO_ADC_FIRST_PIN 0
+
+struct ao_adc {
+ int16_t sense[AO_PAD_NUM];
+ int16_t pyro;
+ int16_t batt;
+};
+
+#define AO_ADC_DUMP(p) \
+ printf ("tick: %5u 0: %5d 1: %5d 2: %5d 3: %5d pyro: %5d batt %5d\n", \
+ (p)->tick, \
+ (p)->adc.sense[0], \
+ (p)->adc.sense[1], \
+ (p)->adc.sense[2], \
+ (p)->adc.sense[3], \
+ (p)->adc.pyro, \
+ (p)->adc.batt)
+
+#define AO_ADC_PINS ((1 << AO_PAD_ADC_0) | \
+ (1 << AO_PAD_ADC_1) | \
+ (1 << AO_PAD_ADC_2) | \
+ (1 << AO_PAD_ADC_3) | \
+ (1 << AO_PAD_ADC_PYRO) | \
+ (1 << AO_PAD_ADC_BATT))
+
+#endif /* _AO_PINS_H_ */
--- /dev/null
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+#include <ao_pad.h>
+#include <ao_74hc165.h>
+#include <ao_radio_cmac_cmd.h>
+
+void
+main(void)
+{
+ ao_clock_init();
+
+ ao_led_init(LEDS_AVAILABLE);
+
+ ao_task_init();
+
+ ao_timer_init();
+ ao_adc_init();
+ ao_cmd_init();
+ ao_spi_init();
+ ao_74hc165_init();
+ ao_storage_init();
+ ao_usb_init();
+ ao_radio_init();
+ ao_aes_init();
+ ao_pad_init();
+// ao_radio_cmac_cmd_init();
+ ao_config_init();
+ ao_start_scheduler();
+}
ao_exti_stm.c \
ao_serial_stm.c \
ao_gps_skytraq.c \
+ ao_gps_show.c \
ao_cc115l.c \
ao_fec_tx.c \
ao_rfpa0133.c \
ao_aprs.c \
- ao_storage.c \
ao_eeprom_stm.c \
ao_sdcard.c \
ao_bufio.c \
PROGNAME=telegps-v0.1
PROG=$(PROGNAME)-$(VERSION).elf
+HEX=$(PROGNAME)-$(VERSION).ihx
SRC=$(ALTOS_SRC) ao_telegps.c
OBJ=$(SRC:.c=.o)
-all: $(PROG)
+all: $(PROG) $(HEX)
$(PROG): Makefile $(OBJ) altos.ld
- $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(SAT_CLIB) -lgcc
+ $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
$(OBJ): $(INC)
distclean: clean
clean:
- rm -f *.o $(PROGNAME)-*.elf
+ rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx
rm -f ao_product.h
install:
#define ao_gps_fifo (ao_stm_usart2.rx_fifo)
#define HAS_EEPROM 1
-#define USE_INTERNAL_FLASH 1
+#define USE_INTERNAL_FLASH 0
+#define USE_EEPROM_CONFIG 1
+#define USE_STORAGE_CONFIG 0
+
#define HAS_USB 1
#define HAS_BEEP 0
#define HAS_RADIO 1
#include <ao.h>
#include <ao_exti.h>
#include <ao_fat.h>
+#include <ao_eeprom.h>
uint16_t ao_flight_number = 1;
ao_dma_init();
ao_exti_init();
- ao_storage_init();
+ ao_eeprom_init();
ao_serial_init();
--- /dev/null
+ao_product.h
+ao_serial_lpc.h
+*.elf
--- /dev/null
+#
+# AltOS build
+#
+#
+
+include ../lpc/Makefile.defs
+
+INC = \
+ ao.h \
+ ao_arch.h \
+ ao_arch_funcs.h \
+ ao_pins.h \
+ ao_product.h \
+ ao_task.h \
+ ao_whiten.h \
+ ao_cc115l.h \
+ ao_fec.h \
+ lpc.h \
+ Makefile
+
+
+ALTOS_SRC = \
+ ao_interrupt.c \
+ ao_boot_chain.c \
+ ao_product.c \
+ ao_romconfig.c \
+ ao_cmd.c \
+ ao_config.c \
+ ao_task.c \
+ ao_stdio.c \
+ ao_panic.c \
+ ao_timer_lpc.c \
+ ao_mutex.c \
+ ao_freq.c \
+ ao_spi_lpc.c \
+ ao_usb_lpc.c \
+ ao_exti_lpc.c \
+ ao_serial_lpc.c \
+ ao_gps_ublox.c \
+ ao_gps_show.c \
+ ao_cc115l.c \
+ ao_fec_tx.c \
+ ao_aprs.c \
+ ao_telemetry.c \
+ ao_storage.c \
+ ao_m25.c \
+ ao_log.c \
+ ao_log_mega.c \
+ ao_gps_report_mega.c \
+ $(SAMPLE_PROFILE)
+
+PRODUCT=TeleGPS-v0.3
+PRODUCT_DEF=-DTELEGPS
+IDPRODUCT=0x0025
+
+CFLAGS = $(PRODUCT_DEF) $(LPC_CFLAGS) $(PROFILE_DEF) -Os -g
+
+PROGNAME=telegps-v0.3
+PROG=$(PROGNAME)-$(VERSION).elf
+
+SRC=$(ALTOS_SRC) ao_telegps.c
+OBJ=$(SRC:.c=.o)
+
+all: $(PROG)
+
+LDFLAGS=-L../lpc -Wl,-Taltos.ld
+
+$(PROG): Makefile $(OBJ) altos.ld
+ $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
+
+$(OBJ): $(INC)
+
+ao_product.h: ao-make-product.5c ../Version
+ $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@
+
+distclean: clean
+
+clean:
+ rm -f *.o ao_serial_lpc.h $(PROGNAME)-*.elf $(PROGNAME)-*.ihx
+ rm -f ao_product.h
+
+install:
+
+uninstall:
--- /dev/null
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_PINS_H_
+#define _AO_PINS_H_
+
+#define AO_STACK_SIZE 448
+
+#define IS_FLASH_LOADER 0
+
+/* Crystal on the board */
+#define AO_LPC_CLKIN 12000000
+
+/* Main clock frequency. 48MHz for USB so we don't use the USB PLL */
+#define AO_LPC_CLKOUT 48000000
+
+/* System clock frequency */
+#define AO_LPC_SYSCLK 24000000
+
+#define HAS_SERIAL_0 1
+#define SERIAL_0_18_19 1
+#define USE_SERIAL_0_STDIN 0
+
+#define ao_gps_getchar ao_serial0_getchar
+#define ao_gps_putchar ao_serial0_putchar
+#define ao_gps_set_speed ao_serial0_set_speed
+#define ao_gps_fifo (ao_usart_rx_fifo)
+
+#define HAS_EEPROM 1
+#define USE_INTERNAL_FLASH 0
+#define HAS_USB 1
+#define HAS_BEEP 0
+#define HAS_RADIO 1
+#define HAS_TELEMETRY 1
+#define HAS_RDF 0
+#define HAS_APRS 1
+#define HAS_RADIO_RECV 0
+
+#define HAS_USB_PULLUP 1
+#define AO_USB_PULLUP_PORT 0
+#define AO_USB_PULLUP_PIN 7
+
+/* Flash part */
+#define HAS_SPI_0 1
+#define SPI_SCK0_P0_6 1
+#define SPI_0_OSPEEDR AO_SPI_OSPEED_12MHz
+
+/* Radio */
+#define HAS_SPI_1 1
+#define SPI_SCK1_P1_15 1
+#define SPI_MISO1_P0_22 1
+#define SPI_MOSI1_P0_21 1
+
+#define HAS_GPS 1
+#define HAS_FLIGHT 0
+#define HAS_ADC 0
+#define HAS_LOG 1
+
+#define AO_CONFIG_DEFAULT_APRS_INTERVAL 5
+#define AO_CONFIG_DEFAULT_RADIO_POWER 0xc0
+
+/*
+ * GPS
+ */
+
+#define AO_SERIAL_SPEED_UBLOX AO_SERIAL_SPEED_9600
+
+/*
+ * Radio (cc115l)
+ */
+
+/* gets pretty close to 434.550 */
+
+#define AO_RADIO_CAL_DEFAULT 0x10b6a5
+
+#define HAS_RADIO_POWER 1
+#define AO_FEC_DEBUG 0
+#define AO_CC115L_SPI_CS_PORT 0
+#define AO_CC115L_SPI_CS_PIN 3
+#define AO_CC115L_SPI_BUS 0
+
+#define AO_CC115L_FIFO_INT_GPIO_IOCFG CC115L_IOCFG2
+#define AO_CC115L_FIFO_INT_PORT 0
+#define AO_CC115L_FIFO_INT_PIN 20
+
+#define AO_CC115L_DONE_INT_GPIO_IOCFG CC115L_IOCFG0
+#define AO_CC115L_DONE_INT_PORT 0
+#define AO_CC115L_DONE_INT_PIN 2
+
+/*
+ * Flash (M25)
+ */
+#define M25_MAX_CHIPS 1
+#define AO_M25_SPI_CS_PORT 0
+#define AO_M25_SPI_CS_MASK (1 << 23)
+#define AO_M25_SPI_BUS 1
+
+#define PACKET_HAS_SLAVE 0
+
+#endif /* _AO_PINS_H_ */
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+#include <ao_exti.h>
+#include <ao_fat.h>
+
+uint16_t ao_flight_number = 1;
+
+int
+main(void)
+{
+ ao_clock_init();
+
+#if HAS_STACK_GUARD
+ ao_mpu_init();
+#endif
+
+ ao_task_init();
+ ao_timer_init();
+
+
+ ao_spi_init();
+ ao_exti_init();
+
+ ao_storage_init();
+
+ ao_serial_init();
+
+ ao_cmd_init();
+
+ ao_usb_init();
+ ao_radio_init();
+
+ ao_gps_init();
+#if HAS_LOG
+ ao_gps_report_mega_init();
+ ao_log_init();
+#endif
+
+ ao_telemetry_init();
+ ao_telemetry_set_interval(AO_SEC_TO_TICKS(1));
+
+#if HAS_SAMPLE_PROFILE
+ ao_sample_profile_init();
+#endif
+ ao_config_init();
+
+ ao_start_scheduler();
+ return 0;
+}
--- /dev/null
+#
+# AltOS flash loader build
+#
+#
+
+TOPDIR=../..
+HARDWARE=telegps-v0.3
+include $(TOPDIR)/lpc/Makefile-flash.defs
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_PINS_H_
+#define _AO_PINS_H_
+
+#include <ao_flash_lpc_pins.h>
+
+#define AO_BOOT_PIN 1
+#define AO_BOOT_APPLICATION_GPIO 0
+#define AO_BOOT_APPLICATION_PIN 19
+#define AO_BOOT_APPLICATION_VALUE 1
+#define AO_BOOT_APPLICATION_MODE AO_EXTI_MODE_PULL_UP
+
+#define HAS_USB_PULLUP 1
+#define AO_USB_PULLUP_PORT 0
+#define AO_USB_PULLUP_PIN 7
+
+#endif /* _AO_PINS_H_ */
PROGNAME=telelco-v0.1
PROG=$(PROGNAME)-$(VERSION).elf
+HEX=$(PROGNAME)-$(VERSION).ihx
SRC=$(ALTOS_SRC) ao_telelco.c
OBJ=$(SRC:.c=.o)
-all: $(PROG)
+all: $(PROG) $(HEX)
$(PROG): Makefile $(OBJ) altos.ld
- $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(SAT_CLIB) -lgcc
+ $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
../altitude.h: make-altitude
nickle $< > $@
distclean: clean
clean:
- rm -f *.o $(PROGNAME)-*.elf
+ rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx
rm -f ao_product.h
install:
ao_radio_spi.h \
ao_radio_cmac.h \
ao_cc1120_CC1120.h \
+ ao_debounce.h \
stm32l.h
#
ao_dma_stm.c \
ao_spi_stm.c \
ao_beep_stm.c \
- ao_storage.c \
ao_eeprom_stm.c \
+ ao_fast_timer.c \
ao_lcd_stm.c \
ao_usb_stm.c \
ao_exti_stm.c \
ao_fec_tx.c \
ao_fec_rx.c \
ao_seven_segment.c \
+ ao_debounce.c \
ao_quadrature.c \
ao_button.c \
ao_event.c \
PROGNAME=telelco-v0.2
PROG=$(PROGNAME)-$(VERSION).elf
+HEX=$(PROGNAME)-$(VERSION).ihx
SRC=$(ALTOS_SRC) ao_telelco.c
OBJ=$(SRC:.c=.o)
-all: $(PROG)
+all: $(PROG) $(HEX)
$(PROG): Makefile $(OBJ) altos.ld
- $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(SAT_CLIB) -lgcc
+ $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
../altitude.h: make-altitude
nickle $< > $@
distclean: clean
clean:
- rm -f *.o $(PROGNAME)-*.elf
+ rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx
rm -f ao_product.h
install:
static struct ao_pad_query ao_pad_query;
static void
-ao_lco_set_pad(void)
+ao_lco_set_pad(uint8_t pad)
{
- ao_seven_segment_set(AO_LCO_PAD_DIGIT, ao_lco_pad + 1);
+ ao_seven_segment_set(AO_LCO_PAD_DIGIT, pad + 1);
}
static void
-ao_lco_set_box(void)
+ao_lco_set_box(uint8_t box)
{
- ao_seven_segment_set(AO_LCO_BOX_DIGIT_1, ao_lco_box % 10);
- ao_seven_segment_set(AO_LCO_BOX_DIGIT_10, ao_lco_box / 10);
+ ao_seven_segment_set(AO_LCO_BOX_DIGIT_1, box % 10);
+ ao_seven_segment_set(AO_LCO_BOX_DIGIT_10, box / 10);
}
#define MASK_SIZE(n) (((n) + 7) >> 3)
int8_t dir, new_box, new_pad;
ao_beep_for(AO_BEEP_MID, AO_MS_TO_TICKS(200));
- ao_lco_set_pad();
- ao_lco_set_box();
for (;;) {
ao_event_get(&event);
PRINTD("event type %d unit %d value %d\n",
switch (event.unit) {
case AO_QUADRATURE_PAD:
if (!ao_lco_armed) {
- if (event.value == ao_lco_pad)
- break;
- dir = ((int8_t) event.value - (int8_t) ao_lco_pad) > 0 ? 1 : -1;
- new_pad = event.value;
- while (!ao_lco_pad_present(new_pad)) {
+ dir = (int8_t) event.value;
+ new_pad = ao_lco_pad;
+ do {
new_pad += dir;
if (new_pad > AO_PAD_MAX_CHANNELS)
new_pad = 0;
new_pad = AO_PAD_MAX_CHANNELS - 1;
if (new_pad == ao_lco_pad)
break;
- }
+ } while (!ao_lco_pad_present(new_pad));
if (new_pad != ao_lco_pad) {
ao_lco_pad = new_pad;
- ao_quadrature_count[AO_QUADRATURE_PAD] = ao_lco_pad;
- ao_lco_set_pad();
+ ao_lco_set_pad(ao_lco_pad);
}
}
break;
case AO_QUADRATURE_BOX:
if (!ao_lco_armed) {
- if (event.value == ao_lco_box)
- break;
- dir = ((int8_t) event.value - (int8_t) ao_lco_box) > 0 ? 1 : -1;
- new_box = event.value;
- while (!ao_lco_box_present(new_box)) {
+ dir = (int8_t) event.value;
+ new_box = ao_lco_box;
+ do {
new_box += dir;
if (new_box > ao_lco_max_box)
new_box = ao_lco_min_box;
else if (new_box < ao_lco_min_box)
- new_box = ao_lco_min_box;
+ new_box = ao_lco_max_box;
if (new_box == ao_lco_box)
break;
- }
- ao_quadrature_count[AO_QUADRATURE_PAD] = new_box;
+ } while (!ao_lco_box_present(new_box));
if (ao_lco_box != new_box) {
ao_lco_box = new_box;
ao_lco_got_channels = 0;
- ao_lco_set_box();
+ ao_lco_set_box(ao_lco_box);
}
}
break;
ao_lco_valid = 1;
if (!c) {
ao_lco_pad = ao_lco_pad_first();
- ao_lco_set_pad();
+ ao_lco_set_pad(ao_lco_pad);
}
} else
ao_lco_valid = 0;
query.igniter_status[2],
query.igniter_status[3]);
#endif
-
ao_wakeup(&ao_pad_query);
}
+static void
+ao_lco_box_reset_present(void)
+{
+ ao_lco_min_box = 0xff;
+ ao_lco_max_box = 0x00;
+ memset(ao_lco_box_mask, 0, sizeof (ao_lco_box_mask));
+}
+
static void
ao_lco_box_set_present(uint8_t box)
{
+ if (box < ao_lco_min_box)
+ ao_lco_min_box = box;
+ if (box > ao_lco_max_box)
+ ao_lco_max_box = box;
if (box >= AO_PAD_MAX_BOXES)
return;
ao_lco_box_mask[MASK_ID(box)] |= 1 << MASK_SHIFT(box);
{
uint16_t tick_offset;
int8_t r;
-
- ao_lco_min_box = 0xff;
- ao_lco_max_box = 0x00;
- for (ao_lco_box = 0; ao_lco_box < AO_PAD_MAX_BOXES; ao_lco_box++) {
- if ((ao_lco_box % 10) == 0)
- ao_lco_set_box();
- r = ao_lco_query(ao_lco_box, &ao_pad_query, &ao_lco_tick_offset);
+ uint8_t box;
+
+ ao_lco_box_reset_present();
+ for (box = 0; box < AO_PAD_MAX_BOXES; box++) {
+ if ((box % 10) == 0)
+ ao_lco_set_box(box);
+ tick_offset = 0;
+ r = ao_lco_query(box, &ao_pad_query, &tick_offset);
+ PRINTD("box %d result %d\n", box, r);
if (r == AO_RADIO_CMAC_OK) {
- if (ao_lco_box < ao_lco_min_box)
- ao_lco_min_box = ao_lco_box;
- if (ao_lco_box > ao_lco_max_box)
- ao_lco_max_box = ao_lco_box;
- ao_lco_box_set_present(ao_lco_box);
+ ao_lco_box_set_present(box);
+ ao_delay(AO_MS_TO_TICKS(30));
}
}
if (ao_lco_min_box <= ao_lco_max_box)
ao_lco_valid = 0;
ao_lco_got_channels = 0;
ao_lco_pad = 0;
+ ao_lco_set_pad(ao_lco_pad);
+ ao_lco_set_box(ao_lco_box);
}
static void
__code struct ao_cmds ao_lco_cmds[] = {
{ ao_lco_set_debug, "D <0 off, 1 on>\0Debug" },
+ { ao_lco_search, "s\0Search for pad boxes" },
{ 0, NULL }
};
#endif
#define HAS_EEPROM 1
#define USE_INTERNAL_FLASH 1
+#define USE_EEPROM_CONFIG 1
+#define USE_STORAGE_CONFIG 0
#define HAS_USB 1
#define HAS_BEEP 1
#define HAS_RADIO 1
*/
#define AO_QUADRATURE_COUNT 2
-#define AO_QUADRATURE_MODE 0
#define AO_QUADRATURE_0_PORT &stm_gpioe
#define AO_QUADRATURE_0_A 3
#include <ao_lco.h>
#include <ao_lco_cmd.h>
#include <ao_radio_cmac_cmd.h>
+#include <ao_eeprom.h>
int
main(void)
ao_quadrature_init();
ao_button_init();
- ao_storage_init();
+ ao_eeprom_init();
ao_radio_init();
ao_task.h \
ao_whiten.h \
ao_sample_profile.h \
+ ao_quaternion.h \
+ math.h \
ao_mpu.h \
stm32l.h \
Makefile
#STACK_GUARD=ao_mpu_stm.c
#STACK_GUARD_DEF=-DHAS_STACK_GUARD=1
+MATH_SRC=\
+ ef_acos.c \
+ ef_sqrt.c \
+ ef_rem_pio2.c \
+ kf_cos.c \
+ kf_sin.c \
+ kf_rem_pio2.c \
+ sf_copysign.c \
+ sf_cos.c \
+ sf_sin.c \
+ sf_fabs.c \
+ sf_floor.c \
+ sf_scalbn.c
+
ALTOS_SRC = \
ao_boot_chain.c \
ao_interrupt.c \
ao_mutex.c \
ao_serial_stm.c \
ao_gps_skytraq.c \
+ ao_gps_show.c \
ao_gps_report_mega.c \
ao_ignite.c \
ao_freq.c \
ao_hmc5883.c \
ao_adc_stm.c \
ao_beep_stm.c \
+ ao_eeprom_stm.c \
ao_storage.c \
ao_m25.c \
ao_usb_stm.c \
ao_companion.c \
ao_pyro.c \
ao_aprs.c \
+ $(MATH_SRC) \
$(PROFILE) \
$(SAMPLE_PROFILE) \
$(STACK_GUARD)
PROGNAME=telemega-v0.1
PROG=$(PROGNAME)-$(VERSION).elf
+HEX=$(PROGNAME)-$(VERSION).ihx
SRC=$(ALTOS_SRC) ao_telemega.c
OBJ=$(SRC:.c=.o)
-all: $(PROG)
+all: $(PROG) $(HEX)
$(PROG): Makefile $(OBJ) altos.ld
- $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(SAT_CLIB) -lgcc
+ $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
../altitude-pa.h: make-altitude-pa
nickle $< > $@
distclean: clean
clean:
- rm -f *.o $(PROGNAME)-*.elf
+ rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx
rm -f ao_product.h
install:
#define ao_gps_set_speed ao_serial3_set_speed
#define ao_gps_fifo (ao_stm_usart3.rx_fifo)
+#define AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX (1024 * 1024)
#define HAS_EEPROM 1
#define USE_INTERNAL_FLASH 0
+#define USE_EEPROM_CONFIG 1
+#define USE_STORAGE_CONFIG 0
#define HAS_USB 1
#define HAS_BEEP 1
#define HAS_RADIO 1
#define HAS_GPS 1
#define HAS_FLIGHT 1
#define HAS_ADC 1
+#define HAS_ADC_TEMP 1
#define HAS_LOG 1
/*
#define HAS_IGNITE 1
#define HAS_IGNITE_REPORT 1
-#define AO_SENSE_DROGUE(p) ((p)->adc.sense[0])
-#define AO_SENSE_MAIN(p) ((p)->adc.sense[1])
+#define AO_SENSE_PYRO(p,n) ((p)->adc.sense[n])
+#define AO_SENSE_DROGUE(p) ((p)->adc.sense[4])
+#define AO_SENSE_MAIN(p) ((p)->adc.sense[5])
#define AO_IGNITER_CLOSED 400
#define AO_IGNITER_OPEN 60
-#define AO_IGNITER_DROGUE_PORT (&stm_gpiod)
-#define AO_IGNITER_DROGUE_PIN 6
+/* Pyro A */
+#define AO_PYRO_PORT_0 (&stm_gpiod)
+#define AO_PYRO_PIN_0 6
-#define AO_IGNITER_MAIN_PORT (&stm_gpiod)
-#define AO_IGNITER_MAIN_PIN 7
+/* Pyro B */
+#define AO_PYRO_PORT_1 (&stm_gpiod)
+#define AO_PYRO_PIN_1 7
-#define AO_PYRO_PORT_0 (&stm_gpiob)
-#define AO_PYRO_PIN_0 5
+/* Pyro C */
+#define AO_PYRO_PORT_2 (&stm_gpiob)
+#define AO_PYRO_PIN_2 5
-#define AO_PYRO_PORT_1 (&stm_gpioe)
-#define AO_PYRO_PIN_1 4
+/* Pyro D */
+#define AO_PYRO_PORT_3 (&stm_gpioe)
+#define AO_PYRO_PIN_3 4
-#define AO_PYRO_PORT_2 (&stm_gpioe)
-#define AO_PYRO_PIN_2 6
+/* Drogue */
+#define AO_IGNITER_DROGUE_PORT (&stm_gpioe)
+#define AO_IGNITER_DROGUE_PIN 6
-#define AO_PYRO_PORT_3 (&stm_gpioe)
-#define AO_PYRO_PIN_3 5
+/* Main */
+#define AO_IGNITER_MAIN_PORT (&stm_gpioe)
+#define AO_IGNITER_MAIN_PIN 5
/* Number of general purpose pyro channels available */
#define AO_PYRO_NUM 4
int16_t sense[AO_ADC_NUM_SENSE];
int16_t v_batt;
int16_t v_pbatt;
- int16_t accel_ref;
- int16_t accel;
int16_t temp;
};
+#define AO_ADC_DUMP(p) \
+ printf("tick: %5u A: %5d B: %5d C: %5d D: %5d drogue: %5d main: %5d batt: %5d pbatt: %5d temp: %5d\n", \
+ (p)->tick, \
+ (p)->adc.sense[0], (p)->adc.sense[1], (p)->adc.sense[2], \
+ (p)->adc.sense[3], (p)->adc.sense[4], (p)->adc.sense[5], \
+ (p)->adc.v_batt, (p)->adc.v_pbatt, (p)->adc.temp)
+
#define AO_ADC_SENSE_A 0
#define AO_ADC_SENSE_A_PORT (&stm_gpioa)
#define AO_ADC_SENSE_A_PIN 0
#define AO_ADC_SENSE_D_PORT (&stm_gpioa)
#define AO_ADC_SENSE_D_PIN 3
-#define AO_ADC_SENSE_E 4
-#define AO_ADC_SENSE_E_PORT (&stm_gpioa)
-#define AO_ADC_SENSE_E_PIN 4
+#define AO_ADC_SENSE_DROGUE 4
+#define AO_ADC_SENSE_DROGUE_PORT (&stm_gpioa)
+#define AO_ADC_SENSE_DROGUE_PIN 4
-#define AO_ADC_SENSE_F 22
-#define AO_ADC_SENSE_F_PORT (&stm_gpioe)
-#define AO_ADC_SENSE_F_PIN 7
+#define AO_ADC_SENSE_MAIN 22
+#define AO_ADC_SENSE_MAIN_PORT (&stm_gpioe)
+#define AO_ADC_SENSE_MAIN_PIN 7
#define AO_ADC_V_BATT 8
#define AO_ADC_V_BATT_PORT (&stm_gpiob)
#define AO_ADC_V_PBATT_PORT (&stm_gpiob)
#define AO_ADC_V_PBATT_PIN 1
-#define AO_ADC_ACCEL_REF 10
-#define AO_ADC_ACCEL_REF_PORT (&stm_gpioc)
-#define AO_ADC_ACCEL_REF_PIN 0
-
-#define AO_ADC_ACCEL 11
-#define AO_ADC_ACCEL_PORT (&stm_gpioc)
-#define AO_ADC_ACCEL_PIN 1
-
#define AO_ADC_TEMP 16
#define AO_ADC_RCC_AHBENR ((1 << STM_RCC_AHBENR_GPIOAEN) | \
(1 << STM_RCC_AHBENR_GPIOEEN) | \
- (1 << STM_RCC_AHBENR_GPIOBEN) | \
- (1 << STM_RCC_AHBENR_GPIOCEN))
+ (1 << STM_RCC_AHBENR_GPIOBEN))
-#define AO_NUM_ADC_PIN (AO_ADC_NUM_SENSE + 4)
+#define AO_NUM_ADC_PIN (AO_ADC_NUM_SENSE + 2)
#define AO_ADC_PIN0_PORT AO_ADC_SENSE_A_PORT
#define AO_ADC_PIN0_PIN AO_ADC_SENSE_A_PIN
#define AO_ADC_PIN2_PIN AO_ADC_SENSE_C_PIN
#define AO_ADC_PIN3_PORT AO_ADC_SENSE_D_PORT
#define AO_ADC_PIN3_PIN AO_ADC_SENSE_D_PIN
-#define AO_ADC_PIN4_PORT AO_ADC_SENSE_E_PORT
-#define AO_ADC_PIN4_PIN AO_ADC_SENSE_E_PIN
-#define AO_ADC_PIN5_PORT AO_ADC_SENSE_F_PORT
-#define AO_ADC_PIN5_PIN AO_ADC_SENSE_F_PIN
+#define AO_ADC_PIN4_PORT AO_ADC_SENSE_DROGUE_PORT
+#define AO_ADC_PIN4_PIN AO_ADC_SENSE_DROGUE_PIN
+#define AO_ADC_PIN5_PORT AO_ADC_SENSE_MAIN_PORT
+#define AO_ADC_PIN5_PIN AO_ADC_SENSE_MAIN_PIN
#define AO_ADC_PIN6_PORT AO_ADC_V_BATT_PORT
#define AO_ADC_PIN6_PIN AO_ADC_V_BATT_PIN
#define AO_ADC_PIN7_PORT AO_ADC_V_PBATT_PORT
#define AO_ADC_PIN7_PIN AO_ADC_V_PBATT_PIN
-#define AO_ADC_PIN8_PORT AO_ADC_ACCEL_REF_PORT
-#define AO_ADC_PIN8_PIN AO_ADC_ACCEL_REF_PIN
-#define AO_ADC_PIN9_PORT AO_ADC_ACCEL_PORT
-#define AO_ADC_PIN9_PIN AO_ADC_ACCEL_PIN
-#define AO_NUM_ADC (AO_ADC_NUM_SENSE + 5)
+#define AO_NUM_ADC (AO_ADC_NUM_SENSE + 3)
#define AO_ADC_SQ1 AO_ADC_SENSE_A
#define AO_ADC_SQ2 AO_ADC_SENSE_B
#define AO_ADC_SQ3 AO_ADC_SENSE_C
#define AO_ADC_SQ4 AO_ADC_SENSE_D
-#define AO_ADC_SQ5 AO_ADC_SENSE_E
-#define AO_ADC_SQ6 AO_ADC_SENSE_F
+#define AO_ADC_SQ5 AO_ADC_SENSE_DROGUE
+#define AO_ADC_SQ6 AO_ADC_SENSE_MAIN
#define AO_ADC_SQ7 AO_ADC_V_BATT
#define AO_ADC_SQ8 AO_ADC_V_PBATT
-#define AO_ADC_SQ9 AO_ADC_ACCEL_REF
-#define AO_ADC_SQ10 AO_ADC_ACCEL
-#define AO_ADC_SQ11 AO_ADC_TEMP
+#define AO_ADC_SQ9 AO_ADC_TEMP
/*
* Pressure sensor settings
#define AO_CC1120_MARC_GPIO 3
#define AO_CC1120_MARC_GPIO_IOCFG CC1120_IOCFG3
-
#define HAS_BOOT_RADIO 0
/*
#define AO_MPU6000_INT_PORT (&stm_gpioc)
#define AO_MPU6000_INT_PIN 13
#define AO_MPU6000_I2C_INDEX STM_I2C_INDEX(1)
-
-#define HAS_HIGHG_ACCEL 0
+#define HAS_IMU 1
/*
* mma655x
#include <ao_packet.h>
#include <ao_companion.h>
#include <ao_profile.h>
+#include <ao_eeprom.h>
#if HAS_SAMPLE_PROFILE
#include <ao_sample_profile.h>
#endif
ao_mma655x_init();
#endif
+ ao_eeprom_init();
ao_storage_init();
ao_flight_init();
+++ /dev/null
-ao_product.h
-telemega-*.elf
+++ /dev/null
-#
-# AltOS build
-#
-#
-
-include ../stm/Makefile.defs
-
-INC = \
- ao.h \
- ao_arch.h \
- ao_arch_funcs.h \
- ao_companion.h \
- ao_data.h \
- ao_sample.h \
- ao_pins.h \
- altitude-pa.h \
- ao_kalman.h \
- ao_product.h \
- ao_ms5607.h \
- ao_hmc5883.h \
- ao_mpu6000.h \
- ao_mma655x.h \
- ao_cc1120_CC1120.h \
- ao_profile.h \
- ao_task.h \
- ao_whiten.h \
- ao_sample_profile.h \
- ao_mpu.h \
- stm32l.h \
- Makefile
-
-#
-# Common AltOS sources
-#
-# ao_hmc5883.c
-
-#PROFILE=ao_profile.c
-#PROFILE_DEF=-DAO_PROFILE=1
-
-#SAMPLE_PROFILE=ao_sample_profile.c \
-# ao_sample_profile_timer.c
-#SAMPLE_PROFILE_DEF=-DHAS_SAMPLE_PROFILE=1
-
-#STACK_GUARD=ao_mpu_stm.c
-#STACK_GUARD_DEF=-DHAS_STACK_GUARD=1
-
-ALTOS_SRC = \
- ao_boot_chain.c \
- ao_interrupt.c \
- ao_product.c \
- ao_romconfig.c \
- ao_cmd.c \
- ao_config.c \
- ao_task.c \
- ao_led.c \
- ao_stdio.c \
- ao_panic.c \
- ao_timer.c \
- ao_mutex.c \
- ao_serial_stm.c \
- ao_gps_ublox.c \
- ao_gps_report_mega.c \
- ao_ignite.c \
- ao_freq.c \
- ao_dma_stm.c \
- ao_spi_stm.c \
- ao_cc1120.c \
- ao_fec_tx.c \
- ao_fec_rx.c \
- ao_data.c \
- ao_ms5607.c \
- ao_mma655x.c \
- ao_hmc5883.c \
- ao_adc_stm.c \
- ao_beep_stm.c \
- ao_storage.c \
- ao_m25.c \
- ao_usb_stm.c \
- ao_exti_stm.c \
- ao_report.c \
- ao_i2c_stm.c \
- ao_mpu6000.c \
- ao_convert_pa.c \
- ao_log.c \
- ao_log_mega.c \
- ao_sample.c \
- ao_kalman.c \
- ao_flight.c \
- ao_telemetry.c \
- ao_packet_slave.c \
- ao_packet.c \
- ao_companion.c \
- ao_pyro.c \
- ao_aprs.c \
- $(PROFILE) \
- $(SAMPLE_PROFILE) \
- $(STACK_GUARD)
-
-PRODUCT=TeleMega-v0.3
-PRODUCT_DEF=-DTELEMEGA
-IDPRODUCT=0x0023
-
-CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF) -Os -g
-
-PROGNAME=telemega-v0.3
-PROG=$(PROGNAME)-$(VERSION).elf
-
-SRC=$(ALTOS_SRC) ao_telemega.c
-OBJ=$(SRC:.c=.o)
-
-all: $(PROG)
-
-$(PROG): Makefile $(OBJ) altos.ld
- $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(SAT_CLIB) -lgcc
-
-../altitude-pa.h: make-altitude-pa
- nickle $< > $@
-
-$(OBJ): $(INC)
-
-ao_product.h: ao-make-product.5c ../Version
- $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@
-
-distclean: clean
-
-clean:
- rm -f *.o $(PROGNAME)-*.elf
- rm -f ao_product.h
-
-install:
-
-uninstall:
+++ /dev/null
-/*
- * Copyright © 2012 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-#ifndef _AO_PINS_H_
-#define _AO_PINS_H_
-
-#define HAS_TASK_QUEUE 1
-
-/* 8MHz High speed external crystal */
-#define AO_HSE 8000000
-
-/* PLLVCO = 96MHz (so that USB will work) */
-#define AO_PLLMUL 12
-#define AO_RCC_CFGR_PLLMUL (STM_RCC_CFGR_PLLMUL_12)
-
-/* SYSCLK = 32MHz (no need to go faster than CPU) */
-#define AO_PLLDIV 3
-#define AO_RCC_CFGR_PLLDIV (STM_RCC_CFGR_PLLDIV_3)
-
-/* HCLK = 32MHz (CPU clock) */
-#define AO_AHB_PRESCALER 1
-#define AO_RCC_CFGR_HPRE_DIV STM_RCC_CFGR_HPRE_DIV_1
-
-/* Run APB1 at 16MHz (HCLK/2) */
-#define AO_APB1_PRESCALER 2
-#define AO_RCC_CFGR_PPRE1_DIV STM_RCC_CFGR_PPRE2_DIV_2
-
-/* Run APB2 at 16MHz (HCLK/2) */
-#define AO_APB2_PRESCALER 2
-#define AO_RCC_CFGR_PPRE2_DIV STM_RCC_CFGR_PPRE2_DIV_2
-
-#define HAS_SERIAL_1 1
-#define USE_SERIAL_1_STDIN 0
-#define SERIAL_1_PB6_PB7 0
-#define SERIAL_1_PA9_PA10 1
-
-#define HAS_SERIAL_2 0
-#define USE_SERIAL_2_STDIN 0
-#define SERIAL_2_PA2_PA3 0
-#define SERIAL_2_PD5_PD6 0
-
-#define HAS_SERIAL_3 1
-#define USE_SERIAL_3_STDIN 0
-#define SERIAL_3_PB10_PB11 0
-#define SERIAL_3_PC10_PC11 1
-#define SERIAL_3_PD8_PD9 0
-
-#define ao_gps_getchar ao_serial3_getchar
-#define ao_gps_putchar ao_serial3_putchar
-#define ao_gps_set_speed ao_serial3_set_speed
-#define ao_gps_fifo (ao_stm_usart3.rx_fifo)
-
-#define HAS_EEPROM 1
-#define USE_INTERNAL_FLASH 0
-#define HAS_USB 1
-#define HAS_BEEP 1
-#define HAS_RADIO 1
-#define HAS_TELEMETRY 1
-#define HAS_APRS 1
-
-#define HAS_SPI_1 1
-#define SPI_1_PA5_PA6_PA7 1 /* Barometer */
-#define SPI_1_PB3_PB4_PB5 0
-#define SPI_1_PE13_PE14_PE15 1 /* Accelerometer, Gyro */
-#define SPI_1_OSPEEDR STM_OSPEEDR_10MHz
-
-#define HAS_SPI_2 1
-#define SPI_2_PB13_PB14_PB15 1 /* Flash, Companion */
-#define SPI_2_PD1_PD3_PD4 0
-#define SPI_2_OSPEEDR STM_OSPEEDR_10MHz
-
-#define SPI_2_PORT (&stm_gpiob)
-#define SPI_2_SCK_PIN 13
-#define SPI_2_MISO_PIN 14
-#define SPI_2_MOSI_PIN 15
-
-#define HAS_I2C_1 1
-#define I2C_1_PB8_PB9 1
-
-#define HAS_I2C_2 0
-#define I2C_2_PB10_PB11 0
-
-#define PACKET_HAS_SLAVE 1
-#define PACKET_HAS_MASTER 0
-
-#define LOW_LEVEL_DEBUG 0
-
-#define LED_PORT_ENABLE STM_RCC_AHBENR_GPIOCEN
-#define LED_PORT (&stm_gpioc)
-#define LED_PIN_RED 8
-#define LED_PIN_GREEN 9
-#define AO_LED_RED (1 << LED_PIN_RED)
-#define AO_LED_GREEN (1 << LED_PIN_GREEN)
-
-#define LEDS_AVAILABLE (AO_LED_RED | AO_LED_GREEN)
-
-#define HAS_GPS 1
-#define HAS_FLIGHT 1
-#define HAS_ADC 1
-#define HAS_ADC_TEMP 1
-#define HAS_LOG 1
-
-/*
- * Igniter
- */
-
-#define HAS_IGNITE 1
-#define HAS_IGNITE_REPORT 1
-
-#define AO_SENSE_DROGUE(p) ((p)->adc.sense[0])
-#define AO_SENSE_MAIN(p) ((p)->adc.sense[1])
-#define AO_IGNITER_CLOSED 400
-#define AO_IGNITER_OPEN 60
-
-#define AO_IGNITER_DROGUE_PORT (&stm_gpiod)
-#define AO_IGNITER_DROGUE_PIN 6
-
-#define AO_IGNITER_MAIN_PORT (&stm_gpiod)
-#define AO_IGNITER_MAIN_PIN 7
-
-#define AO_PYRO_PORT_0 (&stm_gpiob)
-#define AO_PYRO_PIN_0 5
-
-#define AO_PYRO_PORT_1 (&stm_gpioe)
-#define AO_PYRO_PIN_1 4
-
-#define AO_PYRO_PORT_2 (&stm_gpioe)
-#define AO_PYRO_PIN_2 6
-
-#define AO_PYRO_PORT_3 (&stm_gpioe)
-#define AO_PYRO_PIN_3 5
-
-/* Number of general purpose pyro channels available */
-#define AO_PYRO_NUM 4
-
-#define AO_IGNITER_SET_DROGUE(v) stm_gpio_set(AO_IGNITER_DROGUE_PORT, AO_IGNITER_DROGUE_PIN, v)
-#define AO_IGNITER_SET_MAIN(v) stm_gpio_set(AO_IGNITER_MAIN_PORT, AO_IGNITER_MAIN_PIN, v)
-
-/*
- * ADC
- */
-#define AO_DATA_RING 32
-#define AO_ADC_NUM_SENSE 6
-
-struct ao_adc {
- int16_t sense[AO_ADC_NUM_SENSE];
- int16_t v_batt;
- int16_t v_pbatt;
- int16_t temp;
-};
-
-#define AO_ADC_SENSE_A 0
-#define AO_ADC_SENSE_A_PORT (&stm_gpioa)
-#define AO_ADC_SENSE_A_PIN 0
-
-#define AO_ADC_SENSE_B 1
-#define AO_ADC_SENSE_B_PORT (&stm_gpioa)
-#define AO_ADC_SENSE_B_PIN 1
-
-#define AO_ADC_SENSE_C 2
-#define AO_ADC_SENSE_C_PORT (&stm_gpioa)
-#define AO_ADC_SENSE_C_PIN 2
-
-#define AO_ADC_SENSE_D 3
-#define AO_ADC_SENSE_D_PORT (&stm_gpioa)
-#define AO_ADC_SENSE_D_PIN 3
-
-#define AO_ADC_SENSE_E 4
-#define AO_ADC_SENSE_E_PORT (&stm_gpioa)
-#define AO_ADC_SENSE_E_PIN 4
-
-#define AO_ADC_SENSE_F 22
-#define AO_ADC_SENSE_F_PORT (&stm_gpioe)
-#define AO_ADC_SENSE_F_PIN 7
-
-#define AO_ADC_V_BATT 8
-#define AO_ADC_V_BATT_PORT (&stm_gpiob)
-#define AO_ADC_V_BATT_PIN 0
-
-#define AO_ADC_V_PBATT 9
-#define AO_ADC_V_PBATT_PORT (&stm_gpiob)
-#define AO_ADC_V_PBATT_PIN 1
-
-#define AO_ADC_TEMP 16
-
-#define AO_ADC_RCC_AHBENR ((1 << STM_RCC_AHBENR_GPIOAEN) | \
- (1 << STM_RCC_AHBENR_GPIOEEN) | \
- (1 << STM_RCC_AHBENR_GPIOBEN))
-
-#define AO_NUM_ADC_PIN (AO_ADC_NUM_SENSE + 2)
-
-#define AO_ADC_PIN0_PORT AO_ADC_SENSE_A_PORT
-#define AO_ADC_PIN0_PIN AO_ADC_SENSE_A_PIN
-#define AO_ADC_PIN1_PORT AO_ADC_SENSE_B_PORT
-#define AO_ADC_PIN1_PIN AO_ADC_SENSE_B_PIN
-#define AO_ADC_PIN2_PORT AO_ADC_SENSE_C_PORT
-#define AO_ADC_PIN2_PIN AO_ADC_SENSE_C_PIN
-#define AO_ADC_PIN3_PORT AO_ADC_SENSE_D_PORT
-#define AO_ADC_PIN3_PIN AO_ADC_SENSE_D_PIN
-#define AO_ADC_PIN4_PORT AO_ADC_SENSE_E_PORT
-#define AO_ADC_PIN4_PIN AO_ADC_SENSE_E_PIN
-#define AO_ADC_PIN5_PORT AO_ADC_SENSE_F_PORT
-#define AO_ADC_PIN5_PIN AO_ADC_SENSE_F_PIN
-#define AO_ADC_PIN6_PORT AO_ADC_V_BATT_PORT
-#define AO_ADC_PIN6_PIN AO_ADC_V_BATT_PIN
-#define AO_ADC_PIN7_PORT AO_ADC_V_PBATT_PORT
-#define AO_ADC_PIN7_PIN AO_ADC_V_PBATT_PIN
-
-#define AO_NUM_ADC (AO_ADC_NUM_SENSE + 3)
-
-#define AO_ADC_SQ1 AO_ADC_SENSE_A
-#define AO_ADC_SQ2 AO_ADC_SENSE_B
-#define AO_ADC_SQ3 AO_ADC_SENSE_C
-#define AO_ADC_SQ4 AO_ADC_SENSE_D
-#define AO_ADC_SQ5 AO_ADC_SENSE_E
-#define AO_ADC_SQ6 AO_ADC_SENSE_F
-#define AO_ADC_SQ7 AO_ADC_V_BATT
-#define AO_ADC_SQ8 AO_ADC_V_PBATT
-#define AO_ADC_SQ9 AO_ADC_TEMP
-
-/*
- * Pressure sensor settings
- */
-#define HAS_MS5607 1
-#define HAS_MS5611 0
-#define AO_MS5607_PRIVATE_PINS 1
-#define AO_MS5607_CS_PORT (&stm_gpioc)
-#define AO_MS5607_CS_PIN 4
-#define AO_MS5607_CS_MASK (1 << AO_MS5607_CS)
-#define AO_MS5607_MISO_PORT (&stm_gpioa)
-#define AO_MS5607_MISO_PIN 6
-#define AO_MS5607_MISO_MASK (1 << AO_MS5607_MISO)
-#define AO_MS5607_SPI_INDEX AO_SPI_1_PA5_PA6_PA7
-
-/*
- * SPI Flash memory
- */
-
-#define M25_MAX_CHIPS 1
-#define AO_M25_SPI_CS_PORT (&stm_gpiod)
-#define AO_M25_SPI_CS_MASK (1 << 3)
-#define AO_M25_SPI_BUS AO_SPI_2_PB13_PB14_PB15
-
-/*
- * Radio (cc1120)
- */
-
-/* gets pretty close to 434.550 */
-
-#define AO_RADIO_CAL_DEFAULT 0x6ca333
-
-#define AO_FEC_DEBUG 0
-#define AO_CC1120_SPI_CS_PORT (&stm_gpioc)
-#define AO_CC1120_SPI_CS_PIN 5
-#define AO_CC1120_SPI_BUS AO_SPI_2_PB13_PB14_PB15
-#define AO_CC1120_SPI stm_spi2
-
-#define AO_CC1120_INT_PORT (&stm_gpioe)
-#define AO_CC1120_INT_PIN 1
-#define AO_CC1120_MCU_WAKEUP_PORT (&stm_gpioc)
-#define AO_CC1120_MCU_WAKEUP_PIN (0)
-
-#define AO_CC1120_INT_GPIO 2
-#define AO_CC1120_INT_GPIO_IOCFG CC1120_IOCFG2
-
-#define AO_CC1120_MARC_GPIO 3
-#define AO_CC1120_MARC_GPIO_IOCFG CC1120_IOCFG3
-
-#define HAS_BOOT_RADIO 0
-
-/*
- * Mag sensor (hmc5883)
- */
-
-#define HAS_HMC5883 1
-#define AO_HMC5883_INT_PORT (&stm_gpioc)
-#define AO_HMC5883_INT_PIN 12
-#define AO_HMC5883_I2C_INDEX STM_I2C_INDEX(1)
-
-/*
- * mpu6000
- */
-
-#define HAS_MPU6000 1
-#define AO_MPU6000_INT_PORT (&stm_gpioe)
-#define AO_MPU6000_INT_PIN 0
-#define AO_MPU6000_SPI_BUS AO_SPI_1_PE13_PE14_PE15
-#define AO_MPU6000_SPI_CS_PORT (&stm_gpiod)
-#define AO_MPU6000_SPI_CS_PIN 2
-
-#define HAS_HIGHG_ACCEL 1
-
-/*
- * mma655x
- */
-
-#define HAS_MMA655X 1
-#define AO_MMA655X_SPI_INDEX AO_SPI_1_PE13_PE14_PE15
-#define AO_MMA655X_CS_PORT (&stm_gpiod)
-#define AO_MMA655X_CS_PIN 4
-
-#define NUM_CMDS 16
-
-/*
- * Companion
- */
-
-#define AO_COMPANION_CS_PORT (&stm_gpiod)
-#define AO_COMPANION_CS_PIN (0)
-#define AO_COMPANION_SPI_BUS AO_SPI_2_PB13_PB14_PB15
-
-/*
- * Monitor
- */
-
-#define HAS_MONITOR 0
-#define LEGACY_MONITOR 0
-#define HAS_MONITOR_PUT 1
-#define AO_MONITOR_LED 0
-#define HAS_RSSI 0
-
-/*
- * Profiling Viterbi decoding
- */
-
-#ifndef AO_PROFILE
-#define AO_PROFILE 0
-#endif
-
-#endif /* _AO_PINS_H_ */
+++ /dev/null
-/*
- * Copyright © 2011 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-#include <ao.h>
-#include <ao_hmc5883.h>
-#include <ao_mpu6000.h>
-#include <ao_mma655x.h>
-#include <ao_log.h>
-#include <ao_exti.h>
-#include <ao_packet.h>
-#include <ao_companion.h>
-#include <ao_profile.h>
-#if HAS_SAMPLE_PROFILE
-#include <ao_sample_profile.h>
-#endif
-#include <ao_pyro.h>
-#if HAS_STACK_GUARD
-#include <ao_mpu.h>
-#endif
-
-int
-main(void)
-{
- ao_clock_init();
-
-#if HAS_STACK_GUARD
- ao_mpu_init();
-#endif
-
- ao_task_init();
- ao_serial_init();
- ao_led_init(LEDS_AVAILABLE);
- ao_led_on(AO_LED_GREEN);
- ao_timer_init();
-
- ao_i2c_init();
- ao_spi_init();
- ao_dma_init();
- ao_exti_init();
-
- ao_adc_init();
-#if HAS_BEEP
- ao_beep_init();
-#endif
- ao_cmd_init();
-
-#if HAS_MS5607
- ao_ms5607_init();
-#endif
-#if HAS_HMC5883
- ao_hmc5883_init();
-#endif
-#if HAS_MPU6000
- ao_mpu6000_init();
-#endif
-#if HAS_MMA655X
- ao_mma655x_init();
-#endif
-
- ao_storage_init();
-
- ao_flight_init();
- ao_log_init();
- ao_report_init();
-
- ao_usb_init();
- ao_gps_init();
- ao_gps_report_mega_init();
- ao_telemetry_init();
- ao_radio_init();
- ao_packet_slave_init(FALSE);
- ao_igniter_init();
- ao_companion_init();
- ao_pyro_init();
-
- ao_config_init();
-#if AO_PROFILE
- ao_profile_init();
-#endif
-#if HAS_SAMPLE_PROFILE
- ao_sample_profile_init();
-#endif
-
- ao_start_scheduler();
- return 0;
-}
+++ /dev/null
-#
-# AltOS flash loader build
-#
-#
-
-TOPDIR=../..
-HARDWARE=telemega-v0.3
-include $(TOPDIR)/stm/Makefile-flash.defs
+++ /dev/null
-/*
- * Copyright © 2013 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-#ifndef _AO_PINS_H_
-#define _AO_PINS_H_
-
-/* External crystal at 8MHz */
-#define AO_HSE 8000000
-
-#include <ao_flash_stm_pins.h>
-
-/* Companion port cs_companion0 PD0 */
-
-#define AO_BOOT_PIN 1
-#define AO_BOOT_APPLICATION_GPIO stm_gpiod
-#define AO_BOOT_APPLICATION_PIN 0
-#define AO_BOOT_APPLICATION_VALUE 1
-#define AO_BOOT_APPLICATION_MODE AO_EXTI_MODE_PULL_UP
-
-#endif /* _AO_PINS_H_ */
--- /dev/null
+ao_product.h
+telemega-*.elf
--- /dev/null
+#
+# AltOS build
+#
+#
+
+include ../stm/Makefile.defs
+
+INC = \
+ ao.h \
+ ao_arch.h \
+ ao_arch_funcs.h \
+ ao_companion.h \
+ ao_data.h \
+ ao_sample.h \
+ ao_pins.h \
+ altitude-pa.h \
+ ao_kalman.h \
+ ao_product.h \
+ ao_ms5607.h \
+ ao_hmc5883.h \
+ ao_mpu6000.h \
+ ao_mma655x.h \
+ ao_cc1120_CC1120.h \
+ ao_profile.h \
+ ao_task.h \
+ ao_whiten.h \
+ ao_sample_profile.h \
+ ao_quaternion.h \
+ math.h \
+ ao_mpu.h \
+ stm32l.h \
+ math.h \
+ Makefile
+
+#
+# Common AltOS sources
+#
+# ao_hmc5883.c
+
+#PROFILE=ao_profile.c
+#PROFILE_DEF=-DAO_PROFILE=1
+
+#SAMPLE_PROFILE=ao_sample_profile.c \
+# ao_sample_profile_timer.c
+#SAMPLE_PROFILE_DEF=-DHAS_SAMPLE_PROFILE=1
+
+#STACK_GUARD=ao_mpu_stm.c
+#STACK_GUARD_DEF=-DHAS_STACK_GUARD=1
+
+MATH_SRC=\
+ ef_acos.c \
+ ef_sqrt.c \
+ ef_rem_pio2.c \
+ kf_cos.c \
+ kf_sin.c \
+ kf_rem_pio2.c \
+ sf_copysign.c \
+ sf_cos.c \
+ sf_fabs.c \
+ sf_floor.c \
+ sf_scalbn.c \
+ sf_sin.c
+
+ALTOS_SRC = \
+ ao_boot_chain.c \
+ ao_interrupt.c \
+ ao_product.c \
+ ao_romconfig.c \
+ ao_cmd.c \
+ ao_config.c \
+ ao_task.c \
+ ao_led.c \
+ ao_stdio.c \
+ ao_panic.c \
+ ao_timer.c \
+ ao_mutex.c \
+ ao_serial_stm.c \
+ ao_gps_ublox.c \
+ ao_gps_show.c \
+ ao_gps_report_mega.c \
+ ao_ignite.c \
+ ao_freq.c \
+ ao_dma_stm.c \
+ ao_spi_stm.c \
+ ao_cc1120.c \
+ ao_fec_tx.c \
+ ao_fec_rx.c \
+ ao_data.c \
+ ao_ms5607.c \
+ ao_mma655x.c \
+ ao_hmc5883.c \
+ ao_adc_stm.c \
+ ao_beep_stm.c \
+ ao_eeprom_stm.c \
+ ao_storage.c \
+ ao_m25.c \
+ ao_usb_stm.c \
+ ao_exti_stm.c \
+ ao_report.c \
+ ao_i2c_stm.c \
+ ao_mpu6000.c \
+ ao_convert_pa.c \
+ ao_log.c \
+ ao_log_mega.c \
+ ao_sample.c \
+ ao_kalman.c \
+ ao_flight.c \
+ ao_telemetry.c \
+ ao_packet_slave.c \
+ ao_packet.c \
+ ao_companion.c \
+ ao_pyro.c \
+ ao_aprs.c \
+ $(MATH_SRC) \
+ $(PROFILE) \
+ $(SAMPLE_PROFILE) \
+ $(STACK_GUARD)
+
+PRODUCT=TeleMega-v1.0
+PRODUCT_DEF=-DTELEMEGA
+IDPRODUCT=0x0023
+
+CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF) -Os -g
+
+PROGNAME=telemega-v1.0
+PROG=$(PROGNAME)-$(VERSION).elf
+HEX=$(PROGNAME)-$(VERSION).ihx
+
+SRC=$(ALTOS_SRC) ao_telemega.c
+OBJ=$(SRC:.c=.o)
+
+all: $(PROG) $(HEX)
+
+$(PROG): Makefile $(OBJ) altos.ld
+ $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
+
+../altitude-pa.h: make-altitude-pa
+ nickle $< > $@
+
+$(OBJ): $(INC)
+
+ao_product.h: ao-make-product.5c ../Version
+ $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@
+
+distclean: clean
+
+clean:
+ rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx
+ rm -f ao_product.h
+
+install:
+
+uninstall:
--- /dev/null
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_PINS_H_
+#define _AO_PINS_H_
+
+#define HAS_TASK_QUEUE 1
+
+/* 8MHz High speed external crystal */
+#define AO_HSE 8000000
+
+/* PLLVCO = 96MHz (so that USB will work) */
+#define AO_PLLMUL 12
+#define AO_RCC_CFGR_PLLMUL (STM_RCC_CFGR_PLLMUL_12)
+
+/* SYSCLK = 32MHz (no need to go faster than CPU) */
+#define AO_PLLDIV 3
+#define AO_RCC_CFGR_PLLDIV (STM_RCC_CFGR_PLLDIV_3)
+
+/* HCLK = 32MHz (CPU clock) */
+#define AO_AHB_PRESCALER 1
+#define AO_RCC_CFGR_HPRE_DIV STM_RCC_CFGR_HPRE_DIV_1
+
+/* Run APB1 at 16MHz (HCLK/2) */
+#define AO_APB1_PRESCALER 2
+#define AO_RCC_CFGR_PPRE1_DIV STM_RCC_CFGR_PPRE2_DIV_2
+
+/* Run APB2 at 16MHz (HCLK/2) */
+#define AO_APB2_PRESCALER 2
+#define AO_RCC_CFGR_PPRE2_DIV STM_RCC_CFGR_PPRE2_DIV_2
+
+#define HAS_SERIAL_1 1
+#define USE_SERIAL_1_STDIN 0
+#define SERIAL_1_PB6_PB7 0
+#define SERIAL_1_PA9_PA10 1
+
+#define HAS_SERIAL_2 0
+#define USE_SERIAL_2_STDIN 0
+#define SERIAL_2_PA2_PA3 0
+#define SERIAL_2_PD5_PD6 0
+
+#define HAS_SERIAL_3 1
+#define USE_SERIAL_3_STDIN 0
+#define SERIAL_3_PB10_PB11 0
+#define SERIAL_3_PC10_PC11 1
+#define SERIAL_3_PD8_PD9 0
+
+#define ao_gps_getchar ao_serial3_getchar
+#define ao_gps_putchar ao_serial3_putchar
+#define ao_gps_set_speed ao_serial3_set_speed
+#define ao_gps_fifo (ao_stm_usart3.rx_fifo)
+
+#define AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX (1024 * 1024)
+#define HAS_EEPROM 1
+#define USE_INTERNAL_FLASH 0
+#define USE_EEPROM_CONFIG 1
+#define USE_STORAGE_CONFIG 0
+#define HAS_USB 1
+#define HAS_BEEP 1
+#define HAS_RADIO 1
+#define HAS_TELEMETRY 1
+#define HAS_APRS 1
+
+#define HAS_SPI_1 1
+#define SPI_1_PA5_PA6_PA7 1 /* Barometer */
+#define SPI_1_PB3_PB4_PB5 0
+#define SPI_1_PE13_PE14_PE15 1 /* Accelerometer, Gyro */
+#define SPI_1_OSPEEDR STM_OSPEEDR_10MHz
+
+#define HAS_SPI_2 1
+#define SPI_2_PB13_PB14_PB15 1 /* Flash, Companion */
+#define SPI_2_PD1_PD3_PD4 0
+#define SPI_2_OSPEEDR STM_OSPEEDR_10MHz
+
+#define SPI_2_PORT (&stm_gpiob)
+#define SPI_2_SCK_PIN 13
+#define SPI_2_MISO_PIN 14
+#define SPI_2_MOSI_PIN 15
+
+#define HAS_I2C_1 1
+#define I2C_1_PB8_PB9 1
+
+#define HAS_I2C_2 0
+#define I2C_2_PB10_PB11 0
+
+#define PACKET_HAS_SLAVE 1
+#define PACKET_HAS_MASTER 0
+
+#define LOW_LEVEL_DEBUG 0
+
+#define LED_PORT_ENABLE STM_RCC_AHBENR_GPIOCEN
+#define LED_PORT (&stm_gpioc)
+#define LED_PIN_RED 8
+#define LED_PIN_GREEN 9
+#define AO_LED_RED (1 << LED_PIN_RED)
+#define AO_LED_GREEN (1 << LED_PIN_GREEN)
+
+#define LEDS_AVAILABLE (AO_LED_RED | AO_LED_GREEN)
+
+#define HAS_GPS 1
+#define HAS_FLIGHT 1
+#define HAS_ADC 1
+#define HAS_ADC_TEMP 1
+#define HAS_LOG 1
+
+/*
+ * Igniter
+ */
+
+#define HAS_IGNITE 1
+#define HAS_IGNITE_REPORT 1
+
+#define AO_SENSE_PYRO(p,n) ((p)->adc.sense[n])
+#define AO_SENSE_DROGUE(p) ((p)->adc.sense[4])
+#define AO_SENSE_MAIN(p) ((p)->adc.sense[5])
+#define AO_IGNITER_CLOSED 400
+#define AO_IGNITER_OPEN 60
+
+/* Pyro A */
+#define AO_PYRO_PORT_0 (&stm_gpiod)
+#define AO_PYRO_PIN_0 6
+
+/* Pyro B */
+#define AO_PYRO_PORT_1 (&stm_gpiod)
+#define AO_PYRO_PIN_1 7
+
+/* Pyro C */
+#define AO_PYRO_PORT_2 (&stm_gpiob)
+#define AO_PYRO_PIN_2 5
+
+/* Pyro D */
+#define AO_PYRO_PORT_3 (&stm_gpioe)
+#define AO_PYRO_PIN_3 4
+
+/* Drogue */
+#define AO_IGNITER_DROGUE_PORT (&stm_gpioe)
+#define AO_IGNITER_DROGUE_PIN 6
+
+/* Main */
+#define AO_IGNITER_MAIN_PORT (&stm_gpioe)
+#define AO_IGNITER_MAIN_PIN 5
+
+/* Number of general purpose pyro channels available */
+#define AO_PYRO_NUM 4
+
+#define AO_IGNITER_SET_DROGUE(v) stm_gpio_set(AO_IGNITER_DROGUE_PORT, AO_IGNITER_DROGUE_PIN, v)
+#define AO_IGNITER_SET_MAIN(v) stm_gpio_set(AO_IGNITER_MAIN_PORT, AO_IGNITER_MAIN_PIN, v)
+
+/*
+ * ADC
+ */
+#define AO_DATA_RING 32
+#define AO_ADC_NUM_SENSE 6
+
+struct ao_adc {
+ int16_t sense[AO_ADC_NUM_SENSE];
+ int16_t v_batt;
+ int16_t v_pbatt;
+ int16_t temp;
+};
+
+#define AO_ADC_DUMP(p) \
+ printf("tick: %5u A: %5d B: %5d C: %5d D: %5d drogue: %5d main: %5d batt: %5d pbatt: %5d temp: %5d\n", \
+ (p)->tick, \
+ (p)->adc.sense[0], (p)->adc.sense[1], (p)->adc.sense[2], \
+ (p)->adc.sense[3], (p)->adc.sense[4], (p)->adc.sense[5], \
+ (p)->adc.v_batt, (p)->adc.v_pbatt, (p)->adc.temp)
+
+#define AO_ADC_SENSE_A 0
+#define AO_ADC_SENSE_A_PORT (&stm_gpioa)
+#define AO_ADC_SENSE_A_PIN 0
+
+#define AO_ADC_SENSE_B 1
+#define AO_ADC_SENSE_B_PORT (&stm_gpioa)
+#define AO_ADC_SENSE_B_PIN 1
+
+#define AO_ADC_SENSE_C 2
+#define AO_ADC_SENSE_C_PORT (&stm_gpioa)
+#define AO_ADC_SENSE_C_PIN 2
+
+#define AO_ADC_SENSE_D 3
+#define AO_ADC_SENSE_D_PORT (&stm_gpioa)
+#define AO_ADC_SENSE_D_PIN 3
+
+#define AO_ADC_SENSE_DROGUE 4
+#define AO_ADC_SENSE_DROGUE_PORT (&stm_gpioa)
+#define AO_ADC_SENSE_DROGUE_PIN 4
+
+#define AO_ADC_SENSE_MAIN 22
+#define AO_ADC_SENSE_MAIN_PORT (&stm_gpioe)
+#define AO_ADC_SENSE_MAIN_PIN 7
+
+#define AO_ADC_V_BATT 8
+#define AO_ADC_V_BATT_PORT (&stm_gpiob)
+#define AO_ADC_V_BATT_PIN 0
+
+#define AO_ADC_V_PBATT 9
+#define AO_ADC_V_PBATT_PORT (&stm_gpiob)
+#define AO_ADC_V_PBATT_PIN 1
+
+#define AO_ADC_TEMP 16
+
+#define AO_ADC_RCC_AHBENR ((1 << STM_RCC_AHBENR_GPIOAEN) | \
+ (1 << STM_RCC_AHBENR_GPIOEEN) | \
+ (1 << STM_RCC_AHBENR_GPIOBEN))
+
+#define AO_NUM_ADC_PIN (AO_ADC_NUM_SENSE + 2)
+
+#define AO_ADC_PIN0_PORT AO_ADC_SENSE_A_PORT
+#define AO_ADC_PIN0_PIN AO_ADC_SENSE_A_PIN
+#define AO_ADC_PIN1_PORT AO_ADC_SENSE_B_PORT
+#define AO_ADC_PIN1_PIN AO_ADC_SENSE_B_PIN
+#define AO_ADC_PIN2_PORT AO_ADC_SENSE_C_PORT
+#define AO_ADC_PIN2_PIN AO_ADC_SENSE_C_PIN
+#define AO_ADC_PIN3_PORT AO_ADC_SENSE_D_PORT
+#define AO_ADC_PIN3_PIN AO_ADC_SENSE_D_PIN
+#define AO_ADC_PIN4_PORT AO_ADC_SENSE_DROGUE_PORT
+#define AO_ADC_PIN4_PIN AO_ADC_SENSE_DROGUE_PIN
+#define AO_ADC_PIN5_PORT AO_ADC_SENSE_MAIN_PORT
+#define AO_ADC_PIN5_PIN AO_ADC_SENSE_MAIN_PIN
+#define AO_ADC_PIN6_PORT AO_ADC_V_BATT_PORT
+#define AO_ADC_PIN6_PIN AO_ADC_V_BATT_PIN
+#define AO_ADC_PIN7_PORT AO_ADC_V_PBATT_PORT
+#define AO_ADC_PIN7_PIN AO_ADC_V_PBATT_PIN
+
+#define AO_NUM_ADC (AO_ADC_NUM_SENSE + 3)
+
+#define AO_ADC_SQ1 AO_ADC_SENSE_A
+#define AO_ADC_SQ2 AO_ADC_SENSE_B
+#define AO_ADC_SQ3 AO_ADC_SENSE_C
+#define AO_ADC_SQ4 AO_ADC_SENSE_D
+#define AO_ADC_SQ5 AO_ADC_SENSE_DROGUE
+#define AO_ADC_SQ6 AO_ADC_SENSE_MAIN
+#define AO_ADC_SQ7 AO_ADC_V_BATT
+#define AO_ADC_SQ8 AO_ADC_V_PBATT
+#define AO_ADC_SQ9 AO_ADC_TEMP
+
+/*
+ * Pressure sensor settings
+ */
+#define HAS_MS5607 1
+#define HAS_MS5611 0
+#define AO_MS5607_PRIVATE_PINS 1
+#define AO_MS5607_CS_PORT (&stm_gpioc)
+#define AO_MS5607_CS_PIN 4
+#define AO_MS5607_CS_MASK (1 << AO_MS5607_CS)
+#define AO_MS5607_MISO_PORT (&stm_gpioa)
+#define AO_MS5607_MISO_PIN 6
+#define AO_MS5607_MISO_MASK (1 << AO_MS5607_MISO)
+#define AO_MS5607_SPI_INDEX AO_SPI_1_PA5_PA6_PA7
+
+/*
+ * SPI Flash memory
+ */
+
+#define M25_MAX_CHIPS 1
+#define AO_M25_SPI_CS_PORT (&stm_gpiod)
+#define AO_M25_SPI_CS_MASK (1 << 3)
+#define AO_M25_SPI_BUS AO_SPI_2_PB13_PB14_PB15
+
+/*
+ * Radio (cc1120)
+ */
+
+/* gets pretty close to 434.550 */
+
+#define AO_RADIO_CAL_DEFAULT 0x6ca333
+
+#define AO_FEC_DEBUG 0
+#define AO_CC1120_SPI_CS_PORT (&stm_gpioc)
+#define AO_CC1120_SPI_CS_PIN 5
+#define AO_CC1120_SPI_BUS AO_SPI_2_PB13_PB14_PB15
+#define AO_CC1120_SPI stm_spi2
+
+#define AO_CC1120_INT_PORT (&stm_gpioe)
+#define AO_CC1120_INT_PIN 1
+#define AO_CC1120_MCU_WAKEUP_PORT (&stm_gpioc)
+#define AO_CC1120_MCU_WAKEUP_PIN (0)
+
+#define AO_CC1120_INT_GPIO 2
+#define AO_CC1120_INT_GPIO_IOCFG CC1120_IOCFG2
+
+#define AO_CC1120_MARC_GPIO 3
+#define AO_CC1120_MARC_GPIO_IOCFG CC1120_IOCFG3
+
+#define HAS_BOOT_RADIO 0
+
+/*
+ * Mag sensor (hmc5883)
+ */
+
+#define HAS_HMC5883 1
+#define AO_HMC5883_INT_PORT (&stm_gpioc)
+#define AO_HMC5883_INT_PIN 12
+#define AO_HMC5883_I2C_INDEX STM_I2C_INDEX(1)
+
+/*
+ * mpu6000
+ */
+
+#define HAS_MPU6000 1
+#define AO_MPU6000_INT_PORT (&stm_gpioe)
+#define AO_MPU6000_INT_PIN 0
+#define AO_MPU6000_SPI_BUS AO_SPI_1_PE13_PE14_PE15
+#define AO_MPU6000_SPI_CS_PORT (&stm_gpiod)
+#define AO_MPU6000_SPI_CS_PIN 2
+#define HAS_IMU 1
+
+/*
+ * mma655x
+ */
+
+#define HAS_MMA655X 1
+#define AO_MMA655X_SPI_INDEX AO_SPI_1_PE13_PE14_PE15
+#define AO_MMA655X_CS_PORT (&stm_gpiod)
+#define AO_MMA655X_CS_PIN 4
+
+#define NUM_CMDS 16
+
+/*
+ * Companion
+ */
+
+#define AO_COMPANION_CS_PORT (&stm_gpiod)
+#define AO_COMPANION_CS_PIN (0)
+#define AO_COMPANION_SPI_BUS AO_SPI_2_PB13_PB14_PB15
+
+/*
+ * Monitor
+ */
+
+#define HAS_MONITOR 0
+#define LEGACY_MONITOR 0
+#define HAS_MONITOR_PUT 1
+#define AO_MONITOR_LED 0
+#define HAS_RSSI 0
+
+/*
+ * Profiling Viterbi decoding
+ */
+
+#ifndef AO_PROFILE
+#define AO_PROFILE 0
+#endif
+
+#endif /* _AO_PINS_H_ */
--- /dev/null
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+#include <ao_hmc5883.h>
+#include <ao_mpu6000.h>
+#include <ao_mma655x.h>
+#include <ao_log.h>
+#include <ao_exti.h>
+#include <ao_packet.h>
+#include <ao_companion.h>
+#include <ao_profile.h>
+#include <ao_eeprom.h>
+#if HAS_SAMPLE_PROFILE
+#include <ao_sample_profile.h>
+#endif
+#include <ao_pyro.h>
+#if HAS_STACK_GUARD
+#include <ao_mpu.h>
+#endif
+
+int
+main(void)
+{
+ ao_clock_init();
+
+#if HAS_STACK_GUARD
+ ao_mpu_init();
+#endif
+
+ ao_task_init();
+ ao_serial_init();
+ ao_led_init(LEDS_AVAILABLE);
+ ao_led_on(AO_LED_GREEN);
+ ao_timer_init();
+
+ ao_i2c_init();
+ ao_spi_init();
+ ao_dma_init();
+ ao_exti_init();
+
+ ao_adc_init();
+#if HAS_BEEP
+ ao_beep_init();
+#endif
+ ao_cmd_init();
+
+#if HAS_MS5607
+ ao_ms5607_init();
+#endif
+#if HAS_HMC5883
+ ao_hmc5883_init();
+#endif
+#if HAS_MPU6000
+ ao_mpu6000_init();
+#endif
+#if HAS_MMA655X
+ ao_mma655x_init();
+#endif
+
+ ao_eeprom_init();
+ ao_storage_init();
+
+ ao_flight_init();
+ ao_log_init();
+ ao_report_init();
+
+ ao_usb_init();
+ ao_gps_init();
+ ao_gps_report_mega_init();
+ ao_telemetry_init();
+ ao_radio_init();
+ ao_packet_slave_init(FALSE);
+ ao_igniter_init();
+ ao_companion_init();
+ ao_pyro_init();
+
+ ao_config_init();
+#if AO_PROFILE
+ ao_profile_init();
+#endif
+#if HAS_SAMPLE_PROFILE
+ ao_sample_profile_init();
+#endif
+
+ ao_start_scheduler();
+ return 0;
+}
--- /dev/null
+#
+# AltOS flash loader build
+#
+#
+
+TOPDIR=../..
+HARDWARE=telemega-v1.0
+include $(TOPDIR)/stm/Makefile-flash.defs
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_PINS_H_
+#define _AO_PINS_H_
+
+/* External crystal at 8MHz */
+#define AO_HSE 8000000
+
+#include <ao_flash_stm_pins.h>
+
+/* Companion port cs_companion0 PD0 */
+
+#define AO_BOOT_PIN 1
+#define AO_BOOT_APPLICATION_GPIO stm_gpiod
+#define AO_BOOT_APPLICATION_PIN 0
+#define AO_BOOT_APPLICATION_VALUE 1
+#define AO_BOOT_APPLICATION_MODE AO_EXTI_MODE_PULL_UP
+
+#endif /* _AO_PINS_H_ */
TM_SRC = \
ao_gps_skytraq.c \
+ ao_gps_show.c \
ao_25lc1024.c
include ../product/Makefile.telemetrum
TM_SRC = \
ao_companion.c \
ao_gps_skytraq.c \
+ ao_gps_show.c \
ao_at45db161d.c
include ../product/Makefile.telemetrum
TM_SRC = \
ao_companion.c \
ao_gps_skytraq.c \
+ ao_gps_show.c \
ao_m25.c
include ../product/Makefile.telemetrum
TM_SRC = \
ao_companion.c \
ao_gps_skytraq.c \
+ ao_gps_show.c \
ao_m25.c
include ../product/Makefile.telemetrum
--- /dev/null
+ao_product.h
+telemetrum-*.elf
--- /dev/null
+#
+# AltOS build
+#
+#
+
+include ../stm/Makefile.defs
+
+INC = \
+ ao.h \
+ ao_arch.h \
+ ao_arch_funcs.h \
+ ao_companion.h \
+ ao_data.h \
+ ao_sample.h \
+ ao_pins.h \
+ altitude-pa.h \
+ ao_kalman.h \
+ ao_product.h \
+ ao_ms5607.h \
+ ao_mma655x.h \
+ ao_cc1120_CC1120.h \
+ ao_profile.h \
+ ao_task.h \
+ ao_whiten.h \
+ ao_sample_profile.h \
+ ao_mpu.h \
+ stm32l.h \
+ Makefile
+
+#PROFILE=ao_profile.c
+#PROFILE_DEF=-DAO_PROFILE=1
+
+#SAMPLE_PROFILE=ao_sample_profile.c \
+# ao_sample_profile_timer.c
+#SAMPLE_PROFILE_DEF=-DHAS_SAMPLE_PROFILE=1
+
+#STACK_GUARD=ao_mpu_stm.c
+#STACK_GUARD_DEF=-DHAS_STACK_GUARD=1
+
+ALTOS_SRC = \
+ ao_boot_chain.c \
+ ao_interrupt.c \
+ ao_product.c \
+ ao_romconfig.c \
+ ao_cmd.c \
+ ao_config.c \
+ ao_task.c \
+ ao_led.c \
+ ao_stdio.c \
+ ao_panic.c \
+ ao_timer.c \
+ ao_mutex.c \
+ ao_serial_stm.c \
+ ao_gps_ublox.c \
+ ao_gps_show.c \
+ ao_gps_report_metrum.c \
+ ao_ignite.c \
+ ao_freq.c \
+ ao_dma_stm.c \
+ ao_spi_stm.c \
+ ao_cc1120.c \
+ ao_fec_tx.c \
+ ao_fec_rx.c \
+ ao_data.c \
+ ao_ms5607.c \
+ ao_mma655x.c \
+ ao_adc_stm.c \
+ ao_beep_stm.c \
+ ao_storage.c \
+ ao_m25.c \
+ ao_usb_stm.c \
+ ao_exti_stm.c \
+ ao_eeprom_stm.c \
+ ao_report.c \
+ ao_convert_pa.c \
+ ao_log.c \
+ ao_log_metrum.c \
+ ao_sample.c \
+ ao_kalman.c \
+ ao_flight.c \
+ ao_telemetry.c \
+ ao_packet_slave.c \
+ ao_packet.c \
+ ao_companion.c \
+ ao_aprs.c \
+ $(PROFILE) \
+ $(SAMPLE_PROFILE) \
+ $(STACK_GUARD)
+
+PRODUCT=TeleMetrum-v2.0
+PRODUCT_DEF=-DTELEMETRUM_V_2_0
+IDPRODUCT=0x000b
+
+CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF) -Os -g
+
+PROGNAME=telemetrum-v2.0
+PROG=$(PROGNAME)-$(VERSION).elf
+HEX=$(PROGNAME)-$(VERSION).ihx
+
+SRC=$(ALTOS_SRC) ao_telemetrum.c
+OBJ=$(SRC:.c=.o)
+
+all: $(PROG) $(HEX)
+
+$(PROG): Makefile $(OBJ) altos.ld
+ $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
+
+../altitude-pa.h: make-altitude-pa
+ nickle $< > $@
+
+$(OBJ): $(INC)
+
+ao_product.h: ao-make-product.5c ../Version
+ $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@
+
+distclean: clean
+
+clean:
+ rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx
+ rm -f ao_product.h
+
+install:
+
+uninstall:
--- /dev/null
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_PINS_H_
+#define _AO_PINS_H_
+
+#define HAS_TASK_QUEUE 1
+
+/* 8MHz High speed external crystal */
+#define AO_HSE 8000000
+
+/* PLLVCO = 96MHz (so that USB will work) */
+#define AO_PLLMUL 12
+#define AO_RCC_CFGR_PLLMUL (STM_RCC_CFGR_PLLMUL_12)
+
+/* SYSCLK = 32MHz (no need to go faster than CPU) */
+#define AO_PLLDIV 3
+#define AO_RCC_CFGR_PLLDIV (STM_RCC_CFGR_PLLDIV_3)
+
+/* HCLK = 32MHz (CPU clock) */
+#define AO_AHB_PRESCALER 1
+#define AO_RCC_CFGR_HPRE_DIV STM_RCC_CFGR_HPRE_DIV_1
+
+/* Run APB1 at 16MHz (HCLK/2) */
+#define AO_APB1_PRESCALER 2
+#define AO_RCC_CFGR_PPRE1_DIV STM_RCC_CFGR_PPRE2_DIV_2
+
+/* Run APB2 at 16MHz (HCLK/2) */
+#define AO_APB2_PRESCALER 2
+#define AO_RCC_CFGR_PPRE2_DIV STM_RCC_CFGR_PPRE2_DIV_2
+
+#define HAS_SERIAL_1 0
+#define USE_SERIAL_1_STDIN 0
+#define SERIAL_1_PB6_PB7 0
+#define SERIAL_1_PA9_PA10 1
+
+#define HAS_SERIAL_2 0
+#define USE_SERIAL_2_STDIN 0
+#define SERIAL_2_PA2_PA3 0
+#define SERIAL_2_PD5_PD6 0
+
+#define HAS_SERIAL_3 1
+#define USE_SERIAL_3_STDIN 0
+#define SERIAL_3_PB10_PB11 1
+#define SERIAL_3_PC10_PC11 0
+#define SERIAL_3_PD8_PD9 0
+
+#define AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX (512 * 1024)
+#define HAS_EEPROM 1
+#define USE_INTERNAL_FLASH 0
+#define USE_EEPROM_CONFIG 1
+#define USE_STORAGE_CONFIG 0
+#define HAS_USB 1
+#define HAS_BEEP 1
+#define BEEPER_CHANNEL 4
+#define HAS_RADIO 1
+#define HAS_TELEMETRY 1
+#define HAS_APRS 1
+
+#define HAS_SPI_1 1
+#define SPI_1_PA5_PA6_PA7 1 /* Barometer */
+#define SPI_1_PB3_PB4_PB5 1 /* Accelerometer */
+#define SPI_1_PE13_PE14_PE15 0
+#define SPI_1_OSPEEDR STM_OSPEEDR_10MHz
+
+#define HAS_SPI_2 1
+#define SPI_2_PB13_PB14_PB15 1 /* Flash, Companion, Radio */
+#define SPI_2_PD1_PD3_PD4 0
+#define SPI_2_OSPEEDR STM_OSPEEDR_10MHz
+
+#define SPI_2_PORT (&stm_gpiob)
+#define SPI_2_SCK_PIN 13
+#define SPI_2_MISO_PIN 14
+#define SPI_2_MOSI_PIN 15
+
+#define HAS_I2C_1 0
+#define I2C_1_PB8_PB9 0
+
+#define HAS_I2C_2 0
+#define I2C_2_PB10_PB11 0
+
+#define PACKET_HAS_SLAVE 1
+#define PACKET_HAS_MASTER 0
+
+#define LOW_LEVEL_DEBUG 0
+
+#define LED_PORT_ENABLE STM_RCC_AHBENR_GPIOCEN
+#define LED_PORT (&stm_gpioc)
+#define LED_PIN_RED 14
+#define LED_PIN_GREEN 15
+#define AO_LED_RED (1 << LED_PIN_RED)
+#define AO_LED_GREEN (1 << LED_PIN_GREEN)
+
+#define LEDS_AVAILABLE (AO_LED_RED | AO_LED_GREEN)
+
+#define HAS_GPS 1
+#define HAS_FLIGHT 1
+#define HAS_ADC 1
+#define HAS_ADC_TEMP 1
+#define HAS_LOG 1
+
+/*
+ * Igniter
+ */
+
+#define HAS_IGNITE 1
+#define HAS_IGNITE_REPORT 1
+
+#define AO_SENSE_DROGUE(p) ((p)->adc.sense_a)
+#define AO_SENSE_MAIN(p) ((p)->adc.sense_m)
+#define AO_IGNITER_CLOSED 400
+#define AO_IGNITER_OPEN 60
+
+/* Drogue */
+#define AO_IGNITER_DROGUE_PORT (&stm_gpioa)
+#define AO_IGNITER_DROGUE_PIN 8
+
+/* Main */
+#define AO_IGNITER_MAIN_PORT (&stm_gpioa)
+#define AO_IGNITER_MAIN_PIN 9
+
+#define AO_IGNITER_SET_DROGUE(v) stm_gpio_set(AO_IGNITER_DROGUE_PORT, AO_IGNITER_DROGUE_PIN, v)
+#define AO_IGNITER_SET_MAIN(v) stm_gpio_set(AO_IGNITER_MAIN_PORT, AO_IGNITER_MAIN_PIN, v)
+
+/*
+ * ADC
+ */
+#define AO_DATA_RING 32
+#define AO_ADC_NUM_SENSE 2
+
+struct ao_adc {
+ int16_t sense_a;
+ int16_t sense_m;
+ int16_t v_batt;
+ int16_t temp;
+};
+
+#define AO_ADC_DUMP(p) \
+ printf("tick: %5u drogue: %5d main: %5d batt: %5d\n", \
+ (p)->tick, \
+ (p)->adc.sense_a, (p)->adc.sense_m, \
+ (p)->adc.v_batt);
+
+#define AO_ADC_SENSE_DROGUE 0
+#define AO_ADC_SENSE_DROGUE_PORT (&stm_gpioa)
+#define AO_ADC_SENSE_DROGUE_PIN 0
+
+#define AO_ADC_SENSE_MAIN 1
+#define AO_ADC_SENSE_MAIN_PORT (&stm_gpioa)
+#define AO_ADC_SENSE_MAIN_PIN 1
+
+#define AO_ADC_V_BATT 8
+#define AO_ADC_V_BATT_PORT (&stm_gpiob)
+#define AO_ADC_V_BATT_PIN 0
+
+#define AO_ADC_TEMP 16
+
+#define AO_ADC_RCC_AHBENR ((1 << STM_RCC_AHBENR_GPIOAEN) | \
+ (1 << STM_RCC_AHBENR_GPIOEEN) | \
+ (1 << STM_RCC_AHBENR_GPIOBEN))
+
+#define AO_NUM_ADC_PIN 3
+
+#define AO_ADC_PIN0_PORT AO_ADC_SENSE_DROGUE_PORT
+#define AO_ADC_PIN0_PIN AO_ADC_SENSE_DROGUE_PIN
+#define AO_ADC_PIN1_PORT AO_ADC_SENSE_MAIN_PORT
+#define AO_ADC_PIN1_PIN AO_ADC_SENSE_MAIN_PIN
+#define AO_ADC_PIN2_PORT AO_ADC_V_BATT_PORT
+#define AO_ADC_PIN2_PIN AO_ADC_V_BATT_PIN
+
+#define AO_NUM_ADC (AO_NUM_ADC_PIN + 1)
+
+#define AO_ADC_SQ1 AO_ADC_SENSE_DROGUE
+#define AO_ADC_SQ2 AO_ADC_SENSE_MAIN
+#define AO_ADC_SQ3 AO_ADC_V_BATT
+#define AO_ADC_SQ4 AO_ADC_TEMP
+
+/*
+ * GPS
+ */
+
+#define AO_SERIAL_SPEED_UBLOX AO_SERIAL_SPEED_9600
+
+#define ao_gps_getchar ao_serial3_getchar
+#define ao_gps_putchar ao_serial3_putchar
+#define ao_gps_set_speed ao_serial3_set_speed
+#define ao_gps_fifo (ao_stm_usart3.rx_fifo)
+
+/*
+ * Pressure sensor settings
+ */
+#define HAS_MS5607 1
+#define HAS_MS5611 0
+#define AO_MS5607_PRIVATE_PINS 1
+#define AO_MS5607_CS_PORT (&stm_gpiob)
+#define AO_MS5607_CS_PIN 12
+#define AO_MS5607_CS_MASK (1 << AO_MS5607_CS)
+#define AO_MS5607_MISO_PORT (&stm_gpioa)
+#define AO_MS5607_MISO_PIN 6
+#define AO_MS5607_MISO_MASK (1 << AO_MS5607_MISO)
+#define AO_MS5607_SPI_INDEX AO_SPI_1_PA5_PA6_PA7
+
+/*
+ * SPI Flash memory
+ */
+
+#define M25_MAX_CHIPS 1
+#define AO_M25_SPI_CS_PORT (&stm_gpiob)
+#define AO_M25_SPI_CS_MASK (1 << 8)
+#define AO_M25_SPI_BUS AO_SPI_2_PB13_PB14_PB15
+
+/*
+ * Radio (cc1120)
+ */
+
+/* gets pretty close to 434.550 */
+
+#define AO_RADIO_CAL_DEFAULT 0x6ca333
+
+#define AO_FEC_DEBUG 0
+#define AO_CC1120_SPI_CS_PORT (&stm_gpioa)
+#define AO_CC1120_SPI_CS_PIN 2
+#define AO_CC1120_SPI_BUS AO_SPI_2_PB13_PB14_PB15
+#define AO_CC1120_SPI stm_spi2
+
+#define AO_CC1120_INT_PORT (&stm_gpioa)
+#define AO_CC1120_INT_PIN (3)
+#define AO_CC1120_MCU_WAKEUP_PORT (&stm_gpioa)
+#define AO_CC1120_MCU_WAKEUP_PIN (4)
+
+#define AO_CC1120_INT_GPIO 2
+#define AO_CC1120_INT_GPIO_IOCFG CC1120_IOCFG2
+
+#define AO_CC1120_MARC_GPIO 3
+#define AO_CC1120_MARC_GPIO_IOCFG CC1120_IOCFG3
+
+#define HAS_BOOT_RADIO 0
+
+#define HAS_HIGHG_ACCEL 1
+
+/*
+ * mma655x
+ */
+
+#define HAS_MMA655X 1
+#define AO_MMA655X_SPI_INDEX AO_SPI_1_PB3_PB4_PB5
+#define AO_MMA655X_CS_PORT (&stm_gpiob)
+#define AO_MMA655X_CS_PIN 9
+#define AO_MMA655X_INVERT 1
+
+#define NUM_CMDS 16
+
+/*
+ * Companion
+ */
+
+#define AO_COMPANION_CS_PORT (&stm_gpiob)
+#define AO_COMPANION_CS_PIN (6)
+#define AO_COMPANION_SPI_BUS AO_SPI_2_PB13_PB14_PB15
+
+/*
+ * Monitor
+ */
+
+#define HAS_MONITOR 0
+#define LEGACY_MONITOR 0
+#define HAS_MONITOR_PUT 1
+#define AO_MONITOR_LED 0
+#define HAS_RSSI 0
+
+/*
+ * Profiling Viterbi decoding
+ */
+
+#ifndef AO_PROFILE
+#define AO_PROFILE 0
+#endif
+
+#endif /* _AO_PINS_H_ */
--- /dev/null
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+#include <ao_ms5607.h>
+#include <ao_mma655x.h>
+#include <ao_log.h>
+#include <ao_exti.h>
+#include <ao_packet.h>
+#include <ao_companion.h>
+#include <ao_eeprom.h>
+#include <ao_profile.h>
+#if HAS_SAMPLE_PROFILE
+#include <ao_sample_profile.h>
+#endif
+#if HAS_STACK_GUARD
+#include <ao_mpu.h>
+#endif
+
+int
+main(void)
+{
+ ao_clock_init();
+
+#if HAS_STACK_GUARD
+ ao_mpu_init();
+#endif
+
+ ao_task_init();
+ ao_serial_init();
+ ao_led_init(LEDS_AVAILABLE);
+ ao_led_on(AO_LED_RED);
+ ao_timer_init();
+
+ ao_spi_init();
+ ao_dma_init();
+ ao_exti_init();
+
+ ao_adc_init();
+#if HAS_BEEP
+ ao_beep_init();
+#endif
+ ao_cmd_init();
+
+#if HAS_MS5607
+ ao_ms5607_init();
+#endif
+#if HAS_MMA655X
+ ao_mma655x_init();
+#endif
+
+ ao_eeprom_init();
+
+ ao_storage_init();
+
+ ao_flight_init();
+ ao_log_init();
+ ao_report_init();
+
+ ao_usb_init();
+ ao_gps_init();
+ ao_gps_report_metrum_init();
+ ao_telemetry_init();
+ ao_radio_init();
+ ao_packet_slave_init(FALSE);
+ ao_igniter_init();
+ ao_companion_init();
+
+ ao_config_init();
+#if AO_PROFILE
+ ao_profile_init();
+#endif
+#if HAS_SAMPLE_PROFILE
+ ao_sample_profile_init();
+#endif
+
+ ao_start_scheduler();
+ return 0;
+}
--- /dev/null
+#
+# AltOS flash loader build
+#
+#
+
+TOPDIR=../..
+HARDWARE=telemetrum-v2.0
+include $(TOPDIR)/stm/Makefile-flash.defs
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_PINS_H_
+#define _AO_PINS_H_
+
+/* External crystal at 8MHz */
+#define AO_HSE 8000000
+
+#include <ao_flash_stm_pins.h>
+
+/* Companion port cs_companion0 PB6 */
+
+#define AO_BOOT_PIN 1
+#define AO_BOOT_APPLICATION_GPIO stm_gpiob
+#define AO_BOOT_APPLICATION_PIN 6
+#define AO_BOOT_APPLICATION_VALUE 1
+#define AO_BOOT_APPLICATION_MODE AO_EXTI_MODE_PULL_UP
+
+#endif /* _AO_PINS_H_ */
--- /dev/null
+ao_product.h
+telemini-v2.0*
--- /dev/null
+--directory=../cc1111:../product:../core:../drivers:.
+
--- /dev/null
+#
+# TeleMini build file
+#
+
+TELEMINI_VER=2.0
+TELEMINI_DEF=2_0
+
+vpath %.c ..:../core:../cc1111:../drivers:../product
+vpath %.h ..:../core:../cc1111:../drivers:../product
+vpath ao-make-product.5c ../util
+
+ifndef VERSION
+include ../Version
+endif
+
+INC = \
+ ao.h \
+ ao_pins.h \
+ ao_arch.h \
+ ao_arch_funcs.h \
+ cc1111.h \
+ ao_ms5607.h \
+ ao_ms5607_convert_8051.c \
+ ao_product.h \
+ ao_int64.h \
+ ao_sample.h \
+ ao_exti.h \
+ ao_task.h
+
+CORE_SRC = \
+ ao_cmd.c \
+ ao_config.c \
+ ao_convert.c \
+ ao_flight.c \
+ ao_kalman.c \
+ ao_log.c \
+ ao_log_mini.c \
+ ao_mutex.c \
+ ao_panic.c \
+ ao_report.c \
+ ao_sample.c \
+ ao_stdio.c \
+ ao_storage.c \
+ ao_task.c \
+ ao_telemetry.c \
+ ao_freq.c \
+ ao_int64.c
+
+CC1111_SRC = \
+ ao_adc.c \
+ ao_dma.c \
+ ao_ignite.c \
+ ao_led.c \
+ ao_packet.c \
+ ao_packet_slave.c \
+ ao_radio.c \
+ ao_romconfig.c \
+ ao_string.c \
+ ao_spi.c \
+ ao_usb.c \
+ ao_convert_pa.c \
+ ao_beep.c \
+ ao_timer.c \
+ ao_exti.c \
+ _bp.c
+
+DRIVER_SRC = \
+ ao_ms5607.c \
+ ao_m25.c
+
+PRODUCT_SRC = \
+ ao_telemini.c
+
+SRC = \
+ $(CORE_SRC) \
+ $(CC1111_SRC) \
+ $(DRIVER_SRC) \
+ $(PRODUCT_SRC)
+
+PROGNAME = telemini-v$(TELEMINI_VER)
+PROG = $(PROGNAME)-$(VERSION).ihx
+PRODUCT=TeleMini-v$(TELEMINI_VER)
+PRODUCT_DEF=-DTELEMINI_V_$(TELEMINI_DEF)
+IDPRODUCT=0x0027
+
+include ../cc1111/Makefile.cc1111
+
+NICKLE=nickle
+CHECK_STACK=sh ../util/check-stack
+
+V=0
+# The user has explicitly enabled quiet compilation.
+ifeq ($(V),0)
+quiet = @printf " $1 $2 $@\n"; $($1)
+endif
+# Otherwise, print the full command line.
+quiet ?= $($1)
+
+all: $(PROG)
+
+$(PROG): $(REL) Makefile
+ $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL)
+ $(call quiet,CHECK_STACK) ../cc1111/ao_arch.h $(PMEM) || rm $@
+
+ao_product.h: ao-make-product.5c ../Version
+ $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@
+
+distclean: clean
+
+clean: clean-cc1111
+
+install:
+
+uninstall:
+
--- /dev/null
+/*
+ * 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.
+ */
+
+#ifndef _AO_PINS_H_
+#define _AO_PINS_H_
+
+#define HAS_RADIO 1
+
+#define HAS_FLIGHT 1
+#define HAS_USB 1
+#define USB_FORCE_FLIGHT_IDLE 1
+#define HAS_BEEP 1
+#define HAS_GPS 0
+#define HAS_SERIAL_1 0
+#define HAS_EEPROM 1
+#define HAS_LOG 1
+#define USE_INTERNAL_FLASH 0
+#define HAS_DBG 0
+#define PACKET_HAS_SLAVE 1
+
+#define AO_LED_GREEN 1
+#define AO_LED_RED 2
+#define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN)
+#define HAS_EXTERNAL_TEMP 0
+#define HAS_ACCEL 0
+#define HAS_IGNITE 1
+#define HAS_IGNITE_REPORT 1
+#define HAS_MONITOR 0
+
+/*
+ * SPI
+ */
+
+#define HAS_SPI_0 1
+#define SPI_0_ALT_1 1
+#define HAS_SPI_1 1
+#define SPI_1_ALT_2 1
+#define SPI_CS_PORT P1
+#define SPI_CS_SEL P1SEL
+#define SPI_CS_DIR P1DIR
+
+/*
+ * Flash
+ */
+#define AO_M25_SPI_BUS 1
+#define AO_M25_SPI_CS_PORT SPI_CS_PORT
+#define AO_M25_SPI_CS_MASK 0x04 /* cs_flash is P1_2 */
+#define M25_MAX_CHIPS 1
+
+/*
+ * MS5607
+ */
+
+#define HAS_MS5607 1
+#define HAS_MS5611 0
+#define AO_MS5607_PRIVATE_PINS 0
+#define AO_MS5607_CS_PORT P1
+#define AO_MS5607_CS_PIN 3
+#define AO_MS5607_CS P1_3
+#define AO_MS5607_CS_MASK (1 << AO_MS5607_CS_PIN)
+#define AO_MS5607_MISO_PORT P0
+#define AO_MS5607_MISO_PIN 2
+#define AO_MS5607_MISO P0_2
+#define AO_MS5607_MISO_MASK (1 << AO_MS5607_MISO_PIN)
+#define AO_MS5607_SPI_INDEX 0
+#define HAS_EXTI_0 1
+
+/*
+ * Igniters
+ */
+#define AO_IGNITER_PORT P2
+#define AO_IGNITER_DROGUE_PORT AO_IGNITER_PORT
+#define AO_IGNITER_DROGUE P2_3
+#define AO_IGNITER_MAIN P2_4
+#define AO_IGNITER_DIR P2DIR
+#define AO_IGNITER_DROGUE_BIT (1 << 3)
+#define AO_IGNITER_MAIN_BIT (1 << 4)
+#define AO_IGNITER_DROGUE_PIN 3
+#define AO_IGNITER_MAIN_PIN 4
+
+#define AO_IGNITER_DROGUE_PORT AO_IGNITER_PORT
+#define AO_IGNITER_MAIN_PORT AO_IGNITER_PORT
+
+/* test these values with real igniters */
+#define AO_IGNITER_OPEN 1000
+#define AO_IGNITER_CLOSED 7000
+#define AO_IGNITER_FIRE_TIME AO_MS_TO_TICKS(50)
+#define AO_IGNITER_CHARGE_TIME AO_MS_TO_TICKS(2000)
+
+#define AO_SEND_MINI
+#define AO_LOG_FORMAT AO_LOG_FORMAT_TELEMINI
+
+/*
+ * ADC
+ */
+
+#define HAS_ADC 1
+#define AO_ADC_FIRST_PIN 0
+
+struct ao_adc {
+ int16_t sense_a; /* apogee continuity sense */
+ int16_t sense_m; /* main continuity sense */
+ int16_t v_batt; /* battery voltage */
+};
+
+#define ao_data_count ao_adc_count
+
+#define AO_SENSE_DROGUE(p) ((p)->adc.sense_a)
+#define AO_SENSE_MAIN(p) ((p)->adc.sense_m)
+
+#define AO_NUM_TASKS 10
+
+#define AO_ADC_DUMP(p) \
+ printf("tick: %5u apogee: %5d main: %5d batt: %5d\n", \
+ (p)->tick, (p)->adc.sense_a, (p)->adc.sense_m, (p)->adc.v_batt)
+
+#define AO_ADC_PINS ((1 << 0) | (1 << 1) | (1 << 4))
+
+#define FETCH_ADC() do { \
+ a = (uint8_t __xdata *) (&ao_data_ring[ao_data_head].adc); \
+ switch (sequence) { \
+ case 4: \
+ a += 4; \
+ sequence = 0; \
+ break; \
+ case 1: \
+ a += 2; \
+ sequence = 4; \
+ break; \
+ case 0: \
+ sequence = 1; \
+ break; \
+ } \
+ a[0] = ADCL; \
+ a[1] = ADCH; \
+ if (sequence) { \
+ ADCCON3 = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | sequence; \
+ return; \
+ } \
+ AO_DATA_PRESENT(AO_DATA_ADC); \
+ if (ao_data_present != AO_DATA_ALL) \
+ return; \
+ ao_data_ring[ao_data_head].ms5607_raw.pres = ao_ms5607_current.pres; \
+ ao_data_ring[ao_data_head].ms5607_raw.temp = ao_ms5607_current.temp; \
+ } while (0)
+
+#endif /* _AO_PINS_H_ */
--- /dev/null
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+#include "ao_pins.h"
+#include <ao_exti.h>
+
+__xdata uint8_t ao_force_freq;
+
+void
+main(void)
+{
+ ao_clock_init();
+
+#if HAS_STACK_GUARD
+ ao_mpu_init();
+#endif
+ ao_task_init();
+
+ /* Turn on the red LED until the system is stable */
+ ao_led_init(LEDS_AVAILABLE);
+ ao_led_on(AO_LED_RED);
+
+ ao_timer_init();
+
+ ao_spi_init();
+ ao_exti_init();
+ ao_adc_init();
+#if HAS_BEEP
+ ao_beep_init();
+#endif
+ ao_cmd_init();
+#if HAS_MS5607
+ ao_ms5607_init();
+#endif
+ ao_storage_init();
+
+ ao_flight_init();
+ ao_log_init();
+ ao_report_init();
+
+ ao_usb_init();
+ ao_telemetry_init();
+ ao_radio_init();
+ ao_packet_slave_init(TRUE);
+
+ ao_igniter_init();
+
+ ao_config_init();
+ ao_start_scheduler();
+}
vpath % .:..:../core:../product:../drivers:../avr
vpath ao-make-product.5c ../util
+include ../avr/Makefile.defs
+
MCU=atmega32u4
DUDECPUTYPE=m32u4
#PROGRAMMER=stk500v2 -P usb
-PROGRAMMER=usbtiny
-LOADCMD=avrdude
LOADARG=-p $(DUDECPUTYPE) -c $(PROGRAMMER) -e -U flash:w:
-CC=avr-gcc
-OBJCOPY=avr-objcopy
-
-ifndef VERSION
-include ../Version
-endif
INC = \
ao.h \
-telescience-v0.1*
+telescience-pwm*
ao_product.h
vpath % ..:../core:../product:../drivers:../avr
vpath ao-make-product.5c ../util
+include ../avr/Makefile.defs
+
MCU=atmega32u4
DUDECPUTYPE=m32u4
#PROGRAMMER=stk500v2 -P usb
-PROGRAMMER=usbtiny
-LOADCMD=avrdude
LOADARG=-p $(DUDECPUTYPE) -c $(PROGRAMMER) -e -U flash:w:
-CC=avr-gcc
-OBJCOPY=avr-objcopy
-ifndef VERSION
-include ../Version
-endif
+#LDFLAGS=-L$(LDSCRIPTS) -Tavr5.x
INC = \
ao.h \
vpath % ..:../core:../product:../drivers:../avr
vpath ao-make-product.5c ../util
+include ../avr/Makefile.defs
+
MCU=atmega32u4
DUDECPUTYPE=m32u4
#PROGRAMMER=stk500v2 -P usb
-PROGRAMMER=usbtiny
-LOADCMD=avrdude
LOADARG=-p $(DUDECPUTYPE) -c $(PROGRAMMER) -e -U flash:w:
-CC=avr-gcc
-OBJCOPY=avr-objcopy
-ifndef VERSION
-include ../Version
-endif
+#LDFLAGS=-L$(LDSCRIPTS) -Tavr5.x
INC = \
ao.h \
PROGNAME=telescience-v0.2
PROG=$(PROGNAME)-$(VERSION).elf
+HEX=$(PROGNAME)-$(VERSION).ihx
SRC=$(ALTOS_SRC) ao_telescience.c
OBJ=$(SRC:.c=.o)
-all: $(PROG)
+all: $(PROG) $(HEX)
$(PROG): Makefile $(OBJ) altos.ld
- $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(SAT_CLIB) -lgcc
+ $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
$(OBJ): $(INC)
distclean: clean
clean:
- rm -f *.o $(PROGNAME)-*.elf
+ rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx
rm -f ao_product.h
install:
--- /dev/null
+#
+# AltOS flash loader build
+#
+#
+
+TOPDIR=../..
+HARDWARE=telescience-v0.2
+include $(TOPDIR)/stm/Makefile-flash.defs
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_PINS_H_
+#define _AO_PINS_H_
+
+/* External crystal at 8MHz */
+#define AO_HSE 8000000
+
+#include <ao_flash_stm_pins.h>
+
+/* Companion port SS PA4 */
+
+#define AO_BOOT_PIN 1
+#define AO_BOOT_APPLICATION_GPIO stm_gpioa
+#define AO_BOOT_APPLICATION_PIN 4
+#define AO_BOOT_APPLICATION_VALUE 1
+#define AO_BOOT_APPLICATION_MODE AO_EXTI_MODE_PULL_UP
+
+#endif /* _AO_PINS_H_ */
# Otherwise, print the full command line.
quiet ?= $($1)
-all: ../$(PROG)
+all: $(PROG)
-../$(PROG): $(REL) Makefile
- $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) ..
+$(PROG): $(REL) Makefile
+ $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL)
$(call quiet,CHECK_STACK) ../cc1111/ao_arch.h $(PMEM) || rm $@
ao_product.h: ao-make-product.5c ../Version
DRIVER_SRC = \
ao_m25.c \
ao_lcd.c \
- ao_gps_skytraq.c
+ ao_gps_skytraq.c \
+ ao_gps_show.c
PRODUCT_SRC = \
ao_teleterra_0_2.c \
# Otherwise, print the full command line.
quiet ?= $($1)
-all: ../$(PROG)
+all: $(PROG)
-../$(PROG): $(REL) Makefile
- $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) ..
+$(PROG): $(REL) Makefile
+ $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL)
$(call quiet,CHECK_STACK) ../cc1111/ao_arch.h $(PMEM) || rm $@
ao_product.h: ao-make-product.5c ../Version
ao_flight_test_accel
ao_gps_test
ao_gps_test_skytraq
+ao_gps_test_ublox
+ao_int64_test
+ao_ms5607_convert_test
+ao_quaternion_test
ao_convert_test
ao_convert_pa_test
ao_fat_test
-vpath % ..:../core:../drivers:../util:../micropeak:../aes
+vpath % ..:../core:../drivers:../util:../micropeak:../aes:../product
PROGS=ao_flight_test ao_flight_test_baro ao_flight_test_accel ao_flight_test_noisy_accel ao_flight_test_mm \
ao_gps_test ao_gps_test_skytraq ao_gps_test_ublox ao_convert_test ao_convert_pa_test ao_fec_test \
- ao_aprs_test ao_micropeak_test ao_fat_test ao_aes_test
+ ao_aprs_test ao_micropeak_test ao_fat_test ao_aes_test ao_int64_test \
+ ao_ms5607_convert_test ao_quaternion_test
-INCS=ao_kalman.h ao_ms5607.h ao_log.h ao_data.h altitude-pa.h altitude.h
+INCS=ao_kalman.h ao_ms5607.h ao_log.h ao_data.h altitude-pa.h altitude.h ao_quaternion.h
KALMAN=make-kalman
-CFLAGS=-I.. -I. -I../core -I../drivers -I../micropeak -O0 -g -Wall
+CFLAGS=-I.. -I. -I../core -I../drivers -I../micropeak -I../product -O0 -g -Wall
all: $(PROGS) ao_aprs_data.wav
ao_flight_test_accel: ao_flight_test.c ao_host.h ao_flight.c ao_sample.c ao_kalman.c $(INCS)
cc $(CFLAGS) -o $@ -DFORCE_ACCEL=1 ao_flight_test.c
-ao_flight_test_mm: ao_flight_test.c ao_host.h ao_flight.c ao_sample.c ao_kalman.c $(INCS)
+ao_flight_test_mm: ao_flight_test.c ao_host.h ao_flight.c ao_sample.c ao_kalman.c ao_pyro.c ao_pyro.h $(INCS)
cc -DTELEMEGA=1 $(CFLAGS) -o $@ $< -lm
ao_gps_test: ao_gps_test.c ao_gps_sirf.c ao_gps_print.c ao_host.h
cc $(CFLAGS) -o $@ $<
-ao_gps_test_skytraq: ao_gps_test_skytraq.c ao_gps_skytraq.c ao_gps_print.c ao_host.h
+ao_gps_test_skytraq: ao_gps_test_skytraq.c ao_gps_skytraq.c ao_gps_print.c ao_gps_show.c ao_host.h
cc $(CFLAGS) -o $@ $<
-ao_gps_test_ublox: ao_gps_test_ublox.c ao_gps_ublox.c ao_gps_print.c ao_host.h ao_gps_ublox.h
+ao_gps_test_ublox: ao_gps_test_ublox.c ao_gps_ublox.c ao_gps_print.c ao_gps_show.c ao_host.h ao_gps_ublox.h
cc $(CFLAGS) -o $@ $<
ao_convert_test: ao_convert_test.c ao_convert.c altitude.h
ao_aes_test: ao_aes_test.c ao_aes.c ao_aes_tables.c
cc $(CFLAGS) -o $@ ao_aes_test.c
+
+ao_int64_test: ao_int64_test.c ao_int64.c ao_int64.h
+ cc $(CFLAGS) -o $@ ao_int64_test.c
+
+ao_ms5607_convert_test: ao_ms5607_convert_test.c ao_ms5607_convert_8051.c ao_int64.c ao_int64.h
+ cc $(CFLAGS) -o $@ ao_ms5607_convert_test.c
+
+ao_quaternion_test: ao_quaternion_test.c ao_quaternion.h
+ cc $(CFLAGS) -o $@ ao_quaternion_test.c -lm
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
+#include <stddef.h>
#include <string.h>
#include <getopt.h>
#include <math.h>
+#define GRAVITY 9.80665
+
#define AO_HERTZ 100
#define HAS_ADC 1
#define AO_MS_TO_SPEED(ms) ((int16_t) ((ms) * 16))
#define AO_MSS_TO_ACCEL(mss) ((int16_t) ((mss) * 16))
+#define AO_GPS_NEW_DATA 1
+#define AO_GPS_NEW_TRACKING 2
+
+int ao_gps_new;
+
#if TELEMEGA
#define AO_ADC_NUM_SENSE 6
#define HAS_MS5607 1
#define HAS_MPU6000 1
#define HAS_MMA655X 1
+#define HAS_HMC5883 1
struct ao_adc {
int16_t sense[AO_ADC_NUM_SENSE];
#include <ao_data.h>
#include <ao_log.h>
+#include <ao_telemetry.h>
+
+#if TELEMEGA
+int ao_gps_count;
+struct ao_telemetry_location ao_gps_first;
+struct ao_telemetry_location ao_gps_prev;
+struct ao_telemetry_location ao_gps_static;
+
+struct ao_telemetry_satellite ao_gps_tracking;
+
+static inline double sqr(double a) { return a * a; }
+
+void
+cc_great_circle (double start_lat, double start_lon,
+ double end_lat, double end_lon,
+ double *dist, double *bearing)
+{
+ const double rad = M_PI / 180;
+ const double earth_radius = 6371.2 * 1000; /* in meters */
+ double lat1 = rad * start_lat;
+ double lon1 = rad * -start_lon;
+ double lat2 = rad * end_lat;
+ double lon2 = rad * -end_lon;
+
+// double d_lat = lat2 - lat1;
+ double d_lon = lon2 - lon1;
+
+ /* From http://en.wikipedia.org/wiki/Great-circle_distance */
+ double vdn = sqrt(sqr(cos(lat2) * sin(d_lon)) +
+ sqr(cos(lat1) * sin(lat2) -
+ sin(lat1) * cos(lat2) * cos(d_lon)));
+ double vdd = sin(lat1) * sin(lat2) + cos(lat1) * cos(lat2) * cos(d_lon);
+ double d = atan2(vdn,vdd);
+ double course;
+
+ if (cos(lat1) < 1e-20) {
+ if (lat1 > 0)
+ course = M_PI;
+ else
+ course = -M_PI;
+ } else {
+ if (d < 1e-10)
+ course = 0;
+ else
+ course = acos((sin(lat2)-sin(lat1)*cos(d)) /
+ (sin(d)*cos(lat1)));
+ if (sin(lon2-lon1) > 0)
+ course = 2 * M_PI-course;
+ }
+ *dist = d * earth_radius;
+ *bearing = course * 180/M_PI;
+}
+
+double
+ao_distance_from_pad(void)
+{
+ double dist, bearing;
+ if (!ao_gps_count)
+ return 0;
+
+ cc_great_circle(ao_gps_first.latitude / 1e7,
+ ao_gps_first.longitude / 1e7,
+ ao_gps_static.latitude / 1e7,
+ ao_gps_static.longitude / 1e7,
+ &dist, &bearing);
+ return dist;
+}
+
+double
+ao_gps_angle(void)
+{
+ double dist, bearing;
+ double height;
+ double angle;
+
+ if (ao_gps_count < 2)
+ return 0;
+
+ cc_great_circle(ao_gps_prev.latitude / 1e7,
+ ao_gps_prev.longitude / 1e7,
+ ao_gps_static.latitude / 1e7,
+ ao_gps_static.longitude / 1e7,
+ &dist, &bearing);
+ height = ao_gps_static.altitude - ao_gps_prev.altitude;
+
+ angle = atan2(dist, height);
+ return angle * 180/M_PI;
+}
+#endif
#define to_fix16(x) ((int16_t) ((x) * 65536.0 + 0.5))
#define to_fix32(x) ((int32_t) ((x) * 65536.0 + 0.5))
#define ao_rdf_set(rdf)
#define ao_packet_slave_start()
#define ao_packet_slave_stop()
+#define flush()
enum ao_igniter {
ao_igniter_drogue = 0,
static int32_t ao_k_height;
+int16_t
+ao_time(void)
+{
+ return ao_data_static.tick;
+}
+
+void
+ao_delay(int16_t interval)
+{
+ return;
+}
+
void
ao_ignite(enum ao_igniter igniter)
{
#include <ao_ms5607.h>
struct ao_ms5607_prom ms5607_prom;
#include "ao_ms5607_convert.c"
+#define AO_PYRO_NUM 4
+#include <ao_pyro.h>
#else
#include "ao_convert.c"
#endif
int16_t accel_minus_g;
uint8_t pad_orientation;
uint16_t apogee_lockout;
+#if TELEMEGA
+ struct ao_pyro pyro[AO_PYRO_NUM]; /* minor version 12 */
+ int16_t accel_zero_along;
+ int16_t accel_zero_across;
+ int16_t accel_zero_through;
+#endif
};
#define AO_PAD_ORIENTATION_ANTENNA_UP 0
#define DATA_TO_XDATA(x) (x)
-#define GRAVITY 9.80665
extern int16_t ao_ground_accel, ao_flight_accel;
extern int16_t ao_accel_2g;
#include "ao_sqrt.c"
#include "ao_sample.c"
#include "ao_flight.c"
+#if TELEMEGA
+#define AO_PYRO_NUM 4
+
+#define AO_PYRO_0 0
+#define AO_PYRO_1 1
+#define AO_PYRO_2 2
+#define AO_PYRO_3 3
+
+static void
+ao_pyro_pin_set(uint8_t pin, uint8_t value)
+{
+ printf ("set pyro %d %d\n", pin, value);
+}
+
+#include "ao_pyro.c"
+#endif
#define to_double(f) ((f) / 65536.0)
exit(0);
}
-#if HAS_MPU6000
-static double
-ao_mpu6000_accel(int16_t sensor)
-{
- return sensor / 32767.0 * MPU6000_ACCEL_FULLSCALE * GRAVITY;
-}
+#ifdef TELEMEGA
+struct ao_azel {
+ int az;
+ int el;
+};
-static double
-ao_mpu6000_gyro(int32_t sensor)
+static void
+azel (struct ao_azel *r, struct ao_quaternion *q)
{
- return sensor / 32767.0 * MPU6000_GYRO_FULLSCALE;
+ double v;
+
+ r->az = floor (atan2(q->y, q->x) * 180/M_PI + 0.5);
+ v = sqrt (q->x*q->x + q->y*q->y);
+ r->el = floor (atan2(q->z, v) * 180/M_PI + 0.5);
}
#endif
double height = ao_pres_to_altitude(ao_data_static.adc.pres_real) - ao_ground_height;
#endif
+ (void) accel;
if (!tick_offset)
tick_offset = -ao_data_static.tick;
if ((prev_tick - ao_data_static.tick) > 0x400)
}
if (!ao_summary) {
+#if TELEMEGA
+ static struct ao_quaternion ao_ground_mag;
+ static int ao_ground_mag_set;
+
+ if (!ao_ground_mag_set) {
+ ao_quaternion_init_vector (&ao_ground_mag,
+ ao_data_mag_across(&ao_data_static),
+ ao_data_mag_through(&ao_data_static),
+ ao_data_mag_along(&ao_data_static));
+ ao_quaternion_normalize(&ao_ground_mag, &ao_ground_mag);
+ ao_quaternion_rotate(&ao_ground_mag, &ao_ground_mag, &ao_rotation);
+ ao_ground_mag_set = 1;
+ }
+
+ struct ao_quaternion ao_mag, ao_mag_rot;
+
+ ao_quaternion_init_vector(&ao_mag,
+ ao_data_mag_across(&ao_data_static),
+ ao_data_mag_through(&ao_data_static),
+ ao_data_mag_along(&ao_data_static));
+
+ ao_quaternion_normalize(&ao_mag, &ao_mag);
+ ao_quaternion_rotate(&ao_mag_rot, &ao_mag, &ao_rotation);
+
+ float ao_dot;
+ int ao_mag_angle;
+
+ ao_dot = ao_quaternion_dot(&ao_mag_rot, &ao_ground_mag);
+
+ struct ao_azel ground_azel, mag_azel, rot_azel;
+
+ azel(&ground_azel, &ao_ground_mag);
+ azel(&mag_azel, &ao_mag);
+ azel(&rot_azel, &ao_mag_rot);
+
+ ao_mag_angle = floor (acos(ao_dot) * 180 / M_PI + 0.5);
+
+ (void) ao_mag_angle;
+
+ static struct ao_quaternion ao_x = { .r = 0, .x = 1, .y = 0, .z = 0 };
+ struct ao_quaternion ao_out;
+
+ ao_quaternion_rotate(&ao_out, &ao_x, &ao_rotation);
+
+ int out = floor (atan2(ao_out.y, ao_out.x) * 180 / M_PI);
+
+#if 0
+ printf ("%7.2f state %-8.8s height %8.4f tilt %4d rot %4d mag_tilt %4d mag_rot %4d\n",
+ time,
+ ao_state_names[ao_flight_state],
+ ao_k_height / 65536.0,
+ ao_sample_orient, out,
+ mag_azel.el,
+ mag_azel.az);
+#endif
+ printf ("%7.2f state %-8.8s height %8.4f tilt %4d rot %4d dist %12.2f gps_tilt %4d gps_sats %2d\n",
+ time,
+ ao_state_names[ao_flight_state],
+ ao_k_height / 65536.0,
+ ao_sample_orient, out,
+ ao_distance_from_pad(),
+ (int) floor (ao_gps_angle() + 0.5),
+ (ao_gps_static.flags & 0xf) * 10);
+
+#if 0
+ printf ("\t\tstate %-8.8s ground az: %4d el %4d mag az %4d el %4d rot az %4d el %4d el_diff %4d az_diff %4d angle %4d tilt %4d ground %8.5f %8.5f %8.5f cur %8.5f %8.5f %8.5f rot %8.5f %8.5f %8.5f\n",
+ ao_state_names[ao_flight_state],
+ ground_azel.az, ground_azel.el,
+ mag_azel.az, mag_azel.el,
+ rot_azel.az, rot_azel.el,
+ ground_azel.el - rot_azel.el,
+ ground_azel.az - rot_azel.az,
+ ao_mag_angle,
+ ao_sample_orient,
+ ao_ground_mag.x,
+ ao_ground_mag.y,
+ ao_ground_mag.z,
+ ao_mag.x,
+ ao_mag.y,
+ ao_mag.z,
+ ao_mag_rot.x,
+ ao_mag_rot.y,
+ ao_mag_rot.z);
+#endif
+#endif
+
+#if 0
printf("%7.2f height %8.2f accel %8.3f "
#if TELEMEGA
- "roll %8.3f angle %8.3f qangle %8.3f "
- "accel_x %8.3f accel_y %8.3f accel_z %8.3f gyro_x %8.3f gyro_y %8.3f gyro_z %8.3f "
+ "angle %5d "
+ "accel_x %8.3f accel_y %8.3f accel_z %8.3f gyro_x %8.3f gyro_y %8.3f gyro_z %8.3f mag_x %8d mag_y %8d, mag_z %8d mag_angle %4d "
#endif
"state %-8.8s k_height %8.2f k_speed %8.3f k_accel %8.3f avg_height %5d drogue %4d main %4d error %5d\n",
time,
height,
accel,
#if TELEMEGA
- ao_mpu6000_gyro(ao_sample_roll_angle) / 100.0,
- ao_mpu6000_gyro(ao_sample_angle) / 100.0,
- ao_sample_qangle,
+ ao_sample_orient,
+
ao_mpu6000_accel(ao_data_static.mpu6000.accel_x),
ao_mpu6000_accel(ao_data_static.mpu6000.accel_y),
ao_mpu6000_accel(ao_data_static.mpu6000.accel_z),
ao_mpu6000_gyro(ao_data_static.mpu6000.gyro_x - ao_ground_mpu6000.gyro_x),
ao_mpu6000_gyro(ao_data_static.mpu6000.gyro_y - ao_ground_mpu6000.gyro_y),
ao_mpu6000_gyro(ao_data_static.mpu6000.gyro_z - ao_ground_mpu6000.gyro_z),
+ ao_data_static.hmc5883.x,
+ ao_data_static.hmc5883.y,
+ ao_data_static.hmc5883.z,
+ ao_mag_angle,
#endif
ao_state_names[ao_flight_state],
ao_k_height / 65536.0,
drogue_height,
main_height,
ao_error_h_sq_avg);
+#endif
// if (ao_flight_state == ao_flight_landed)
// ao_test_exit();
}
}
-#define AO_MAX_CALLSIGN 8
-#define AO_MAX_VERSION 8
-#define AO_MAX_TELEMETRY 128
-
-struct ao_telemetry_generic {
- uint16_t serial; /* 0 */
- uint16_t tick; /* 2 */
- uint8_t type; /* 4 */
- uint8_t payload[27]; /* 5 */
- /* 32 */
-};
-
-#define AO_TELEMETRY_SENSOR_TELEMETRUM 0x01
-#define AO_TELEMETRY_SENSOR_TELEMINI 0x02
-#define AO_TELEMETRY_SENSOR_TELENANO 0x03
-
-struct ao_telemetry_sensor {
- uint16_t serial; /* 0 */
- uint16_t tick; /* 2 */
- uint8_t type; /* 4 */
-
- uint8_t state; /* 5 flight state */
- int16_t accel; /* 6 accelerometer (TM only) */
- int16_t pres; /* 8 pressure sensor */
- int16_t temp; /* 10 temperature sensor */
- int16_t v_batt; /* 12 battery voltage */
- int16_t sense_d; /* 14 drogue continuity sense (TM/Tm) */
- int16_t sense_m; /* 16 main continuity sense (TM/Tm) */
-
- int16_t acceleration; /* 18 m/s² * 16 */
- int16_t speed; /* 20 m/s * 16 */
- int16_t height; /* 22 m */
-
- int16_t ground_pres; /* 24 average pres on pad */
- int16_t ground_accel; /* 26 average accel on pad */
- int16_t accel_plus_g; /* 28 accel calibration at +1g */
- int16_t accel_minus_g; /* 30 accel calibration at -1g */
- /* 32 */
-};
-
-#define AO_TELEMETRY_CONFIGURATION 0x04
-
-struct ao_telemetry_configuration {
- uint16_t serial; /* 0 */
- uint16_t tick; /* 2 */
- uint8_t type; /* 4 */
-
- uint8_t device; /* 5 device type */
- uint16_t flight; /* 6 flight number */
- uint8_t config_major; /* 8 Config major version */
- uint8_t config_minor; /* 9 Config minor version */
- uint16_t apogee_delay; /* 10 Apogee deploy delay in seconds */
- uint16_t main_deploy; /* 12 Main deploy alt in meters */
- uint16_t flight_log_max; /* 14 Maximum flight log size in kB */
- char callsign[AO_MAX_CALLSIGN]; /* 16 Radio operator identity */
- char version[AO_MAX_VERSION]; /* 24 Software version */
- /* 32 */
-};
-
-#define AO_TELEMETRY_LOCATION 0x05
-
-#define AO_GPS_MODE_NOT_VALID 'N'
-#define AO_GPS_MODE_AUTONOMOUS 'A'
-#define AO_GPS_MODE_DIFFERENTIAL 'D'
-#define AO_GPS_MODE_ESTIMATED 'E'
-#define AO_GPS_MODE_MANUAL 'M'
-#define AO_GPS_MODE_SIMULATED 'S'
-
-struct ao_telemetry_location {
- uint16_t serial; /* 0 */
- uint16_t tick; /* 2 */
- uint8_t type; /* 4 */
-
- uint8_t flags; /* 5 Number of sats and other flags */
- int16_t altitude; /* 6 GPS reported altitude (m) */
- int32_t latitude; /* 8 latitude (degrees * 10⁷) */
- int32_t longitude; /* 12 longitude (degrees * 10⁷) */
- uint8_t year; /* 16 (- 2000) */
- uint8_t month; /* 17 (1-12) */
- uint8_t day; /* 18 (1-31) */
- uint8_t hour; /* 19 (0-23) */
- uint8_t minute; /* 20 (0-59) */
- uint8_t second; /* 21 (0-59) */
- uint8_t pdop; /* 22 (m * 5) */
- uint8_t hdop; /* 23 (m * 5) */
- uint8_t vdop; /* 24 (m * 5) */
- uint8_t mode; /* 25 */
- uint16_t ground_speed; /* 26 cm/s */
- int16_t climb_rate; /* 28 cm/s */
- uint8_t course; /* 30 degrees / 2 */
- uint8_t unused[1]; /* 31 */
- /* 32 */
-};
-
-#define AO_TELEMETRY_SATELLITE 0x06
-
-struct ao_telemetry_satellite_info {
- uint8_t svid;
- uint8_t c_n_1;
-};
-
-struct ao_telemetry_satellite {
- uint16_t serial; /* 0 */
- uint16_t tick; /* 2 */
- uint8_t type; /* 4 */
- uint8_t channels; /* 5 number of reported sats */
-
- struct ao_telemetry_satellite_info sats[12]; /* 6 */
- uint8_t unused[2]; /* 30 */
- /* 32 */
-};
-
-union ao_telemetry_all {
- struct ao_telemetry_generic generic;
- struct ao_telemetry_sensor sensor;
- struct ao_telemetry_configuration configuration;
- struct ao_telemetry_location location;
- struct ao_telemetry_satellite satellite;
-};
uint16_t
uint16(uint8_t *bytes, int off)
static int log_format;
-#if TELEMEGA
-
-static double
-ao_vec_norm(double x, double y, double z)
-{
- return x*x + y*y + z*z;
-}
-
-static void
-ao_vec_normalize(double *x, double *y, double *z)
-{
- double scale = 1/sqrt(ao_vec_norm(*x, *y, *z));
-
- *x *= scale;
- *y *= scale;
- *z *= scale;
-}
-
-struct ao_quat {
- double q0, q1, q2, q3;
-};
-
-static void
-ao_quat_mul(struct ao_quat *r, struct ao_quat *a, struct ao_quat *b)
-{
- r->q0 = a->q0 * b->q0 - a->q1 * b->q1 - a->q2 * b->q2 - a->q3 * b->q3;
- r->q1 = a->q0 * b->q1 + a->q1 * b->q0 + a->q2 * b->q3 - a->q3 * b->q2;
- r->q2 = a->q0 * b->q2 - a->q1 * b->q3 + a->q2 * b->q0 + a->q3 * b->q1;
- r->q3 = a->q0 * b->q3 + a->q1 * b->q2 - a->q2 * b->q1 + a->q3 * b->q0;
-}
-
-#if 0
-static void
-ao_quat_scale(struct ao_quat *r, struct ao_quat *a, double s)
-{
- r->q0 = a->q0 * s;
- r->q1 = a->q1 * s;
- r->q2 = a->q2 * s;
- r->q3 = a->q3 * s;
-}
-#endif
-
-static void
-ao_quat_conj(struct ao_quat *r, struct ao_quat *a)
-{
- r->q0 = a->q0;
- r->q1 = -a->q1;
- r->q2 = -a->q2;
- r->q3 = -a->q3;
-}
-
-static void
-ao_quat_rot(struct ao_quat *r, struct ao_quat *a, struct ao_quat *q)
-{
- struct ao_quat t;
- struct ao_quat c;
- ao_quat_mul(&t, q, a);
- ao_quat_conj(&c, q);
- ao_quat_mul(r, &t, &c);
-}
-
-static void
-ao_quat_from_angle(struct ao_quat *r,
- double x_rad,
- double y_rad,
- double z_rad)
-{
- double angle = sqrt (x_rad * x_rad + y_rad * y_rad + z_rad * z_rad);
- double s = sin(angle/2);
- double c = cos(angle/2);
-
- r->q0 = c;
- r->q1 = x_rad * s / angle;
- r->q2 = y_rad * s / angle;
- r->q3 = z_rad * s / angle;
-}
-
-static void
-ao_quat_from_vector(struct ao_quat *r, double x, double y, double z)
-{
- ao_vec_normalize(&x, &y, &z);
- double x_rad = atan2(z, y);
- double y_rad = atan2(x, z);
- double z_rad = atan2(y, x);
-
- ao_quat_from_angle(r, x_rad, y_rad, z_rad);
-}
-
-static double
-ao_quat_norm(struct ao_quat *a)
-{
- return (a->q0 * a->q0 +
- a->q1 * a->q1 +
- a->q2 * a->q2 +
- a->q3 * a->q3);
-}
-
-static void
-ao_quat_normalize(struct ao_quat *a)
-{
- double norm = ao_quat_norm(a);
-
- if (norm) {
- double m = 1/sqrt(norm);
-
- a->q0 *= m;
- a->q1 *= m;
- a->q2 *= m;
- a->q3 *= m;
- }
-}
-
-static struct ao_quat ao_up, ao_current;
-static struct ao_quat ao_orient;
-static int ao_orient_tick;
-
-void
-set_orientation(double x, double y, double z, int tick)
-{
- struct ao_quat t;
-
- printf ("set_orientation %g %g %g\n", x, y, z);
- ao_quat_from_vector(&ao_orient, x, y, z);
- ao_up.q1 = ao_up.q2 = 0;
- ao_up.q0 = ao_up.q3 = sqrt(2)/2;
- ao_orient_tick = tick;
-
- ao_orient.q0 = 1;
- ao_orient.q1 = 0;
- ao_orient.q2 = 0;
- ao_orient.q3 = 0;
-
- printf ("orient (%g) %g %g %g up (%g) %g %g %g\n",
- ao_orient.q0,
- ao_orient.q1,
- ao_orient.q2,
- ao_orient.q3,
- ao_up.q0,
- ao_up.q1,
- ao_up.q2,
- ao_up.q3);
-
- ao_quat_rot(&t, &ao_up, &ao_orient);
- printf ("pad orient (%g) %g %g %g\n",
- t.q0,
- t.q1,
- t.q2,
- t.q3);
-
-}
-
-void
-update_orientation (double rate_x, double rate_y, double rate_z, int tick)
-{
- struct ao_quat q_dot;
- double lambda;
- double dt = (tick - ao_orient_tick) / 100.0;
-
- ao_orient_tick = tick;
-
-// lambda = 1 - ao_quat_norm(&ao_orient);
- lambda = 0;
-
- q_dot.q0 = -0.5 * (ao_orient.q1 * rate_x + ao_orient.q2 * rate_y + ao_orient.q3 * rate_z) + lambda * ao_orient.q0;
- q_dot.q1 = 0.5 * (ao_orient.q0 * rate_x + ao_orient.q2 * rate_z - ao_orient.q3 * rate_y) + lambda * ao_orient.q1;
- q_dot.q2 = 0.5 * (ao_orient.q0 * rate_y + ao_orient.q3 * rate_x - ao_orient.q1 * rate_z) + lambda * ao_orient.q2;
- q_dot.q3 = 0.5 * (ao_orient.q0 * rate_z + ao_orient.q1 * rate_y - ao_orient.q2 * rate_x) + lambda * ao_orient.q3;
-
-#if 0
- printf ("update_orientation %g %g %g (%g s)\n", rate_x, rate_y, rate_z, dt);
- printf ("q_dot (%g) %g %g %g\n",
- q_dot.q0,
- q_dot.q1,
- q_dot.q2,
- q_dot.q3);
-#endif
-
- ao_orient.q0 += q_dot.q0 * dt;
- ao_orient.q1 += q_dot.q1 * dt;
- ao_orient.q2 += q_dot.q2 * dt;
- ao_orient.q3 += q_dot.q3 * dt;
-
- ao_quat_normalize(&ao_orient);
-
- ao_quat_rot(&ao_current, &ao_up, &ao_orient);
-
- ao_sample_qangle = 180 / M_PI * acos(ao_current.q3 * sqrt(2));
-#if 0
- printf ("orient (%g) %g %g %g current (%g) %g %g %g\n",
- ao_orient.q0,
- ao_orient.q1,
- ao_orient.q2,
- ao_orient.q3,
- ao_current.q0,
- ao_current.q1,
- ao_current.q2,
- ao_current.q3);
-#endif
-}
-#endif
-
void
ao_sleep(void *wchan)
{
char *words[64];
int nword;
+#if TELEMEGA
+ if (ao_flight_state >= ao_flight_boost && ao_flight_state < ao_flight_landed)
+ ao_pyro_check();
+#endif
for (;;) {
if (ao_records_read > 2 && ao_flight_state == ao_flight_startup)
{
ao_data_static.ms5607_raw.temp = int32(bytes, 4);
ao_ms5607_convert(&ao_data_static.ms5607_raw, &value);
ao_data_static.mpu6000.accel_x = int16(bytes, 8);
- ao_data_static.mpu6000.accel_y = -int16(bytes, 10);
+ ao_data_static.mpu6000.accel_y = int16(bytes, 10);
ao_data_static.mpu6000.accel_z = int16(bytes, 12);
ao_data_static.mpu6000.gyro_x = int16(bytes, 14);
- ao_data_static.mpu6000.gyro_y = -int16(bytes, 16);
+ ao_data_static.mpu6000.gyro_y = int16(bytes, 16);
ao_data_static.mpu6000.gyro_z = int16(bytes, 18);
+ ao_data_static.hmc5883.x = int16(bytes, 20);
+ ao_data_static.hmc5883.y = int16(bytes, 22);
+ ao_data_static.hmc5883.z = int16(bytes, 24);
#if HAS_MMA655X
ao_data_static.mma655x = int16(bytes, 26);
#endif
- if (ao_records_read == 0)
- ao_ground_mpu6000 = ao_data_static.mpu6000;
- else if (ao_records_read < 10) {
-#define f(f) ao_ground_mpu6000.f = ao_ground_mpu6000.f + ((ao_data_static.mpu6000.f - ao_ground_mpu6000.f) >> 2)
- f(accel_x);
- f(accel_y);
- f(accel_z);
- f(gyro_x);
- f(gyro_y);
- f(gyro_z);
-
- double accel_x = ao_mpu6000_accel(ao_ground_mpu6000.accel_x);
- double accel_y = ao_mpu6000_accel(ao_ground_mpu6000.accel_y);
- double accel_z = ao_mpu6000_accel(ao_ground_mpu6000.accel_z);
-
- /* X and Y are in the ground plane, arbitraryily picked as MPU X and Z axes
- * Z is normal to the ground, the MPU y axis
- */
- set_orientation(accel_x, accel_z, accel_y, tick);
- } else {
- double rate_x = ao_mpu6000_gyro(ao_data_static.mpu6000.gyro_x - ao_ground_mpu6000.gyro_x);
- double rate_y = ao_mpu6000_gyro(ao_data_static.mpu6000.gyro_y - ao_ground_mpu6000.gyro_y);
- double rate_z = ao_mpu6000_gyro(ao_data_static.mpu6000.gyro_z - ao_ground_mpu6000.gyro_z);
-
- update_orientation(rate_x * M_PI / 180, rate_z * M_PI / 180, rate_y * M_PI / 180, tick);
- }
ao_records_read++;
ao_insert();
return;
+ case 'G':
+ ao_gps_prev = ao_gps_static;
+ ao_gps_static.tick = tick;
+ ao_gps_static.latitude = int32(bytes, 0);
+ ao_gps_static.longitude = int32(bytes, 4);
+ ao_gps_static.altitude = int32(bytes, 8);
+ ao_gps_static.flags = bytes[13];
+ if (!ao_gps_count)
+ ao_gps_first = ao_gps_static;
+ ao_gps_count++;
+ break;
}
continue;
} else if (nword == 3 && strcmp(words[0], "ms5607") == 0) {
else if (strcmp(words[1], "crc:") == 0)
ms5607_prom.crc = strtoul(words[2], NULL, 10);
continue;
+ } else if (nword >= 3 && strcmp(words[0], "Pyro") == 0) {
+ int p = strtoul(words[1], NULL, 10);
+ int i, j;
+ struct ao_pyro *pyro = &ao_config.pyro[p];
+
+ for (i = 2; i < nword; i++) {
+ for (j = 0; j < NUM_PYRO_VALUES; j++)
+ if (!strcmp (words[2], ao_pyro_values[j].name))
+ break;
+ if (j == NUM_PYRO_VALUES)
+ continue;
+ pyro->flags |= ao_pyro_values[j].flag;
+ if (ao_pyro_values[j].offset != NO_VALUE && i + 1 < nword) {
+ int16_t val = strtoul(words[++i], NULL, 10);
+ *((int16_t *) ((char *) pyro + ao_pyro_values[j].offset)) = val;
+ }
+ }
}
#else
if (nword == 4 && log_format != AO_LOG_FORMAT_TELEMEGA) {
} else if (nword >= 6 && strcmp(words[0], "Accel") == 0) {
ao_config.accel_plus_g = atoi(words[3]);
ao_config.accel_minus_g = atoi(words[5]);
+#ifdef TELEMEGA
+ } else if (nword >= 8 && strcmp(words[0], "IMU") == 0) {
+ ao_config.accel_zero_along = atoi(words[3]);
+ ao_config.accel_zero_across = atoi(words[5]);
+ ao_config.accel_zero_through = atoi(words[7]);
+ printf ("%d %d %d\n", ao_config.accel_zero_along, ao_config.accel_zero_across, ao_config.accel_zero_through);
+#endif
} else if (nword >= 4 && strcmp(words[0], "Main") == 0) {
ao_config.main_deploy = atoi(words[2]);
} else if (nword >= 3 && strcmp(words[0], "Apogee") == 0 &&
#define AO_GPS_NUM_SAT_MASK (0xf << 0)
#define AO_GPS_NUM_SAT_SHIFT (0)
+#define AO_GPS_NEW_DATA 1
+#define AO_GPS_NEW_TRACKING 2
+
#define AO_GPS_VALID (1 << 4)
#define AO_GPS_RUNNING (1 << 5)
#define AO_GPS_DATE_VALID (1 << 6)
ao_dump_state(void *wchan)
{
int i;
- if (wchan == &ao_gps_data)
+
+ if (wchan != &ao_gps_new)
+ return;
+
+ if (ao_gps_new & AO_GPS_NEW_DATA) {
ao_gps_print(&ao_gps_data);
- else
+ putchar('\n');
+ }
+ if (ao_gps_new & AO_GPS_NEW_TRACKING) {
ao_gps_tracking_print(&ao_gps_tracking_data);
- putchar('\n');
+ putchar('\n');
+ }
return;
printf ("%02d:%02d:%02d",
ao_gps_data.hour, ao_gps_data.minute,
#define AO_GPS_NUM_SAT_MASK (0xf << 0)
#define AO_GPS_NUM_SAT_SHIFT (0)
+#define AO_GPS_NEW_DATA 1
+#define AO_GPS_NEW_TRACKING 2
+
#define AO_GPS_VALID (1 << 4)
#define AO_GPS_RUNNING (1 << 5)
#define AO_GPS_DATE_VALID (1 << 6)
#define ao_telemetry_satellite ao_gps_tracking_orig
#define ao_telemetry_satellite_info ao_gps_sat_orig
+extern __xdata struct ao_telemetry_location ao_gps_data;
+extern __xdata struct ao_telemetry_satellite ao_gps_tracking_data;
+
+uint8_t ao_gps_mutex;
+
void
ao_mutex_get(uint8_t *mutex)
{
#define ao_usb_getchar() 0
#include "ao_gps_print.c"
+#include "ao_gps_show.c"
#include "ao_gps_skytraq.c"
void
ao_dump_state(void *wchan)
{
- if (wchan == &ao_gps_data)
- ao_gps_print(&ao_gps_data);
- else
- ao_gps_tracking_print(&ao_gps_tracking_data);
- putchar('\n');
- return;
+ if (wchan == &ao_gps_new)
+ ao_gps_show();
}
int
#define AO_GPS_NUM_SAT_MASK (0xf << 0)
#define AO_GPS_NUM_SAT_SHIFT (0)
+#define AO_GPS_NEW_DATA 1
+#define AO_GPS_NEW_TRACKING 2
+
#define AO_GPS_VALID (1 << 4)
#define AO_GPS_RUNNING (1 << 5)
#define AO_GPS_DATE_VALID (1 << 6)
#define ao_gps_tracking_orig ao_telemetry_satellite
#define ao_gps_sat_orig ao_telemetry_satellite_info
+extern __xdata struct ao_telemetry_location ao_gps_data;
+extern __xdata struct ao_telemetry_satellite ao_gps_tracking_data;
+
+uint8_t ao_gps_mutex;
+
void
ao_mutex_get(uint8_t *mutex)
{
static void check_ublox_message(char *which, uint8_t *msg);
char
-ao_serial1_getchar(void)
+ao_gps_getchar(void)
{
char c;
uint8_t uc;
static uint16_t send_len;
void
-ao_serial1_putchar(char c)
+ao_gps_putchar(char c)
{
int i;
uint8_t uc = (uint8_t) c;
#define AO_SERIAL_SPEED_115200 3
static void
-ao_serial1_set_speed(uint8_t speed)
+ao_gps_set_speed(uint8_t speed)
{
int fd = ao_gps_fd;
struct termios termios;
#define ao_usb_getchar() 0
#include "ao_gps_print.c"
+#include "ao_gps_show.c"
#include "ao_gps_ublox.c"
static void
void
ao_dump_state(void *wchan)
{
- if (wchan == &ao_gps_data)
- ao_gps_print(&ao_gps_data);
- else
- ao_gps_tracking_print(&ao_gps_tracking_data);
- putchar('\n');
+ if (wchan == &ao_gps_new)
+ ao_gps_show();
return;
}
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#define __data
+#define __pdata
+#define __xdata
+#define __reentrant
+
+#include <ao_int64.h>
+#include <ao_int64.c>
+#include <stdio.h>
+#include <stdlib.h>
+
+int errors;
+
+#define test_o(op,func,mod,a,b,ao_a,ao_b) do { \
+ r = (a) op (b); \
+ func(&ao_r, ao_a, ao_b); \
+ c = ao_cast64(&ao_r); \
+ if (c != r) { \
+ printf ("trial %4d: %lld " #func mod " %lld = %lld (should be %lld)\n", \
+ trial, (int64_t) (a), (int64_t) b, c, r); \
+ ++errors; \
+ } \
+ } while (0)
+
+#define test(op,func,a,b,ao_a,ao_b) test_o(op,func,"",a,b,ao_a,ao_b)
+
+#define test_a(op,func,a,b,ao_a,ao_b) do { \
+ ao_r = *ao_a; \
+ test_o(op,func,"_a",a,b,&ao_r,ao_b); \
+ } while (0)
+
+#define test_b(op,func,a,b,ao_a,ao_b) do { \
+ ao_r = *ao_b; \
+ test_o(op,func,"_b",a,b,ao_a,&ao_r); \
+ } while (0)
+
+#define test_x(op,func,a,b,ao_a,ao_b) do { \
+ ao_r = *ao_a; \
+ test_o(op,func,"_xa",a,a,&ao_r,&ao_r); \
+ ao_r = *ao_b; \
+ test_o(op,func,"_xb",b,b,&ao_r,&ao_r); \
+ } while (0)
+
+void
+do_test(int trial, int64_t a, int64_t b)
+{
+ int64_t r, c;
+ ao_int64_t ao_a, ao_b, ao_r;
+
+ ao_int64_init64(&ao_a, a >> 32, a);
+ ao_int64_init64(&ao_b, b >> 32, b);
+
+ test(+, ao_plus64, a, b, &ao_a, &ao_b);
+ test_a(+, ao_plus64, a, b, &ao_a, &ao_b);
+ test_b(+, ao_plus64, a, b, &ao_a, &ao_b);
+ test_x(+, ao_plus64, a, b, &ao_a, &ao_b);
+ test(-, ao_minus64, a, b, &ao_a, &ao_b);
+ test_a(-, ao_minus64, a, b, &ao_a, &ao_b);
+ test_b(-, ao_minus64, a, b, &ao_a, &ao_b);
+ test_x(-, ao_minus64, a, b, &ao_a, &ao_b);
+ test(*, ao_mul64_32_32,(int64_t) (int32_t) a, (int32_t) b, (int32_t) a, (int32_t) b);
+ test(*, ao_mul64, a, b, &ao_a, &ao_b);
+ test_a(*, ao_mul64, a, b, &ao_a, &ao_b);
+ test_b(*, ao_mul64, a, b, &ao_a, &ao_b);
+ test_x(*, ao_mul64, a, b, &ao_a, &ao_b);
+ test(*, ao_mul64_64_16, a, (uint16_t) b, &ao_a, (uint16_t) b);
+ test_a(*, ao_mul64_64_16, a, (uint16_t) b, &ao_a, (uint16_t) b);
+ test(>>, ao_rshift64, a, (uint8_t) b & 0x3f, &ao_a, (uint8_t) b & 0x3f);
+ test_a(>>, ao_rshift64, a, (uint8_t) b & 0x3f, &ao_a, (uint8_t) b & 0x3f);
+ test(<<, ao_lshift64, a, (uint8_t) b & 0x3f, &ao_a, (uint8_t) b & 0x3f);
+ test_a(<<, ao_lshift64, a, (uint8_t) b & 0x3f, &ao_a, (uint8_t) b & 0x3f);
+}
+
+#define TESTS 10000000
+
+static int64_t
+random64(void)
+{
+ return (int64_t) random() + ((int64_t) random() << 31) /* + ((int64_t) random() << 33) */;
+}
+
+int
+main (int argc, char **argv)
+{
+ int i, start;
+
+ if (argv[1])
+ start = atoi(argv[1]);
+ else
+ start = 0;
+ srandom(1000);
+ for (i = 0; i < TESTS; i++) {
+ int64_t a = random64();
+ int64_t b = random64();
+ if (i >= start)
+ do_test(i, a, b);
+ }
+ return errors;
+}
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#define __xdata
+#define __data
+#define __pdata
+#define __reentrant
+
+#include <stdint.h>
+#include <ao_ms5607.h>
+
+struct ao_ms5607_prom ms5607_prom = {
+ 0x002c,
+ 0xa6e0,
+ 0x988e,
+ 0x6814,
+ 0x5eff,
+ 0x8468,
+ 0x6c86,
+ 0xa271,
+};
+
+int32_t D1_mm = 6179630;
+int32_t D2_mm = 8933155;
+
+#include <ao_ms5607_convert.c>
+#define ao_ms5607_convert ao_ms5607_convert_8051
+#include <ao_ms5607_convert_8051.c>
+#include <ao_int64.c>
+#include <stdio.h>
+#include <stdlib.h>
+
+struct ao_ms5607_sample ao_sample = {
+ 6179630,
+ 8933155
+};
+
+int errors;
+
+void test(int trial, struct ao_ms5607_sample *sample)
+{
+ struct ao_ms5607_value value, value_8051;
+
+ ao_ms5607_convert(sample, &value);
+ ao_ms5607_convert_8051(sample, &value_8051);
+ if (value.temp != value_8051.temp || value.pres != value_8051.pres) {
+ ++errors;
+ printf ("trial %d: %d, %d -> %d, %d (should be %d, %d)\n",
+ trial,
+ sample->pres, sample->temp,
+ value_8051.pres, value_8051.temp,
+ value.pres, value.temp);
+ }
+}
+
+#define TESTS 10000000
+
+#include <stdlib.h>
+
+static int32_t rand24(void) { return random() & 0xffffff; }
+
+int
+main(int argc, char **argv)
+{
+ struct ao_ms5607_sample sample;
+ int i, start;
+
+ if (argv[1])
+ start = atoi(argv[1]);
+ else
+ start = 0;
+
+ srandom(10000);
+ test(-1, &ao_sample);
+ for (i = 0; i < TESTS; i++) {
+ sample.pres = rand24();
+ sample.temp = rand24();
+ if (i >= start)
+ test(i, &sample);
+ }
+ return errors;
+}
--- /dev/null
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#define _GNU_SOURCE
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <getopt.h>
+#include <math.h>
+
+#include "ao_quaternion.h"
+
+#if 0
+static void
+print_q(char *name, struct ao_quaternion *q)
+{
+ printf ("%8.8s: r%8.5f x%8.5f y%8.5f z%8.5f ", name,
+ q->r, q->x, q->y, q->z);
+}
+#endif
+
+#define STEPS 16
+
+#define DEG (1.0f * 3.1415926535f / 180.0f)
+
+struct ao_rotation {
+ int steps;
+ float x, y, z;
+};
+
+static struct ao_rotation ao_path[] = {
+ { .steps = 45, .x = 2*DEG, .y = 0, .z = 0 },
+
+ { .steps = 45, .x = 0, .y = 2*DEG, .z = 0 },
+
+ { .steps = 45, .x = -2*DEG, .y = 0, .z = 0 },
+
+ { .steps = 45, .x = 0, .y = -2*DEG, .z = 0 },
+};
+
+#define NUM_PATH (sizeof ao_path / sizeof ao_path[0])
+
+static int close(float a, float b) {
+ return fabsf (a - b) < 1e-5;
+}
+
+static int check_quaternion(char *where, struct ao_quaternion *got, struct ao_quaternion *expect) {
+ if (!close (got->r, expect->r) ||
+ !close (got->x, expect->x) ||
+ !close (got->y, expect->y) ||
+ !close (got->z, expect->z))
+ {
+ printf ("%s: got r%8.5f x%8.5f y%8.5f z%8.5f expect r%8.5f x%8.5f y%8.5f z%8.5f\n",
+ where,
+ got->r, got->x, got->y, got->z,
+ expect->r, expect->x, expect->y, expect->z);
+ return 1;
+ }
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ struct ao_quaternion position;
+ struct ao_quaternion position_expect;
+ struct ao_quaternion rotation;
+ struct ao_quaternion rotated;
+ struct ao_quaternion little_rotation;
+ int i;
+ int p;
+ int ret = 0;
+
+ /* vector */
+ ao_quaternion_init_vector(&position, 1, 1, 1);
+ ao_quaternion_init_vector(&position_expect, -1, -1, 1);
+
+ /* zero rotation */
+ ao_quaternion_init_zero_rotation(&rotation);
+
+#define dump() do { \
+ \
+ ao_quaternion_rotate(&rotated, &position, &rotation); \
+ print_q("rotated", &rotated); \
+ print_q("rotation", &rotation); \
+ printf ("\n"); \
+ } while (0)
+
+// dump();
+
+ for (p = 0; p < NUM_PATH; p++) {
+ ao_quaternion_init_half_euler(&little_rotation,
+ ao_path[p].x / 2.0f,
+ ao_path[p].y / 2.0f,
+ ao_path[p].z / 2.0f);
+// printf ("\t\tx: %8.4f, y: %8.4f, z: %8.4f ", ao_path[p].x, ao_path[p].y, ao_path[p].z);
+// print_q("step", &little_rotation);
+// printf("\n");
+ for (i = 0; i < ao_path[p].steps; i++) {
+ ao_quaternion_multiply(&rotation, &little_rotation, &rotation);
+
+ ao_quaternion_normalize(&rotation, &rotation);
+
+// dump();
+ }
+ }
+
+ ao_quaternion_rotate(&rotated, &position, &rotation);
+
+ ret += check_quaternion("rotation", &rotated, &position_expect);
+
+ struct ao_quaternion vertical;
+ struct ao_quaternion angle;
+ struct ao_quaternion rot;
+
+ ao_quaternion_init_vector(&vertical, 0, 0, 1);
+ ao_quaternion_init_vector(&angle, 0, 0, 1);
+
+ ao_quaternion_init_half_euler(&rot,
+ M_PI * 3.0 / 8.0 , 0, 0);
+
+ ao_quaternion_rotate(&angle, &angle, &rot);
+
+ struct ao_quaternion rot_compute;
+
+ ao_quaternion_vectors_to_rotation(&rot_compute, &vertical, &angle);
+
+ ret += check_quaternion("vector rotation", &rot_compute, &rot);
+
+ struct ao_quaternion rotd;
+
+ ao_quaternion_rotate(&rotd, &vertical, &rot_compute);
+
+ ret += check_quaternion("vector rotated", &rotd, &angle);
+
+ return ret;
+}
+
--- /dev/null
+2013-10-12-serial-0094-flight-0001.eeprom
+2013-09-02-serial-094-flight-002.eeprom
+2013-03-02-serial-069-flight-002.eeprom
+2013-03-02-serial-069-flight-001.eeprom
+2013-05-27-serial-084-flight-001.mega
+2013-05-26-serial-085-flight-002.mega
+2013-05-19-serial-084-flight-003.mega
+2013-04-21-serial-069-flight-002.mega
+2012-10-20-serial-068-flight-004.mega
+2012-07-03-serial-058-flight-007.mega
+2012-06-30-serial-058-flight-006.mega
+2012-06-30-serial-058-flight-005.mega
--- /dev/null
+#!/bin/sh
+
+case $# in
+1)
+ file="$1"
+ title="$1"
+ ;;
+2)
+ file="$1"
+ title="$2"
+ ;;
+*)
+ echo "Usage: $0 <data-file> <title>"
+ exit 1
+esac
+
+gnuplot -persist << EOF
+set ylabel "altitude (m)"
+set y2label "angle (d)"
+set xlabel "time (s)"
+set xtics border out nomirror
+set ytics border out nomirror
+set y2tics border out nomirror
+set title "$title"
+plot "$file" using 1:5 with lines axes x1y1 title "height",\
+"$file" using 1:9 with lines axes x1y2 title "gyro rot", \
+"$file" using 1:7 with lines axes x1y2 title "gyro tilt", \
+"$file" using 1:13 with lines axes x1y2 title "mag rot", \
+"$file" using 1:11 with lines axes x1y2 title "mag tilt"
+EOF
+#!/bin/sh
+
+case $# in
+1)
+ file="$1"
+ title="$1"
+ ;;
+2)
+ file="$1"
+ title="$2"
+ ;;
+*)
+ echo "Usage: $0 <data-file> <title>"
+ exit 1
+esac
+
gnuplot -persist << EOF
-set ylabel "altitude (m)"
+set ylabel "distance (m)"
set y2label "angle (d)"
set xlabel "time (s)"
set xtics border out nomirror
set ytics border out nomirror
set y2tics border out nomirror
-plot "$1" using 1:3 with lines axes x1y1 title "raw height",\
-"$1" using 1:9 with lines axes x1y2 title "angle",\
-"$1" using 1:11 with lines axes x1y2 title "qangle"
+set title "$title"
+plot "$file" using 1:5 with lines axes x1y1 title "height",\
+"$file" using 1:7 with lines axes x1y2 title "angle",\
+"$file" using 1:13 with lines axes x1y2 title "gps angle",\
+"$file" using 1:15 with lines axes x1y2 title "sats"
EOF
--- /dev/null
+#!/bin/sh
+./run-mm `cat mega.flights`
DIR=~/misc/rockets/flights
for i in "$@"; do
-case "$i" in
- */*)
- file="$i"
- ;;
- *)
- file="$DIR/$i"
- ;;
-esac
-./ao_flight_test_mm "$file" > run-out.mm
+ case "$i" in
+ */*)
+ file="$i"
+ ;;
+ *)
+ file="$DIR/$i"
+ ;;
+ esac
+ base=`basename "$i" .eeprom`
+
+ ./ao_flight_test_mm "$file" > $base.plot
+
+ sh ./plotmm $base.plot `basename "$file"`
+done
#./ao_flight_test_accel "$file" > run-out.accel
#"run-out.accel" using 1:9 with lines lt 4 axes x1y1 title "accel height",\
#"run-out.accel" using 1:17 with lines lt 4 axes x1y1 title "accel main",\
#
-gnuplot << EOF
-set ylabel "altitude (m)"
-set y2label "velocity (m/s), acceleration(m/s²)"
-set xlabel "time (s)"
-set xtics border out nomirror
-set ytics border out nomirror
-set y2tics border out nomirror
-set title "$i"
-plot "run-out.mm" using 1:3 with lines lw 2 lt 1 axes x1y1 title "raw height",\
-"run-out.mm" using 1:5 with lines lw 2 lt 1 axes x1y2 title "raw accel",\
-"run-out.mm" using 1:21 with lines lt 2 axes x1y1 title "mm height",\
-"run-out.mm" using 1:23 with lines lt 2 axes x1y2 title "mm speed",\
-"run-out.mm" using 1:25 with lines lt 2 axes x1y2 title "mm accel",\
-"run-out.mm" using 1:29 with lines lt 2 axes x1y1 title "mm drogue",\
-"run-out.mm" using 1:31 with lines lt 2 axes x1y1 title "mm main"
-pause mouse close
-EOF
-done
\ No newline at end of file
+#gnuplot << EOF
+#set ylabel "altitude (m)"
+#set y2label "velocity (m/s), acceleration(m/s²)"
+#set xlabel "time (s)"
+#set xtics border out nomirror
+#set ytics border out nomirror
+#set y2tics border out nomirror
+#set title "$i"
+#plot "run-out.mm" using 1:3 with lines lw 2 lt 1 axes x1y1 title "raw height",\
+#"run-out.mm" using 1:5 with lines lw 2 lt 1 axes x1y2 title "raw accel",\
+#"run-out.mm" using 1:21 with lines lt 2 axes x1y1 title "mm height",\
+#"run-out.mm" using 1:23 with lines lt 2 axes x1y2 title "mm speed",\
+#"run-out.mm" using 1:25 with lines lt 2 axes x1y2 title "mm accel",\
+#"run-out.mm" using 1:29 with lines lt 2 axes x1y1 title "mm drogue",\
+#"run-out.mm" using 1:31 with lines lt 2 axes x1y1 title "mm main"
+#pause mouse close
+#EOF
+#done
\ No newline at end of file
# Otherwise, print the full command line.
quiet ?= $($1)
-all: ../$(PROG)
+all: $(PROG)
-../$(PROG): $(REL) Makefile
- $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) ..
+$(PROG): $(REL) Makefile
+ $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL)
$(call quiet,CHECK_STACK) ../cc1111/ao_arch.h $(PMEM) || rm $@
ao_product.h: ao-make-product.5c ../Version
%TeleMega% = AltusMetrum.Install, USB\VID_FFFE&PID_0023, AltusMetrumSerial\r
%MegaDongle = AltusMetrum.Install, USB\VID_FFFE&PID_0024, AltusMetrumSerial\r
%TeleGPS% = AltusMetrum.Install, USB\VID_FFFE&PID_0025, AltusMetrumSerial\r
-%AltusMetrum26% = AltusMetrum.Install, USB\VID_FFFE&PID_0026, AltusMetrumSerial\r
-%AltusMetrum27% = AltusMetrum.Install, USB\VID_FFFE&PID_0027, AltusMetrumSerial\r
+%EasyMini% = AltusMetrum.Install, USB\VID_FFFE&PID_0026, AltusMetrumSerial\r
+%TeleMini% = AltusMetrum.Install, USB\VID_FFFE&PID_0027, AltusMetrumSerial\r
%AltusMetrum28% = AltusMetrum.Install, USB\VID_FFFE&PID_0028, AltusMetrumSerial\r
%AltusMetrum29% = AltusMetrum.Install, USB\VID_FFFE&PID_0029, AltusMetrumSerial\r
%AltusMetrum2a% = AltusMetrum.Install, USB\VID_FFFE&PID_002a, AltusMetrumSerial\r
%TeleMega% = AltusMetrum.Install, USB\VID_FFFE&PID_0023, AltusMetrumSerial\r
%MegaDongle = AltusMetrum.Install, USB\VID_FFFE&PID_0024, AltusMetrumSerial\r
%TeleGPS% = AltusMetrum.Install, USB\VID_FFFE&PID_0025, AltusMetrumSerial\r
-%AltusMetrum26% = AltusMetrum.Install, USB\VID_FFFE&PID_0026, AltusMetrumSerial\r
-%AltusMetrum27% = AltusMetrum.Install, USB\VID_FFFE&PID_0027, AltusMetrumSerial\r
+%EasyMini% = AltusMetrum.Install, USB\VID_FFFE&PID_0026, AltusMetrumSerial\r
+%TeleMini% = AltusMetrum.Install, USB\VID_FFFE&PID_0027, AltusMetrumSerial\r
%AltusMetrum28% = AltusMetrum.Install, USB\VID_FFFE&PID_0028, AltusMetrumSerial\r
%AltusMetrum29% = AltusMetrum.Install, USB\VID_FFFE&PID_0029, AltusMetrumSerial\r
%AltusMetrum2a% = AltusMetrum.Install, USB\VID_FFFE&PID_002a, AltusMetrumSerial\r
%TeleMega% = AltusMetrum.Install, USB\VID_FFFE&PID_0023, AltusMetrumSerial\r
%MegaDongle = AltusMetrum.Install, USB\VID_FFFE&PID_0024, AltusMetrumSerial\r
%TeleGPS% = AltusMetrum.Install, USB\VID_FFFE&PID_0025, AltusMetrumSerial\r
-%AltusMetrum26% = AltusMetrum.Install, USB\VID_FFFE&PID_0026, AltusMetrumSerial\r
-%AltusMetrum27% = AltusMetrum.Install, USB\VID_FFFE&PID_0027, AltusMetrumSerial\r
+%EasyMini% = AltusMetrum.Install, USB\VID_FFFE&PID_0026, AltusMetrumSerial\r
+%TeleMini% = AltusMetrum.Install, USB\VID_FFFE&PID_0027, AltusMetrumSerial\r
%AltusMetrum28% = AltusMetrum.Install, USB\VID_FFFE&PID_0028, AltusMetrumSerial\r
%AltusMetrum29% = AltusMetrum.Install, USB\VID_FFFE&PID_0029, AltusMetrumSerial\r
%AltusMetrum2a% = AltusMetrum.Install, USB\VID_FFFE&PID_002a, AltusMetrumSerial\r
%TeleMega% = AltusMetrum.Install, USB\VID_FFFE&PID_0023, AltusMetrumSerial\r
%MegaDongle = AltusMetrum.Install, USB\VID_FFFE&PID_0024, AltusMetrumSerial\r
%TeleGPS% = AltusMetrum.Install, USB\VID_FFFE&PID_0025, AltusMetrumSerial\r
-%AltusMetrum26% = AltusMetrum.Install, USB\VID_FFFE&PID_0026, AltusMetrumSerial\r
-%AltusMetrum27% = AltusMetrum.Install, USB\VID_FFFE&PID_0027, AltusMetrumSerial\r
+%EasyMini% = AltusMetrum.Install, USB\VID_FFFE&PID_0026, AltusMetrumSerial\r
+%TeleMini% = AltusMetrum.Install, USB\VID_FFFE&PID_0027, AltusMetrumSerial\r
%AltusMetrum28% = AltusMetrum.Install, USB\VID_FFFE&PID_0028, AltusMetrumSerial\r
%AltusMetrum29% = AltusMetrum.Install, USB\VID_FFFE&PID_0029, AltusMetrumSerial\r
%AltusMetrum2a% = AltusMetrum.Install, USB\VID_FFFE&PID_002a, AltusMetrumSerial\r
HKR,, Properties, 1, C0,01,00,00, 00,00,00,00, FF,00,00,00, 07,00,00,00, 0F,00,00,00, F7,0F,00,00, 00,84,03,00, C0,DA,00,00\r
\r
[Uninstall.AddReg]\r
-HKLM,Software\Microsoft\Windows\CurrentVersion\Uninstall\%TeleMetrum%,DisplayName,,"%TeleMetrum%"\r
+HKLM,Software\Microsoft\Windows\CurrentVersion\Uninstall\%AltusMetrum%,DisplayName,,"%AltusMetrum%"\r
\r
[Strings]\r
Mfg = "altusmetrum.org"\r
TeleMetrum = "TeleMetrum"\r
TeleDongle = "TeleDongle"\r
TeleTerra = "TeleTerra"\r
+TeleBT = "TeleBT"\r
+TeleLaunch = "TeleLaunch"\r
+TeleLCO = "TeleLCO"\r
+TeleScience = "TeleScience"\r
+TelePyro = "TelePyro"\r
+TeleShield = "TeleShield"\r
+TeleMega = "TeleMega"\r
+MegaDongle = "MegaDongle"\r
+TeleGPS = "TeleGPS"\r
+EasyMini = "EasyMini"\r
+TeleMini = "TeleMini"\r
+AltusMetrum28 = "AltusMetrum28"\r
+AltusMetrum29 = "AltusMetrum29"\r
+AltusMetrum2a = "AltusMetrum2a"\r
+AltusMetrum2b = "AltusMetrum2b"\r
+AltusMetrum2c = "AltusMetrum2c"\r
+\r
DriverName = "Altus Metrum Device Driver"\r
\r