+commit fdf1dbd3d945f6f34f404ffbcb57781f4df23015
+Merge: 5b4da841 bfc4999c
+Author: Bdale Garbee <bdale@gag.com>
+Date: Thu Dec 5 22:21:29 2019 -0700
+
+ Merge branch 'master' into branch-1.9
+
+commit bfc4999c99dc7ba29226a956f3991c2a45a1dd88
+Author: Bdale Garbee <bdale@gag.com>
+Date: Thu Dec 5 22:18:12 2019 -0700
+
+ update release date in all documents
+
+commit 55af5c3a0df734cedbac98bbe350846add45d5e3
+Author: Bdale Garbee <bdale@gag.com>
+Date: Thu Dec 5 22:15:21 2019 -0700
+
+ start the process of releasing 1.9.1
+
+commit 2ff2b4962f3241ede9a7718e373a68296c4e308a
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Dec 5 21:05:28 2019 -0800
+
+ Release note about self-flashing on windows waiting for devices
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 695dba4e37ccca9a2dc06e1656699a13406002c1
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Dec 5 16:59:40 2019 -0800
+
+ altosuilib: Wait for Windows to get ready with new device
+
+ Windows appears to report the new device path long before
+ the path is actually usable. Stick some long delays trying to
+ open the device before giving up.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2b3c6806a3039ac8c4c1a1e2d6715b0cdc5b9632
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Dec 3 19:34:06 2019 -0800
+
+ altosuilib: Show the recovered product name in the Configure Rom dialog
+
+ This lets the user know that things are actually working as expected
+ as the correct device name should appear in the dialog.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 5bdf8eeb1cdc1a50c9abd0f8962533f6970bd7f0
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Dec 3 19:31:34 2019 -0800
+
+ altoslib: Linker script changed -> the USB desc is two bytes off
+
+ The USB descriptor used to be at 0x0800110c in previous releases and
+ is now at 0x0800110a, presumably because the linker script changed the
+ padding requirements of those sections.
+
+ Search forward and backwards two bytes to see if we can't find the
+ descriptors by checking for the descriptor value and size at each
+ location.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 946faa1541f69c6cf2759c13760fa9bc16e2298e
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Nov 26 15:47:07 2019 -0800
+
+ doc: Update docs to reference TeleMetrum v3 where appropriate
+
+ Mostly just add 'or newer' to various TeleMetrum v2 bits. Also add
+ specs for the v3 board.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 68aa05881239264b95e37c648faa821fd0230402
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Nov 26 15:33:25 2019 -0800
+
+ doc: Mention TeleMetrum v3.0 in release notes for 1.9.1
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 56767df42a2582c9663554f27b354c2b9c180119
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Nov 25 18:38:14 2019 -0800
+
+ ao-telem: Show all 24 bits of GPS altitude data
+
+ Need to mix in the upper 8 bits from devices which include them.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 4a47071b7f23874ca3d889ba18cd218d6445df29
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Nov 25 18:36:16 2019 -0800
+
+ altos: Send "metrum" telemetry packets for TeleMetrum v3.0 boards
+
+ This includes the ADC values, which report igniter continuity
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 66b6b2d5fb1313d5e16a3f802c2af8cc6585362b
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Nov 25 18:15:16 2019 -0800
+
+ altoslib: Set up adxl375 for TM v3.0 in idle mode
+
+ Need to select axis and polarity for each adxl375 product.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9bb091f6d6aec6e5e887eebc93174106b25a7a98
+Author: Bdale Garbee <bdale@gag.com>
+Date: Mon Nov 25 18:02:06 2019 -0700
+
+ ao-bringup: add production test support for TeleMetrum v3.0
+
+commit f95b359aa1a3ba3982a162bdf398d0b261806d47
+Author: Bdale Garbee <bdale@gag.com>
+Date: Mon Nov 25 17:57:27 2019 -0700
+
+ altosuilib: TeleMetrum v3, like v2, doesn't use flash for config
+
+commit 8554da3b6c05c1094045f4fb21b43c183029408f
+Author: Bdale Garbee <bdale@gag.com>
+Date: Mon Nov 25 17:55:10 2019 -0700
+
+ altosui: add TeleMetrum v3 to delivered firmware list
+
+commit 0072e9741719367a1f6748d242cd6195a1a7c6a5
+Author: Bdale Garbee <bdale@gag.com>
+Date: Mon Nov 25 17:50:41 2019 -0700
+
+ altosui: add monitor idle support for TeleMetrum v3
+
+commit 6d55d03587e9f71a7e8320a6b36fde25edc63b28
+Author: Keith Packard <keithp@keithp.com>
+Date: Fri Nov 22 17:18:58 2019 -0800
+
+ altos: TeleMetrum v3.0 has ADXL375 and Max-8Q
+
+ Replacce the mma655x driver with the adxl375 driver
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit b215bed45798ea30f8f13128204493e7afdc9af1
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Oct 27 10:24:52 2019 -0700
+
+ altoslib: Fix original telemetry sensor packet parsing
+
+ ground_pres is at byte 24, ground_accel at byte 26. These were flipped
+ around.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit cdbc29d6d86c69e70b0f105d273ee8ddd7ae290e
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Oct 27 10:24:10 2019 -0700
+
+ altoslib: Fix setting of CLASSPATH
+
+ Need to include bin for local files.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3aeb1a310069811a2e043a5df28dc2df17436fc4
+Author: Bdale Garbee <bdale@gag.com>
+Date: Wed Oct 23 10:43:54 2019 -0600
+
+ doc: add some text about cross-bank drag race safe/arm to TeleLaunch manual
+
+commit 1cb529e0532d0a7430487c856bb9b037ff6cea0f
+Author: Bdale Garbee <bdale@gag.com>
+Date: Wed Oct 23 10:41:30 2019 -0600
+
+ doc: add some text to TeleLaunch troubleshooting about SAFE/ARM on TeleFire
+
+commit 88e279b15b3d2357f142e58d20d73c24bf2561eb
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Oct 23 09:24:18 2019 -0700
+
+ altos: Improve labeling of telefire receive packet information
+
+ Avoid the use of 'cmac_recv', which is not exactly descriptive.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c31db066e5ba7a6708ebe4bf350963697c611816
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Oct 23 09:20:53 2019 -0700
+
+ altos: Relabel packet receive status line for TeleFire boxes
+
+ The status line included return value and RSSI, but neither was
+ labeled, which left the user unsure as to what it meant.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit b6602d8c4053932a72c2bf4a63e24793634b2ad0
+Author: Bdale Garbee <bdale@gag.com>
+Date: Tue Oct 22 09:30:25 2019 -0600
+
+ doc: add more text to TeleLaunch manual, be less sloppy with dBm assertions
+
+commit c349eb9d1b90abd7c0492b5d0ba2116ae5ad6ec2
+Author: Mike Beattie <mike@ethernal.org>
+Date: Sun Oct 13 20:22:37 2019 +1300
+
+ Update app to use Material Design Light theme
+
+ The Holo theme does weird things these days
+
+ Signed-off-by: Mike Beattie <mike@ethernal.org>
+
+commit b8560bd91d603e4697f0cddc095952f923366d30
+Author: Keith Packard <keithp@keithp.com>
+Date: Fri Oct 18 01:06:55 2019 -0700
+
+ altoslib: Don't bother adding FREETTS to CLASSPATH
+
+ altoslib doesn't use freetts at all
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 4696687ef84181e363ac79f43016d347d7e14a23
+Author: Keith Packard <keithp@keithp.com>
+Date: Fri Oct 18 01:05:15 2019 -0700
+
+ altosdroid: Make altosdroid code more resilient to weird androidisms
+
+ Sometimes altosdroid was crashing when messing with configuration bits
+ like selecting different themes. These fixes seem to make that happen
+ less.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8be4e3b8faac362665641e98a1df1e1e8a681b7a
+Author: Keith Packard <keithp@keithp.com>
+Date: Fri Oct 18 01:02:51 2019 -0700
+
+ altos/test: Get test code working again after restructuring
+
+ Something changed, the test code wasn't building. Now it does.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8d5792e32dc35441ec98339149fb4df3cc16f44b
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Oct 17 23:09:47 2019 -0700
+
+ altos/telefire: Don't arm the box if the local arm switch is off
+
+ This skips arming the box when the local arming switch is off. This
+ keeps the siren and light from going off, and also avoids attempting
+ to fire the channels in case something else screwy is going on.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 75cd8196ee9ba4ed983abdc83f1fe60fb94f2866
+Author: Bdale Garbee <bdale@gag.com>
+Date: Mon Sep 30 21:15:56 2019 -0600
+
+ TeleFireEight has simple green LEDs for continuity
+
+commit ff68c8855bc6983638db5102ffbc6822b83edb5d
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Sep 25 13:10:36 2019 -0700
+
+ telegps: Get --graph mode working after recent changes
+
+ Was just exiting due to a null pointer exception caused by mis-ordered
+ setup of the map data. Also using stale API.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 35351c7db337c4384ef642fbc8b8676f0944686a
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Sep 25 13:09:22 2019 -0700
+
+ altoslib: Don't crash when map flight data is missing
+
+ Just a couple of null pointer checks to allow the map display to come
+ up even when no data are available.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 4df77f2ac7f34986b8e7c0584c57d77dc74d9df9
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Sep 24 20:49:56 2019 -0700
+
+ doc: Update for 1.9.1
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 51cca3b3405da7408fd8af18f8d1ff7db97fe1bc
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Sep 24 20:50:08 2019 -0700
+
+ doc: Describe new 'show nearest values' in map view
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6032ca7f418924e5794a886c06ca752dee0ada83
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Sep 23 12:40:19 2019 -0700
+
+ altos: Rename 'log' in ao_log_fireone to 'ao_fireone_data'
+
+ Avoids conflict with global 'log' function
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 77e6bad5e66023e487430ef31244edaeaef7c606
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Sep 23 12:39:42 2019 -0700
+
+ altos: Switch all main() to return 'int'
+
+ Makes gcc happy
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3979c88417fd5512447f5d02cc660522dff5d9d6
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Sep 18 17:38:44 2019 -0700
+
+ altosdroid: Update Makefile.am to run gradle-based build
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d607cbee5c9b406ef0f4e522c12e56993632cf00
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Sep 18 17:10:14 2019 -0700
+
+ altos: Add missing build files for avr/attiny devices
+
+ These were sitting in my src directory but not in git
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 260dd06107c8f8f5c7e606a283d388cb3ba46465
+Merge: 28618a72 faa5abe0
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Sep 18 16:26:44 2019 -0700
+
+ Merge remote-tracking branch 'mjb/android-build-update'
+
+commit faa5abe0bc9aa071ffa55534a24638bc0972e3c2
+Author: Mike Beattie <mike@ethernal.org>
+Date: Thu Sep 19 10:26:40 2019 +1200
+
+ Update Google Maps API usage.
+
+ Signed-off-by: Mike Beattie <mike@ethernal.org>
+
+commit 3af69b00a94b473dbc98fcf6d26fa90b66065e8b
+Author: Mike Beattie <mike@ethernal.org>
+Date: Thu Sep 19 10:25:47 2019 +1200
+
+ Update persistent notification in TelemetryService
+
+ Signed-off-by: Mike Beattie <mike@ethernal.org>
+
+commit be9ed3ffc9b00c97e8513bbfab23b8e16329bc4b
+Author: Mike Beattie <mike@ethernal.org>
+Date: Thu Sep 19 10:25:09 2019 +1200
+
+ Convert to AndroidX from support_v4
+
+ Signed-off-by: Mike Beattie <mike@ethernal.org>
+
+commit d7ef39ba104a1ac6024af875c730a645f282719f
+Author: Mike Beattie <mike@ethernal.org>
+Date: Thu Sep 19 10:24:13 2019 +1200
+
+ Import cleanup
+
+ Signed-off-by: Mike Beattie <mike@ethernal.org>
+
+commit 5c1acdabd211346936423ec8bc147a47f62bb8ae
+Author: Mike Beattie <mike@ethernal.org>
+Date: Thu Sep 19 10:19:11 2019 +1200
+
+ Commented out duplicate strings
+
+ Signed-off-by: Mike Beattie <mike@ethernal.org>
+
+commit ffdac6b48b43dc5610ddb926191a7cff738c97de
+Author: Mike Beattie <mike@ethernal.org>
+Date: Thu Sep 19 10:18:48 2019 +1200
+
+ Indentation cleanup
+
+ Signed-off-by: Mike Beattie <mike@ethernal.org>
+
+commit b6cb79994a58f37f6c743c1f2fafe30337e89d79
+Author: Mike Beattie <mike@ethernal.org>
+Date: Thu Sep 19 10:17:52 2019 +1200
+
+ Add FOREGROUND_SERVICE permission which is now required
+
+ Signed-off-by: Mike Beattie <mike@ethernal.org>
+
+commit f2c652d5115eb64568d9ae8ed6426a16e6154999
+Author: Mike Beattie <mike@ethernal.org>
+Date: Thu Sep 19 10:17:09 2019 +1200
+
+ Remove versioning data from AndroidManifest.xml.in
+
+ (now in build.gradle)
+
+ Signed-off-by: Mike Beattie <mike@ethernal.org>
+
+commit 198c868a25b3cbcde9634bbbcce57d71f3659eee
+Author: Mike Beattie <mike@ethernal.org>
+Date: Thu Sep 19 10:16:18 2019 +1200
+
+ Clean up duplication in AndroidManifest.xml.in
+
+ Signed-off-by: Mike Beattie <mike@ethernal.org>
+
+commit 1ba8ffe41defe411390197c56b03762fa51c20bf
+Author: Mike Beattie <mike@ethernal.org>
+Date: Thu Sep 19 10:12:59 2019 +1200
+
+ buildinfo data comes from Makedefs now, not Version
+
+ Signed-off-by: Mike Beattie <mike@ethernal.org>
+
+commit 3c4d4d5cc1a8361a713aba075b29c3f6509f3f90
+Author: Mike Beattie <mike@ethernal.org>
+Date: Thu Sep 19 10:12:30 2019 +1200
+
+ Add gradle build files
+
+ Signed-off-by: Mike Beattie <mike@ethernal.org>
+
+commit 70fb078cac4203e76e04211a0b8f1a6eceb6298b
+Author: Mike Beattie <mike@ethernal.org>
+Date: Thu Sep 19 10:09:26 2019 +1200
+
+ Update files that reference new paths
+
+ Signed-off-by: Mike Beattie <mike@ethernal.org>
+
+commit 8b53f860eb3171cd43e4bd0e440f2889bd810662
+Author: Mike Beattie <mike@ethernal.org>
+Date: Thu Sep 19 10:04:58 2019 +1200
+
+ Move java source, and resources to new paths for gradle
+
+ Signed-off-by: Mike Beattie <mike@ethernal.org>
+
+commit 4a257455b2dc57069c41e1845daf66239c5cbe1d
+Author: Mike Beattie <mike@ethernal.org>
+Date: Thu Sep 19 09:58:06 2019 +1200
+
+ Remove ant build files
+
+ Signed-off-by: Mike Beattie <mike@ethernal.org>
+
+commit 28618a728e85b70ecac73983531894a25e90d7f6
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Sep 16 13:12:08 2019 -0700
+
+ altos: Add EasyMega v3.0 bits (not setup correctly yet)
+
+ This adds a new directory for EasyMega v3.0, replacing the mpu9250
+ with a bmx160.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 28add4f616dbaf06a1ca3234b81c68c4a299d056
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Sep 16 13:10:09 2019 -0700
+
+ altos: Integrate BMX160 into data code
+
+ Get conversion functions written and fix up a few warnings
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a87698663f8a5ced468755068a0468755d8f2746
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Sep 16 12:39:09 2019 -0700
+
+ altos: Add bmx160 driver
+
+ This just adds the driver, it doesn't hook it up yet
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 99525a748e00406424b98a0952f0156437b30b6c
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Sep 15 17:09:26 2019 -0700
+
+ altos: Replace ao_xmem functions with direct mem calls
+
+ We no longer need to wrap these functions
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 46d3cbadce6808b4cd29ad1e034efac7b5e4fa42
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Sep 15 17:05:59 2019 -0700
+
+ drivers: Use 'main_value' instead of 'main'
+
+ GCC can emit a warning when programs redefine 'main'.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2524730217e6972f3d0f04a9954350ba1964a83a
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Sep 2 15:20:14 2019 -0500
+
+ altosui: Add speed and gps height to map display data
+
+ And generalize the API so that any other GPS data could be added in
+ the future.
+
+ This feature was proposed by Mike Beattie
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit b13893245e8c66b48e23bb2005ef6ce46e69744f
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat Aug 31 23:20:31 2019 -0500
+
+ altosui: Display data for point nearest cursor in map view
+
+ Include time, lat and lon
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 936a5ff21d01db6f0084ee7e4712042c914942a5
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Aug 28 22:40:21 2019 -0500
+
+ libaltos: gitignore btletest
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 252009db6451f01c9707970d05e69f39e3a047dd
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Aug 28 22:39:25 2019 -0500
+
+ Add .gitignore files for new projects
+
+ EasyMega v2.0
+ TeleFireEight v2.0
+ TeleFireOne v1.0
+ TeleLco v0.2 with cc1200 radio
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 415302a81f7bf0cdfd79999e1fcd5ea41dc39d13
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Aug 28 22:34:53 2019 -0500
+
+ icon: Ignore generated LED images
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 025c53a14804385ad96afcc9bf29a8d5c202a93a
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Aug 28 22:33:35 2019 -0500
+
+ Add new altosdroid icon
+
+ Remove drop shadow
+ Change size to make Google happier
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit fcb5d55e94058810fc8b31ad5e8caa99fa61200c
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Aug 12 17:30:48 2019 -0700
+
+ altos: Use fast timer for buttons instead of edge-triggered ISR
+
+ If the button bounces between the triggering interrupt and the button
+ state check, we could lose the final state change of the button and
+ send an incorrect event to the application. In the worst case, the button
+ would end up in exactly the wrong state, toggling in the wrong direction.
+
+ Use the fast timer to poll all buttons instead so that there is only
+ one check of each button at each poll interval (instead of the
+ interrupt and the state check). This makes buttons reliably debounced.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 5e738fd2e3602c6a92f205df99361dbe06c1719e
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Aug 4 21:12:29 2019 -0700
+
+ altosui: Make it possible to disable APRS
+
+ The menu says "Disabled", but the device wants "0". Translate back and
+ forth to avoid an error.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 1105cfe0c065483e8a97a800bc870fbdecaab9b6
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Aug 4 20:33:21 2019 -0700
+
+ altosui: Fix path to easymini-v2.0 ihx file
+
+ This gets the bits included in macosx and linux builds
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 489b429dbeb8b0fb69881161ff32fdc2fdfcf9f8
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Jul 16 11:15:20 2019 -0700
+
+ altosdroid: Hack up build to 'work' for now
+
+ Android apps are now build with gradle instead of ant; the ant bits
+ are stale and only work with old java. Use old java to run ant while
+ using the current java compiler to build things.
+
+ This requires a custom version of the google play API library.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 93401542ab1bf53c5b7b2a2cad5da97e44d7244e
+Author: Bdale Garbee <bdale@gag.com>
+Date: Fri Aug 2 14:20:39 2019 -0600
+
+ ao-bringup: add a turnon_telefireeight script
+
+commit 318b81d59e6f34a92a7a78c0896aa331bc14d0a1
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Jul 17 11:40:06 2019 -0700
+
+ Use discovered java path for compiler and jni include files
+
+ Instead of using the discovered java bits just for jni.h, also use
+ javac from that directory. Add JAVA_VERSION param to set language
+ version for newer compilers.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 784ccd37d051e8b88ef1b150ccb4e89103675b3e
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Jul 17 11:38:43 2019 -0700
+
+ altoslib: Stop using deprecated Java functionality
+
+ new Double(x) -> Double.valueOf(x)
+ c.newInstance() -> c.getDeclaredConstructor().newInstance()
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 25be2785cf34773bdcac5ec7b2a41769e352812a
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Jul 16 12:08:33 2019 -0700
+
+ ao-tools/ao-eeprom: Add support for TeleFireTwo
+
+ Display converted pressure and thrust data along with raw thermistor
+ data.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8b2e457db8c4536440ecd7dc35d06f827fc008dc
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Jul 16 11:12:49 2019 -0700
+
+ altos: Record all failed sensors and report status at power up
+
+ Use DATA bits to mark which sensors have failed, then report that in
+ beeps at startup time to help diagnose hardware failures while still
+ allowing the board to be used over USB.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c37cd66b7c11f904b528c5ff7e80e18c5e0d26e5
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Jul 16 11:10:36 2019 -0700
+
+ altos/micropeak-v2.0: Reduce power usage
+
+ This gets power consumption down under 1mA on the pad. Not really low
+ enough to sell, but I think this is about as low as the chip will go.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 40624256be70088d7608742b71e1241d95a7fcdf
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Jul 16 11:07:27 2019 -0700
+
+ altos/stmf0: Allow SPI to be powered down when idle if desired
+
+ Set SPI_1_POWER_MANAGE and/or SPI_2_POWER_MANAGE to have the spi
+ blocks powered down when not in use.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit bdcb3653bd9fb97f98773ac3bc1f87a6f52b1121
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Jul 16 11:04:16 2019 -0700
+
+ altos/stmf0: Add 'ao_serial_shutdown'
+
+ This powers down the UART logic on request.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 009d56b4f03c1ba3c9a36bdb54c772ad21844057
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Jul 16 11:02:56 2019 -0700
+
+ altos/stmf0: Leave power interface disabled until needed
+
+ We only need the power interface when placing the chip in the lowest
+ power state, so don't power up the power interface clock at startup,
+ instead wait until later.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e879d739c394602043e8ed512ad1a433fbf96c1c
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Jul 16 10:23:54 2019 -0700
+
+ icon: Add altosdroid-specific icon
+
+ Google style guides have no drop shadows anymore, so create an icon
+ for the play store without one.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9abacdaacf5ad1211da4fc72f5320ba9c43ff509
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Jul 16 10:22:02 2019 -0700
+
+ altosuilib: Don't crash when flashing an unknown device
+
+ An unknown device will not have a config; check for that before
+ showing radio calibration dialogs.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a0a109d8c82e7f362253a0f1e52d14843ddec996
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Jul 16 09:57:24 2019 -0700
+
+ ao-tools/ao-eeprom: Add altitude data for baro values
+
+ Displays altitude along with pressure and temp for baro sensor data.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 0a60b7addddc302c66556c0f25ba1e71d14cf53d
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Jul 16 09:56:39 2019 -0700
+
+ ao-tools/lib: Add atmosphere model
+
+ Converts between pressure and altitude
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit fa214ca689449af3a241750e6c759dd3f2d52327
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Jul 15 13:28:11 2019 -0700
+
+ ao-tools/ao-telem: Fix man page and usage to match code
+
+ ao-telem just parses .telem files.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 245a49a85dd7b6a7cb9ec36ad02f6bb66e42f4e2
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Jul 15 13:26:30 2019 -0700
+
+ altos: Allow ms5607 driver to either set ao_sensor_errors or panic
+
+ Products that want to remain usable (over USB) after a sensor failure
+ don't want to panic when the ms5607 fails, but products with limited
+ ROM space don't want to have extra code to check for the sensor
+ failure and panic. Change the MS5607 driver to allow either option,
+ and then make the micropeak based devices use it.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 98f7c1c116aab672a29db1f81213cabe2d72ae16
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Jul 15 13:22:15 2019 -0700
+
+ ao-tools: Change ao-eeprom into eeprom analysis tool
+
+ ao-eeprom used to be a TeleMetrum v0.2 specific tool for fetching
+ eeprom contents from that device. ao-dumpflash handles that case now.
+
+ ao-eeprom now parses .eeprom files and displays their contents.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e3eb285ff6be17afe592dca4a2fb5526c0626283
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Jun 18 23:18:19 2019 -0700
+
+ altos/micropeak-v2: Update .gitignore
+
+ Ignore built stuff
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 06be34ea0750743b85823b873041188dac7b06d9
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Jun 18 23:17:10 2019 -0700
+
+ altos/micropeak-v2: Correct AO_LOG_ID value
+
+ Typo wasn't caught by the compiler (thanks!)
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c4b8aff07d5366cef2c7209729f6cd22fa67de0c
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Jun 18 23:16:12 2019 -0700
+
+ altos/micropeak-v2: Erase log space at end of BOOST_DELAY
+
+ We have to erase the log before the flight starts, so this seems like
+ the latest possible moment.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 835faccc2c1141f7cd8ff93629d583fcaf785e48
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Jun 18 23:14:54 2019 -0700
+
+ altos: Don't dump MS5607 eeprom in 'B' command
+
+ MicroPeak v2 now has config stuff where these values get shown
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit bcf609837eefd431415c979942a31abda1227eb9
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Jun 18 23:14:05 2019 -0700
+
+ altoslib: Add support for MicroPeak v2 eeprom format
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ee7a54b3215ffa1eb38f16a151c0740b14b60857
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Jun 18 14:50:53 2019 -0700
+
+ altos/micropeak-v2.0: expose log and config commands over USB
+
+ This lets AltosUI handle the eeprom data
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6529fd623f0e4b921aea1110c723d7dc03954def
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Jun 18 14:50:18 2019 -0700
+
+ altosui/telegps: Display error message when attempting to graph unknown files
+
+ Instead of presenting an empty graph window.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit bd351b9e3b1ba21851b2c87f5202ac3bf5c479c0
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Jun 18 14:25:09 2019 -0700
+
+ altoslib: Always create an ordered record set for eeprom files
+
+ If we can't parse the format, just leave it empty. This makes code
+ handling arbitrary records much easier as it doesn't have to check for
+ the ordered set existing.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 4d4f018f22a0a9814e675a232b1c4239572bdd9a
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Jun 18 13:02:51 2019 -0700
+
+ altos/micropeak-v2.0: Go into standby mode after landing
+
+ This is the lowest power state we can reach, and consumes about 15µA
+ or less.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2ef794e60b4f6a6e9cb5e9a14ef732f7d6d36b3d
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Jun 18 13:02:12 2019 -0700
+
+ altos/micropeak-v2.0: Fix LED blinking sequence at power-on
+
+ 'pips' happens between altitude report and data dump.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8ec178bbc3babb072b8d53975632cf6294626e98
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Jun 18 00:11:49 2019 -0700
+
+ altos/micropeak-v2.0: Wait for the power supply to stabilize before measuring
+
+ If we don't wait before measuring the battery, it will often read
+ under 3.2V right at boot time, which puts MicroPeak in flight mode
+ instead of USB mode.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 77df3f636ef8bf461800f5e08c28c09bfb69c48b
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Jun 17 23:44:50 2019 -0700
+
+ altos/micropeak-v2.0: Don't run flight code when plugged in
+
+ No sense running the flight code when there's a USB cable attached.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ff7fa802f632700f73418246f1be5017ac0a09b4
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Jun 17 23:43:02 2019 -0700
+
+ altos: Support ao_ms5607_dump when no ms5607 task
+
+ MicroPeak v2.0 has tasking support, but doesn't have a separate ms5607
+ task. That means the device isn't getting initialized when not running
+ the flight code, so in cmd mode we need to make sure it's initialized,
+ and we also need to actually fetch a value to display.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 7c5ba25e61f98fd4537062dce52ab22d1445fa24
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Jun 17 23:41:51 2019 -0700
+
+ doc: Say 'thousands of feet' instead of '3000-4000 feet'
+
+ No reason to try and be precise here.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 4be194a350987cff5b459ebaa751347b216fde05
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Jun 17 14:49:36 2019 -0700
+
+ altosui: Ship EasyMini v2.0 firwmare
+
+ Left this out in the last release...
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 0a466e9869633c6ce7e43ff24ba2afff938461dd
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Jun 17 14:47:56 2019 -0700
+
+ doc: Describe what sunlight does to MicroPeak and how to protect it
+
+ Show flight data from micropeak in sunlight, a picture of foam
+ installed on micropeak and the resulting data.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit fa8e0fb8b75a808e029b090747fb60b35debb44a
+Author: Bdale Garbee <bdale@gag.com>
+Date: Wed Jun 5 10:46:57 2019 -0600
+
+ add an explicit reference to Poron open-cell foam in Appendix A
+
+commit a6e8b739c47c50fa472e3f2a41cf13abb8d82c07
+Author: Keith Packard <keithp@keithp.com>
+Date: Fri May 3 21:51:28 2019 -0700
+
+ altos: Directly compute radio tuning values from frequency
+
+ The 8051 compiler doesn't support 64-bit ints, so the old
+ code used an iterative method in 32-bit values. That could take
+ a long time when the frequency was mis-entered in Hz or MHz instead of
+ kHz.
+
+ This direct-computation uses 64-bit ints, but takes a fixed amount of
+ time for any inputs.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 1d3a8443d8de832b8e76a005e56ac5ff09b71849
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Apr 23 06:45:54 2019 -0700
+
+ Add TeleStatic-v3.0 makefiles
+
+commit 0800970a4c9c6ed38bb76bfed6374093ca16b459
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Apr 21 18:30:43 2019 -0700
+
+ altos: Add preliminary TeleStatic v3.0 code
+
+ This adds the pin definitions and all of the code except for the
+ ads131a04 driver.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6a29b84cffcd31b2a74dd14a18aa4790eb4f14f9
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Apr 21 18:19:59 2019 -0700
+
+ altos/telefireone-v2.0: Include MAX6691 data in ring
+
+ Define HAS_MAX6691 which tells the data code to pull the MAX6691 data
+ into the data ring for logging etc.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 83823e4ee901edb893db68e36deb2b92ffec3958
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Apr 21 18:18:55 2019 -0700
+
+ altos: Change MAX6691 driver to run its own thread
+
+ This just captures temp data continuously; it takes 100ms to get the
+ temp data from the sensor, so the maximum rate is around 10 samples/sec.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 188f9efadd480de872f86a8eb741e8738db84c6b
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Apr 21 18:14:05 2019 -0700
+
+ altos: Add MAX6691 and ADS131A0X data to ring if present
+
+ Add these two devices as potential data sources to be added into the
+ ring if available.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2c19d410f9d6ff1075ea2de0c0ad7b6a84e1e378
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Apr 21 16:53:51 2019 -0700
+
+ altos/telefireone-v2.0: Definitions needed for MAX6691 driver
+
+ Fix the DMA channel definition (STM starts values at 1 for unknown reasons).
+ Add definition of the power enable bit for the timer.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 5d3436ed8551537287dc6cf418f93b0989e1aee8
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Apr 21 16:49:19 2019 -0700
+
+ altos: get ao_max6691 driver working
+
+ The driver uses a timer connected to a DMA engine to measure pulse
+ widths from the chip. We get 11 pulses for 4 channels; the first pulse
+ is caused by the timer starting up, the next two are the marker pulse
+ and then 8 more indicating the end of the high and low periods for
+ each channel.
+
+ The driver API returns the 8 pulse widths; the caller is expected to
+ know what to do with those values as using them requires knowing the
+ value of the configuration resistor and the characteristics of the
+ thermistors.
+
+ The test code assumes a 1k configuration resistor, using that it computes
+ the resistance of the four thermistors.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 49ce3e9a2eb4e1918773b80c355d720a3dadc7e0
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Apr 11 23:54:37 2019 -0700
+
+ altos: Work on MAX6691 driver
+
+commit 0e8970c7f4eb7e8dd4ef325e4db4fe7412d0ed78
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Apr 21 12:55:20 2019 -0700
+
+ altos/lambdakey-v1.0: Fix obvious build errors
+
+ The code is too large to run on this device at this point, but at least
+ it doesn't fail to compile?
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8d77d5032781c5ef0dbb19de07ea97389b809f08
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Apr 18 19:48:00 2019 -0700
+
+ altoslib: Correct monitor idle IMU data for EasyMega v2
+
+ The IMU on EasyMega v2 is rotated from the other devices using this sensor.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6dea82844075348049ce5ff9bb8670ba8efc6668
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Apr 18 19:46:24 2019 -0700
+
+ altoslib: Fetch correct mag along data for EasyMega v2
+
+ Was using the wrong axis (y) instead of the correct one (x)
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit df08028ff5dd892dafa667fde1fbf9de43f82fea
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Apr 18 14:42:15 2019 -0700
+
+ altos: Use ao_data_accel_invert when changing orientation value
+
+ Instead of using AO_ACCEL_INVERT, use the macro which flips the values
+ around. This fixes a bug with ADXL375 flight computers (EasyMega v2.0) where the
+ accel cal values would be scrambled when changing orientation.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 774001a9426493fd5c0d5a237da6cb903b1259a8
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Apr 18 14:32:48 2019 -0700
+
+ doc: Make sure all 'code' examples are in DejaVu Sans Mono
+
+ We were inheriting the default value for this setting, which was Courier
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit b4ee716c0026cf997cde36ef00720d63a4c62c0c
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Mar 28 22:29:21 2019 -0700
+
+ doc: Document LEDs on TeleGPS devices
+
+ V1 has just the battery charger. V2 adds the GPS lock indicator.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 226f422b1fe5ccdf0bb3c07fa4983ec1615ce066
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Mar 18 17:21:57 2019 -0700
+
+ altos/stm32f4-disco: Remove scheme
+
+ This demo doesn't need a lisp interpreter
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 96c446b4dba6814d61317efb4d2dc99a3ca29e0c
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Mar 18 17:20:52 2019 -0700
+
+ altos/stm32f4: Working on USB
+
+ Reset now works, still no packets
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e38e1a2f735a1bb4aebf0817cdd99a05567c6340
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Mar 18 17:20:14 2019 -0700
+
+ altos/stm32f4: Wrong value for CK48MSEL_PLL_Q
+
+ This meant that the USB clock wasn't actually getting started...
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 65be5d1e07ff4ae619233f3b541b9599c44490ab
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Mar 18 17:17:21 2019 -0700
+
+ altos/stm32f4: Need to read-back register after clock enable
+
+ This was reported as necessary; I have no idea, but it's not
+ expensive, so why not...
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit efc2c093819b3ec2e5743126efb76d3a9c0ad231
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Mar 18 17:16:16 2019 -0700
+
+ altos/stm32f4: Add -mfloat-abi=hard compile option
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a2df970fca0e719e4b32e1642803590ff7bbd1ee
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Mar 18 17:15:16 2019 -0700
+
+ altos: ARM ABI requires 8-byte aligned stack
+
+ This makes doubles on the stack (as for var-args functions) work
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit b7de266431ee7bf05ba68ccae3e43a0468045860
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Mar 12 12:58:20 2019 +0100
+
+ altos/drivers/ao_led.c: Declare LED port as void * to allow any SoC to use this code
+
+ The generic LED code needs a generic type for the GPIO port.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3a01a7e36dd475adf96468f42c95aa352b5fdf11
+Merge: 338372b9 6b0754ce
+Author: Bdale Garbee <bdale@gag.com>
+Date: Tue Mar 5 18:31:37 2019 -0700
+
+ Merge branch 'master' of ssh://git.gag.com/scm/git/fw/altos
+
+commit 6b0754cee625c6e2c19dc70fb5be6cd2f0125d47
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Mar 5 17:25:44 2019 -0800
+
+ doc: A few minor edits to telelaunch docs
+
+ 3 → three
+ less → fewer
+ transreflexive -> reflective
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 338372b97d441c30d2a23df540163a66a7f8d8c0
+Merge: 8d0df64b cd920a0e
+Author: Bdale Garbee <bdale@gag.com>
+Date: Mon Feb 25 18:30:08 2019 -0700
+
+ Merge branch 'master' of ssh://git.gag.com/scm/git/fw/altos
+
+commit cd920a0e5321166ef8b1d6afc3d63fc5de998a93
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Feb 25 16:42:25 2019 -0700
+
+ altos: add ao_time_ns API
+
+ This provides nano-second resolution times by reading the systick
+ value (which runs at 250ns ticks on stm).
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 0448b9b638f8599633227a639ef9d8572780bbd9
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Feb 25 16:41:45 2019 -0700
+
+ altos: Change default time type to 32-bits
+
+ Offers additional range for internal use without increasing cost on
+ 32-bit platforms.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6fec7b5affd223c18bad78377d7655af958dffc2
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Feb 25 16:40:16 2019 -0700
+
+ altos: Fix several mis-specified time types
+
+ Make sure AO_TICK_TYPE is used "everywhere", instead of uint16_t or other.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8d0df64bbc5ed31188b4b4bea0be52a52dbece3b
+Author: Bdale Garbee <bdale@gag.com>
+Date: Sun Feb 24 15:10:25 2019 -0700
+
+ altos: ads124s0x successfully reading data
+
+commit 14fe18559d2eb7e568f07fcbaec89b6ef55fae24
+Author: Bdale Garbee <bdale@gag.com>
+Date: Sun Feb 24 11:51:58 2019 -0700
+
+ altos: snapshot - working on ads124x0x driver
+
+commit 2f87e182d9f0b3c2856f62149371ad70b16148cf
+Author: Bdale Garbee <bdale@gag.com>
+Date: Sun Feb 24 10:49:47 2019 -0700
+
+ altos: ADS124S0X driver compiles now
+
+commit 69bdb309f46a28803e93b08921720805b28b18a2
+Author: Bdale Garbee <bdale@gag.com>
+Date: Sun Feb 24 10:28:15 2019 -0700
+
+ altos: fix ads124s0x data structure
+
+commit 8cc418ed3b0df0e465f0af27c2255cb97294e6ce
+Author: Bdale Garbee <bdale@gag.com>
+Date: Sun Feb 24 10:25:31 2019 -0700
+
+ altos: first cut at ADS124S0X driver interrupt handling
+
+commit 654a23168f59d04d7e9cad657bebf8ecfdd8e41e
+Merge: d0f66918 655c5d2c
+Author: Bdale Garbee <bdale@gag.com>
+Date: Thu Feb 21 21:57:26 2019 -0700
+
+ Merge branch 'master' of ssh://git.gag.com/scm/git/fw/altos
+
+commit d0f6691804ee8de633601483354c93f1c2d75219
+Author: Bdale Garbee <bdale@gag.com>
+Date: Thu Feb 21 21:57:08 2019 -0700
+
+ doc: actually add the telelaunch files
+
+commit 655c5d2c1124182ba336db368474cf4de0b9ce9d
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Feb 21 19:28:14 2019 -0800
+
+ altos: Allow applications to override newlib printf selection
+
+ Re-defining NEWLIB_PRINTF_CFLAGS will allow applications to select
+ printf with floating point support if desired.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3310b22e28d953a6569cd50e83f91c25577424a5
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Feb 21 19:26:41 2019 -0800
+
+ altos: Fix ISR declarations to make them non-weak
+
+ In my zeal to eliminate warnings, I added declarations of all ISR
+ functions to a shared header file. However, I managed to include the
+ 'weak' declaration, which meant that the intended ISR functions were
+ as weak as the 'default' ISR functions. This left all interrupts
+ non-functional, which doesn't make for a happy program.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit eaf2ee0f498b519d64e1664a2b8c66c52ac1497c
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Feb 18 16:43:50 2019 -0800
+
+ altos/telefireone-v2.0: Remove build of ao_product.h from Makefile
+
+ This is built in common code now.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c411c7ec71be0263a958c0803772cd6068e6bdad
+Author: Bdale Garbee <bdale@gag.com>
+Date: Thu Feb 21 17:14:24 2019 -0700
+
+ doc: new TeleLaunch system manual
+
+commit 5c772d58ba83e147f0a404261a34c39183f2aac3
+Author: Bdale Garbee <bdale@gag.com>
+Date: Mon Feb 18 17:39:34 2019 -0700
+
+ altos: first cut of code for telefireone-v2.0
+
+commit d31fda73fef37cf6a9e449c99f3197b713b93acb
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Feb 18 16:26:39 2019 -0800
+
+ altos: Build telefireone-v1.0 by default
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6aeb000899ad7f22e92b487b5891664554bc4d33
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Feb 18 16:26:08 2019 -0800
+
+ altos/telefireone-v1.0: Track ao_led_init API change
+
+ No longer takes a parameter.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2e468bfbf9f430b6a3970283d818ea4405ccfc5b
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Feb 18 16:25:38 2019 -0800
+
+ altos/telefireone-v1.0: Set various ADC values
+
+ Reference voltage and divider resistor values.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 4b41b14ea46ff6954895824a60637c0eb4353b17
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Feb 18 16:25:06 2019 -0800
+
+ altos/telefireone-v1.0: Set AO_LOG_FORMAT
+
+ Use AO_LOG_FORMAT_TELFIRETWO for now; perhaps we'll have a new format
+ at some point.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 58f77ec66f5e40095917905578e36566b7e3401e
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Feb 18 16:24:21 2019 -0800
+
+ altos/telefireone-v1.0: Turn off USE_INTERNAL_FLASH
+
+ This is for TeleMini v1.0 which stored log data to the program flash.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9ea50f00039c812ea6a4a4235d78c140a0252662
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Feb 18 16:23:13 2019 -0800
+
+ altos/telefireone-v1.0: Clean up Makefile
+
+ Follow other projects and remove common bits which are now in
+ Makefile.defs
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d19f1888d736943e8b51aeb56ec7097e11a505fc
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Feb 18 16:22:07 2019 -0800
+
+ altos/telefireone-v1.0: Doesn't have a beeper
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit f9f1776f61cf365e3c8862f9f93cd2773391da16
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Feb 18 16:20:14 2019 -0800
+
+ altos: Remove AO_LOG_STATE from ao_log_telefiretwo
+
+ Telefiretwo never changes flight state, so these packets weren't going
+ to be written.
+
+ Also stop passing &log to ao_log_firetwo -- it always got the global
+ anyways, just use it directly.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 7a89aa1ea7e1b02b5cd310986adf4239ec0ce91d
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Feb 18 12:59:05 2019 -0800
+
+ altos: Move common build definitions to src/Makefile.defs
+
+ This cleans up the build process for all architectures, providing a
+ common place to specify vpath, cflags and build rules for various
+ common files.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 889518aeee080b0f8bb954db86d08105898d8161
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Feb 18 11:25:21 2019 -0800
+
+ altos/attiny: Mark 'mode' param to ao_exti_setup_port as used
+
+ Retain API.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a12dc56db6d5245ee8ac594337576dd85791a984
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Feb 18 10:42:23 2019 -0800
+
+ altos: Add -Wshadow to CFLAGS
+
+ And fix up the related messages.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit fda36e57205138f6c180a18b54956ea1682a5293
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Feb 18 10:41:31 2019 -0800
+
+ altos/stm-demo: Make this build again after various API and CFLAGS changes
+
+ Deal with LED API change. Remove unused functions.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 85104dbe9684af579c9255553b609fd28f8ee276
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Feb 18 10:40:06 2019 -0800
+
+ ao-tools/ao-dump-up: Document --wait flag
+
+ --wait means to poll for a µPusb device instead of bailing when none
+ exists at startup. Quite useful for testing a batch of new device.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit b6021e8dd866d6db54d28c79f0572aadd1861a5f
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Feb 18 10:39:11 2019 -0800
+
+ ao-bringup: chaosread is no longer part of altos
+
+ this has been moved to a separate project.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a43bc96ad4a524480a2d47500fb0cfaeeba8ad3d
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Feb 18 10:38:21 2019 -0800
+
+ stm: Expose LCD font API in ao_lcd_font.h
+
+ That required renaming the existing LCD font defintions from
+ ao_lcd_font.h to ao_lcd_font_bits.h.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ebb8ab6a2f5f1245098ad68d0cd007d3f115a24d
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Feb 4 22:39:34 2019 -0800
+
+ altos: Add a pile more compiler warnings
+
+ Adds:
+ -Wpointer-arith
+ -Wstrict-prototypes
+ -Wmissing-prototypes
+ -Wmissing-declarations
+ -Wnested-externs
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d6c3c3618a708d2a1a7948454710e6ae21c2a426
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Feb 4 22:38:23 2019 -0800
+
+ altos: Declare task stack as union of uint8_t and uint32_t
+
+ Support -Wcast-align and -Wpointer-arith while still allowing
+ architectures to pick whether they want an 8-bit or 32-bit stack.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 63a44b9c169d042fb1a3997620477e7f00bb0918
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Feb 4 22:34:21 2019 -0800
+
+ altos: Remove unused ao_adc_get from ao_adc_stm.c
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit f26197f0eec650330b476514c47978b4ba087719
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Feb 4 22:33:32 2019 -0800
+
+ altos: Stop doing pointer arith on void *
+
+ Switch to uint8_t * instead.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 54dd2a6e3a05b940d9daebb3d73f6876c182b3e7
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Feb 4 22:32:24 2019 -0800
+
+ altos: Add 'void' to function declarations with no params.
+
+ Support -Wstrict-prototypes
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 873f511173c637016b5e173813bd03c1725797bb
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Feb 4 22:28:02 2019 -0800
+
+ altos: Declare all public functions in header files
+
+ Including interrupt vectors to catch mis-spellings.
+ Working toward supporting -Wmissing-prototypes
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c11427819ca24bb77523496309b5b6f699d126c5
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Feb 4 22:24:37 2019 -0800
+
+ altos: Mark local functions 'static'
+
+ Working towards supporting -Wmissing-prototypes
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 119a829e58aff5dd7801fe7ef8cae886bf31fec1
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Feb 4 22:35:02 2019 -0800
+
+ altos/stm: Note that ao_i2c_recv_dma_isr isn't actually used
+
+ This function resets the i2c transceiver after DMA completes, but it
+ hasn't ever been hooked up. Some testing would be a good idea. For
+ now, just add a comment and mark the function as referenced to avoid a
+ compiler warning.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit acf032eb39504657e9289ca54844967b9c3bed76
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Feb 4 22:42:05 2019 -0800
+
+ altos: Fix spelling of stm_dma_ch4_5_6_isr
+
+ This spellingn error would have caused all DMA to these channels to fail.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d7f8c9262f7979ddcc93cb64b913e392c18ef674
+Author: Bdale Garbee <bdale@gag.com>
+Date: Sun Feb 17 17:35:25 2019 -0700
+
+ altos: ADS124S0X driver compiles with initialization code maybe completed
+
+commit c29f65a5696df66efb7e84e3ae8a3ea4b1f1494c
+Author: Bdale Garbee <bdale@gag.com>
+Date: Sun Feb 17 14:38:53 2019 -0700
+
+ altos: add initial support for TeleFireOne v2.0
+
+commit 630f457666b48321be0a5b6fbf391efef1fa3eb4
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Feb 3 12:48:45 2019 -0800
+
+ Use strip-nondeterminism to fix JAR timestamps
+
+ .jar files are just zip files, and contain dates. These will cause the
+ build to be non-reproducible. Use strip-nondeterminism to smash all of
+ these back to a fixed value.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 145e5a1ac557c4990e74fb64b005fc68d6941bdc
+Merge: e2c9ef80 db730875
+Author: Bdale Garbee <bdale@gag.com>
+Date: Mon Jan 28 13:46:59 2019 -0700
+
+ Merge branch 'master' of ssh://git.gag.com/scm/git/fw/altos
+
+commit e2c9ef801abacd2533d9b4321c24a490d4556134
+Author: Bdale Garbee <bdale@gag.com>
+Date: Mon Jan 28 13:45:31 2019 -0700
+
+ Makefiles, too
+
+commit db7308750b3478ec3d2332e81db9957a9d4f2cfc
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Jan 28 11:35:32 2019 -0800
+
+ altos/telefireeight-v2.0: Add flash loader Makefile
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e40407467f28ab44b9f7c7d51a65a51f802410d5
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Jan 28 11:33:19 2019 -0800
+
+ altos: Delete unused config bits for telefireeight-v2.0. Add Makefile
+
+ Clean up the config and set the copyright year.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 38dc7545a98a851af447ad3d69fa5bc85583fed9
+Author: Bdale Garbee <bdale@gag.com>
+Date: Sun Jan 27 19:20:02 2019 -0700
+
+ altos: add telefireeight-v2.0 to src/Makefile and to Releasing
+
+commit f29b55691c9f160898b49bf15f46a88ae00b115f
+Author: Bdale Garbee <bdale@gag.com>
+Date: Sun Jan 27 19:16:41 2019 -0700
+
+ altos: add support for telefireeight-v2.0
+
+commit 37f4a66e47370e0e5ef42b0d70cda060fa2baa64
+Author: Bdale Garbee <bdale@gag.com>
+Date: Wed Jan 9 15:42:42 2019 -0700
+
+ doc: add force-bootloader instructions for TeleGPS v1 and v2
+
+commit 3703aef1b8b043697e8b99df24b987ba696909bc
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Jan 7 17:15:41 2019 -0800
+
+ doc: Fix typo in TeleBT v3 flash-force instructions
+
+ taht → that
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 38630c65460b5e873a0df0fef937d498a37ea329
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Jan 7 17:12:56 2019 -0800
+
+ Remove ao-chaosread
+
+ This program is now provided by the independent chaosread program.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 31f9ed231e63b214b405a141cabce3eb758e82e6
+Author: Bdale Garbee <bdale@gag.com>
+Date: Sat Jan 5 18:02:34 2019 -0700
+
+ doc: add flash-force instructions for TeleBT v3.0
+
+commit 72bcff4c1af10571314e5cbbe29f073de818088e
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Jan 3 11:59:02 2019 -0800
+
+ ao-tools/ao-telem: Print out 'log_max' value. Clean up compiler warnings.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 14900d539c9d379a39ec157bb7e1914aad8fde3c
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Jan 3 11:57:42 2019 -0800
+
+ ao-tools/ao-cal-accel: Initialize byte count var 'l'
+
+ When left uninitialized, the program would randomly segfault at startup.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 96be286b3a9daa9bdb7872118be0118872d483f8
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Jan 3 11:55:38 2019 -0800
+
+ ao-tools/ao-load: Return status from 'rewrite'
+
+ Was just falling off the end of this function, returning a random value.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6f729ff46b2f4531db68f0af85e7e9fe0f6d1969
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Jan 3 11:41:49 2019 -0800
+
+ ao-tools: Fix warnings in ao-tools
+
+ None of these appear likely to have caused actual problems.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit f14c799ae7ff3be56c28f5694f04c03daff7708e
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Jan 3 11:40:32 2019 -0800
+
+ ao-tools: Add lots of compiler warning flags to ao-tools build
+
+ This catches some uninitialized variable errors which cause
+ ao-cal-accel to crash (fixes coming next)
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit adf4bec88df1822031e1a8b00422de8b8b0c0cd4
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Jan 2 23:51:58 2019 -0800
+
+ doc: Update all docs to 1.9. Note this in doc/RELNOTES
+
+ Missed a bunch of 1.8.7 numbers due to a missing step in the release process
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a3177edd807b12a58d684ece60b0f3329e742af6
+Author: Bdale Garbee <bdale@gag.com>
+Date: Thu Jan 3 00:49:22 2019 -0700
+
+ updates to Releasing based on 1.9 release process learnings
+
+commit 5b4da841459a650e641924aab132f566c6259c4d
+Merge: 95ffec07 ecf40a3a
+Author: Bdale Garbee <bdale@gag.com>
+Date: Wed Jan 2 23:03:41 2019 -0700
+
+ Merge branch 'master' into branch-1.9
+
+commit ecf40a3a190fb2f7d7d2654c1e87daddf0362b0c
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Jan 2 22:02:42 2019 -0800
+
+ doc: Skip .pdf generation when asciidoctor-pdf is missing
+
+ Not available in debian unstable yet
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 95ffec073b0758801df04a77eca0bd2bc6e57e35
+Author: Bdale Garbee <bdale@gag.com>
+Date: Wed Jan 2 22:19:36 2019 -0700
+
+ changelog for 1.9 release
+
commit 4e9e0bf99d6b71086110038fa1e3231d00bb2496
Author: Keith Packard <keithp@keithp.com>
Date: Mon Dec 31 15:20:57 2018 -0800
These are Bdale's notes on how to do a release.
- - make sure build environment is up to date
+ - make sure Debian build environment is up to date
sudo cowbuilder --update
+ - make sure fat build environment is up to date
+ sudo apt update && sudo apt upgrade
+
- ensure i386 build support is available, and we have tools to build
installers for Windows and Mac OS X
- cherry-pick or merge appropriate content from master
- make sure there is a doc/release-notes-<version>.inc
- - make sure that doc/altusmetrum-docinfo.xml has the right copyright
- year, and add release to the revision history at the front (release
- notes will be pulled in automatically)
+ - make sure that doc/*.txt have the right copyright year and the
+ new release is included
- make absolutely sure checked-out tree is "clean"
- - make absolutely sure the pdclib/ submodule is on the master branch,
- up to date, and "clean"
git log > ChangeLog
git commit -a
git commit -n debian/changelog -m "update changelog for Debian build"
- if this is a -1 release, then
- gbp buildpackage --git-no-pristine-tar --git-submodules \
+ gbp buildpackage --git-no-pristine-tar \
--git-upstream-branch=branch-<version> \ # eg 1.3
--git-upstream-tag=<version> # eg 1.3.1
pristine-tar commit \
../build-area/altos_<version>.orig.tar.gz \
branch-<version>
else if this is not a -1 release
- gbp buildpackage --git-submodules
+ gbp buildpackage
git tag debian/<version>
src/telemini-v3.0/{*.elf,*.ihx} \
src/telelco-v2.0/{*.elf,*.ihx} \
src/telefireeight-v1.0/{*.elf,*.ihx} \
+ src/telefireeight-v2.0/{*.elf,*.ihx} \
~/altusmetrumllc/Binaries/
cp src/chaoskey-v1.0/flash-loader/{*.elf,*.bin} \
src/easymega-v1.0/flash-loader/*.elf \
src/telemini-v3.0/flash-loader/{*.elf,*.bin} \
src/telelco-v2.0/flash-loader/*.elf \
src/telefireeight-v1.0/flash-loader/*.elf \
+ src/telefireeight-v2.0/flash-loader/*.elf \
~/altusmetrumllc/Binaries/loaders/
(cd ~/altusmetrumllc ; git add Binaries ; git commit -a)
- remove previous versions (only keep latest release)
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<classpath>
- <classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
- <classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
- <classpathentry kind="src" path="src"/>
- <classpathentry kind="src" path="gen"/>
- <classpathentry kind="lib" path="libs/android-support-v4.jar"/>
- <classpathentry kind="lib" path="libs/altoslib_1.jar"/>
- <classpathentry kind="output" path="bin/classes"/>
-</classpath>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<launchConfiguration type="org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType">
-<stringAttribute key="org.eclipse.debug.core.ATTR_REFRESH_SCOPE" value="${working_set:<?xml version="1.0" encoding="UTF-8"?> <resources> <item path="/AltosDroid/src/org/altusmetrum/AltosDroid/BuildInfo.java" type="1"/> </resources>}"/>
-<booleanAttribute key="org.eclipse.debug.core.capture_output" value="false"/>
-<booleanAttribute key="org.eclipse.debug.ui.ATTR_CONSOLE_OUTPUT_ON" value="false"/>
-<booleanAttribute key="org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND" value="false"/>
-<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/AltosDroid/buildinfo.sh}"/>
-<stringAttribute key="org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS" value="full,incremental,auto,"/>
-<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/>
-<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/AltosDroid}"/>
-</launchConfiguration>
+.gradle
+.idea
+build/
+app/build/
+app/libs/
+app/app.iml
+altosdroid.iml
local.properties
-bin
-gen
-libs
-google-play-services_lib
-src/org/altusmetrum/AltosDroid/BuildInfo.java
-res/drawable/*led.png
-AndroidManifest.xml
+app/src/main/AndroidManifest.xml
+app/src/main/java/org/altusmetrum/AltosDroid/BuildInfo.java
+app/src/main/res/drawable/*led.png
+++ /dev/null
-#Wed Sep 28 19:51:24 NZDT 2011
-eclipse.preferences.version=1
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
-org.eclipse.jdt.core.compiler.compliance=1.5
-org.eclipse.jdt.core.compiler.source=1.5
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-
- 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; 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.
-
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="org.altusmetrum.AltosDroid"
- android:versionCode="@ANDROID_VERSION@"
- android:versionName="@VERSION@">
- <uses-sdk android:targetSdkVersion="12" android:minSdkVersion="12"/>
- <!-- Google Maps -->
- <uses-feature android:glEsVersion="0x00020000" android:required="true"/>
-
- <!-- Permissions needed to access bluetooth -->
- <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
- <uses-permission android:name="android.permission.BLUETOOTH" />
- <!-- Permissions needed to save Telemetry logs to SD card -->
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- <!-- Permissions needed for GoogleMaps -->
- <uses-permission android:name="android.permission.INTERNET"/>
- <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES"/>
- <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
-
- <permission android:name="org.altusmetrum.AltosDroid.permission.MAPS_RECEIVE"
- android:protectionLevel="signature"/>
- <uses-permission android:name="org.altusmetrum.AltosDroid.permission.MAPS_RECEIVE"/>
-
- <!-- Permissions needed to access USB OTG -->
- <uses-feature android:name="android.hardware.usb.host" android:required="false" />
-
- <application android:label="@string/app_name"
- android:icon="@drawable/app_icon"
- android:allowBackup="true"
- android:theme="@style/CustomTheme">
- <activity android:name="org.altusmetrum.AltosDroid.AltosDroid"
- android:label="@string/app_name"
- android:configChanges="orientation|keyboardHidden"
- android:launchMode="singleTop">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
-
- <activity android:name="org.altusmetrum.AltosDroid.AltosDroid"
- android:configChanges="orientation|keyboardHidden"
- android:launchMode="singleTop">
- <intent-filter>
- <action
- android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"/>
- </intent-filter>
- <meta-data
- android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
- android:resource="@xml/device_filter" />
- </activity>
-
- <activity android:name=".DeviceListActivity"
- android:label="@string/select_device"
- android:theme="@android:style/Theme.Dialog"
- android:configChanges="orientation|keyboardHidden" />
-
- <activity android:name=".PreloadMapActivity"
- android:label="@string/preload_maps"
- android:theme="@android:style/Theme.Dialog"
- android:configChanges="orientation|keyboardHidden" />
-
- <activity android:name=".MapTypeActivity"
- android:label="@string/map_type"
- android:theme="@android:style/Theme.Dialog"
- android:configChanges="orientation|keyboardHidden" />
-
- <activity android:name=".IdleModeActivity"
- android:label="@string/idle_mode"
- android:theme="@android:style/Theme.Dialog"
- android:configChanges="orientation|keyboardHidden" />
-
- <activity android:name=".IgniterActivity"
- android:label="@string/igniters"
- android:theme="@android:style/Theme.Dialog"
- android:configChanges="orientation|keyboardHidden" />
-
- <activity android:name=".SetupActivity"
- android:label="@string/setup"
- android:theme="@android:style/Theme.Dialog"
- android:configChanges="orientation" />
-
- <activity android:name=".ManageFrequenciesActivity"
- android:label="@string/manage_frequencies"
- android:theme="@android:style/Theme.Dialog"
- android:configChanges="orientation|keyboard" />
-
- <service android:name=".TelemetryService" />
-
- <meta-data android:name="com.google.android.maps.v2.API_KEY"
- android:value="@GOOGLEKEY@"/>
- <meta-data android:name="com.google.android.gms.version"
- android:value="@integer/google_play_services_version" />
- </application>
-</manifest>
+DBG_APK=app/build/outputs/apk/debug/app-debug.apk
+REL_APK=app/build/outputs/apk/release/app-release.apk
+
if ANDROID
-all_target=bin/AltosDroid-debug.apk
+all_target=$(DBG_APK)
if ANDROID_RELEASE
-all_target+=bin/AltosDroid-release.apk
+all_target+=$(REL_APK)
endif
else
all_target=
ZIPALIGN_A=$(SDK)/tools/zipalign
ZIPALIGN_B=$(shell ls $(SDK)/build-tools/*/zipalign | tail -1)
-JAVA_SRC_DIR=src/org/altusmetrum/AltosDroid
-EXT_LIBDIR=libs
-DRAWABLE_DIR=res/drawable
-LAYOUT_DIR=res/layout
-MENU_DIR=res/menu
-VALUES_DIR=res/values
-XML_DIR=res/xml
+JAVA_SRC_DIR=app/src/main/java/org/altusmetrum/AltosDroid
+EXT_LIBDIR=app/libs
+RES_DIR=app/src/main/res
+DRAWABLE_DIR=$(RES_DIR)/drawable
+LAYOUT_DIR=$(RES_DIR)/layout
+MENU_DIR=$(RES_DIR)/menu
+VALUES_DIR=$(RES_DIR)/values
+XML_DIR=$(RES_DIR)/xml
ALTOSLIB_SRCDIR=../altoslib
ALTOSLIB_JAR=altoslib_$(ALTOSLIB_VERSION).jar
ALTOSLIB=$(EXT_LIBDIR)/$(ALTOSLIB_JAR)
-SUPPORT_V4_SRCDIR=$(SDK)/extras/android/support/v4
-SUPPORT_V4_JAR=android-support-v4.jar
-
-SUPPORT_V4=$(EXT_LIBDIR)/$(SUPPORT_V4_JAR)
-
-GOOGLE_PLAY_SERVICES_LIB_SRCDIR=$(SDK)/extras/google/google_play_services/libproject
-GOOGLE_PLAY_SERVICES_LIB=google-play-services_lib
-
JAVA_SRC=$(JAVA_SRC_DIR)/*.java $(JAVA_SRC_DIR)/BuildInfo.java
DRAWABLES=\
$(DRAWABLE_DIR)/greenled.png \
$(DRAWABLE_DIR)/grayled.png
+GRADLEW=bash ./gradlew --no-daemon
+
LAYOUTS=$(LAYOUT_DIR)/*.xml
MENUS=$(MENU_DIR)/*.xml
VALUES=$(VALUES_DIR)/*.xml
-XMLS=$(XML_DIR)/*.xml AndroidManifest.xml
+XMLS=$(XML_DIR)/*.xml app/src/main/AndroidManifest.xml
RES=$(LAYOUTS) $(MENUS) $(VALUES) $(XMLS)
mkdir -p $(EXT_LIBDIR)
cd $(EXT_LIBDIR) && ln -sf $(shell echo $(EXT_LIBDIR) | sed 's|[^/]\+|..|g')/$(ALTOSLIB_SRCDIR)/$(ALTOSLIB_JAR) .
-$(SUPPORT_V4): $(SUPPORT_V4_SRCDIR)/$(SUPPORT_V4_JAR)
- mkdir -p $(EXT_LIBDIR)
- cd $(EXT_LIBDIR) && ln -sf $(SUPPORT_V4_SRCDIR)/$(SUPPORT_V4_JAR) .
-
-$(GOOGLE_PLAY_SERVICES_LIB): $(GOOGLE_PLAY_SERVICES_LIB_SRCDIR)/$(GOOGLE_PLAY_SERVICES_LIB)
- cp -a $(GOOGLE_PLAY_SERVICES_LIB_SRCDIR)/$(GOOGLE_PLAY_SERVICES_LIB) .
- cd $(GOOGLE_PLAY_SERVICES_LIB) && $(SDK)/tools/android update project --target $(SDK_TARGET) --path .
-
$(JAVA_SRC_DIR)/BuildInfo.java: $(filter-out $(JAVA_SRC_DIR)/BuildInfo.java,$(shell echo $(JAVA_SRC)))
./buildinfo.sh
cd $(DRAWABLE_DIR) && ln -sf $(shell echo $(DRAWABLE_DIR) | sed 's|[^/]\+|..|g')/$< .
if ANDROID
-install-release: bin/AltosDroid-release.apk
- $(ADB) install -r bin/AltosDroid-release.apk
-
-install-debug: bin/AltosDroid-debug.apk
- $(ADB) install -r bin/AltosDroid-debug.apk
-
-bin/AltosDroid-debug.apk: $(SRC) $(ALTOSLIB) $(SUPPORT_V4) $(GOOGLE_PLAY_SERVICES_LIB)
- ant debug
-
-bin/AltosDroid-release-unsigned.apk: $(SRC) $(ALTOSLIB) $(SUPPORT_V4) $(GOOGLE_PLAY_SERVICES_LIB)
- ant release
-
-bin/AltosDroid-release.apk: bin/AltosDroid-release-unsigned.apk
- jarsigner -sigalg SHA1withDSA -digestalg SHA1 \
- -keystore ~/altusmetrumllc/google-play-release.keystore \
- -storepass:file ~/altusmetrumllc/google-play-passphrase \
- -signedjar bin/AltosDroid-release-signed.apk \
- bin/AltosDroid-release-unsigned.apk AltosDroid
- if [ -f $(ZIPALIGN_A) ]; then \
- $(ZIPALIGN_A) -f 4 \
- bin/AltosDroid-release-signed.apk \
- bin/AltosDroid-release.apk; \
- else \
- $(ZIPALIGN_B) -f 4 \
- bin/AltosDroid-release-signed.apk \
- bin/AltosDroid-release.apk; \
- fi
-
-release: bin/AltosDroid-release.apk
+install-release: $(REL_APK)
+ $(ADB) install -r $(REL_APK)
+
+install-debug: $(DBG_APK)
+ $(ADB) install -r $(DBG_APK)
+
+$(DBG_APK): $(SRC) $(ALTOSLIB)
+ $(GRADLEW) assembleDebug
+
+$(REL_APK): $(SRC) $(ALTOSLIB)
+ $(GRADLEW) build
+
+release: $(REL_APK)
clean-local: $(GOOGLE_PLAY_SERVICES_LIB)
- ant clean
+ $(GRADLEW) clean
rm -f $(JAVA_SRC_DIR)/BuildInfo.java
rm -f $(DRAWABLES)
rm -rf $(EXT_LIBDIR)
--- /dev/null
+apply plugin: 'com.android.application'
+
+def keystorePropertiesFile = file(System.properties['user.home'] + "/altusmetrumllc/android_keystore.properties")
+def keystoreProperties = new Properties()
+keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
+
+android {
+ signingConfigs {
+ release {
+ storeFile file(System.properties['user.home'] + "/altusmetrumllc/android_keystore.jks")
+ storePassword keystoreProperties['storePassword']
+ keyAlias keystoreProperties['keyAlias']
+ keyPassword keystoreProperties['keyPassword']
+ }
+ }
+
+ compileSdkVersion 28
+ defaultConfig {
+ applicationId "org.altusmetrum.AltosDroid"
+ minSdkVersion 26
+ targetSdkVersion 28
+ versionCode 19
+ versionName "1.9.1rc1"
+ }
+ buildTypes {
+ release {
+ signingConfig signingConfigs.release
+ minifyEnabled false
+ debuggable false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ debug {
+ debuggable true
+ }
+ }
+ lintOptions {
+ abortOnError false
+ }
+}
+
+dependencies {
+ implementation 'androidx.appcompat:appcompat:1.0.0'
+ implementation 'androidx.legacy:legacy-support-v4:1.0.0'
+ implementation 'com.google.android.gms:play-services-maps:17.0.0'
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
+}
+
--- /dev/null
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+ 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; 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.
+
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="org.altusmetrum.AltosDroid">
+ <!-- Google Maps -->
+ <uses-feature android:glEsVersion="0x00020000" android:required="true"/>
+
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
+
+ <!-- Permissions needed to access bluetooth -->
+ <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
+ <uses-permission android:name="android.permission.BLUETOOTH" />
+ <!-- Permissions needed to save Telemetry logs to SD card -->
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <!-- Permissions needed for GoogleMaps -->
+ <uses-permission android:name="android.permission.INTERNET"/>
+ <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES"/>
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
+
+ <permission android:name="org.altusmetrum.AltosDroid.permission.MAPS_RECEIVE"
+ android:protectionLevel="signature"/>
+ <uses-permission android:name="org.altusmetrum.AltosDroid.permission.MAPS_RECEIVE"/>
+
+ <!-- Permissions needed to access USB OTG -->
+ <uses-feature android:name="android.hardware.usb.host" android:required="false" />
+
+ <application android:label="@string/app_name"
+ android:icon="@drawable/app_icon"
+ android:allowBackup="true"
+ android:theme="@style/CustomTheme">
+
+ <activity android:name="org.altusmetrum.AltosDroid.AltosDroid"
+ android:label="@string/app_name"
+ android:configChanges="orientation|keyboardHidden"
+ android:launchMode="singleTop">
+ <intent-filter>
+ <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.intent.action.VIEW" />
+ <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"/>
+ </intent-filter>
+ <meta-data
+ android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
+ android:resource="@xml/device_filter" />
+ </activity>
+
+ <activity android:name=".DeviceListActivity"
+ android:label="@string/select_device"
+ android:theme="@android:style/Theme.Dialog"
+ android:configChanges="orientation|keyboardHidden" />
+
+ <activity android:name=".PreloadMapActivity"
+ android:label="@string/preload_maps"
+ android:theme="@android:style/Theme.Dialog"
+ android:configChanges="orientation|keyboardHidden" />
+
+ <activity android:name=".MapTypeActivity"
+ android:label="@string/map_type"
+ android:theme="@android:style/Theme.Dialog"
+ android:configChanges="orientation|keyboardHidden" />
+
+ <activity android:name=".IdleModeActivity"
+ android:label="@string/idle_mode"
+ android:theme="@android:style/Theme.Dialog"
+ android:configChanges="orientation|keyboardHidden" />
+
+ <activity android:name=".IgniterActivity"
+ android:label="@string/igniters"
+ android:theme="@android:style/Theme.Dialog"
+ android:configChanges="orientation|keyboardHidden" />
+
+ <activity android:name=".SetupActivity"
+ android:label="@string/setup"
+ android:theme="@android:style/Theme.Dialog"
+ android:configChanges="orientation" />
+
+ <activity android:name=".ManageFrequenciesActivity"
+ android:label="@string/manage_frequencies"
+ android:theme="@android:style/Theme.Dialog"
+ android:configChanges="orientation|keyboard" />
+
+ <service android:name=".TelemetryService" />
+
+ <meta-data android:name="com.google.android.maps.v2.API_KEY"
+ android:value="@GOOGLEKEY@"/>
+ <meta-data android:name="com.google.android.gms.version"
+ android:value="@integer/google_play_services_version" />
+ </application>
+</manifest>
--- /dev/null
+/*
+ * 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; 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.
+ */
+
+package org.altusmetrum.AltosDroid;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.UUID;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothSocket;
+import android.os.Handler;
+
+public class AltosBluetooth extends AltosDroidLink {
+
+ private ConnectThread connect_thread = null;
+
+ private BluetoothDevice device;
+ private BluetoothSocket socket;
+ private InputStream input;
+ private OutputStream output;
+ private boolean pause;
+
+ // Constructor
+ public AltosBluetooth(BluetoothDevice device, Handler handler, boolean pause) {
+ super(handler);
+ this.device = device;
+ this.handler = handler;
+ this.pause = pause;
+
+ connect_thread = new ConnectThread();
+ connect_thread.start();
+ }
+
+ void connected() {
+ if (closed()) {
+ AltosDebug.debug("connected after closed");
+ return;
+ }
+
+ AltosDebug.check_ui("connected\n");
+ try {
+ synchronized(this) {
+ if (socket != null) {
+ input = socket.getInputStream();
+ output = socket.getOutputStream();
+ super.connected();
+ }
+ }
+ } catch (InterruptedException ie) {
+ connect_failed();
+ } catch (IOException io) {
+ connect_failed();
+ }
+ }
+
+ private void connect_failed() {
+ if (closed()) {
+ AltosDebug.debug("connect_failed after closed");
+ return;
+ }
+
+ close_device();
+ input = null;
+ output = null;
+ handler.obtainMessage(TelemetryService.MSG_CONNECT_FAILED, this).sendToTarget();
+ AltosDebug.error("ConnectThread: Failed to establish connection");
+ }
+
+ void close_device() {
+ BluetoothSocket tmp_socket;
+
+ synchronized(this) {
+ tmp_socket = socket;
+ socket = null;
+ }
+
+ if (tmp_socket != null) {
+ try {
+ tmp_socket.close();
+ } catch (IOException e) {
+ AltosDebug.error("close_socket failed");
+ }
+ }
+ }
+
+ public void close() {
+ super.close();
+ input = null;
+ output = null;
+ }
+
+ private final UUID SPP_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
+
+ private void create_socket(BluetoothDevice device) {
+
+ BluetoothSocket tmp_socket = null;
+
+ AltosDebug.check_ui("create_socket\n");
+ try {
+ tmp_socket = device.createInsecureRfcommSocketToServiceRecord(SPP_UUID);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ if (socket != null) {
+ AltosDebug.debug("Socket already allocated %s", socket.toString());
+ close_device();
+ }
+ synchronized (this) {
+ socket = tmp_socket;
+ }
+ }
+
+ private class ConnectThread extends Thread {
+
+ public void run() {
+ AltosDebug.debug("ConnectThread: BEGIN (pause %b)", pause);
+ setName("ConnectThread");
+
+ if (pause) {
+ try {
+ Thread.sleep(4000);
+ } catch (InterruptedException e) {
+ }
+ }
+
+ create_socket(device);
+ // Always cancel discovery because it will slow down a connection
+ try {
+ BluetoothAdapter.getDefaultAdapter().cancelDiscovery();
+ } catch (Exception e) {
+ AltosDebug.debug("cancelDiscovery exception %s", e.toString());
+ }
+
+ BluetoothSocket local_socket = null;
+
+ synchronized (AltosBluetooth.this) {
+ if (!closed())
+ local_socket = socket;
+ }
+
+ if (local_socket != null) {
+ try {
+ // Make a connection to the BluetoothSocket
+ // This is a blocking call and will only return on a
+ // successful connection or an exception
+ local_socket.connect();
+ } catch (Exception e) {
+ AltosDebug.debug("Connect exception %s", e.toString());
+ try {
+ local_socket.close();
+ } catch (Exception ce) {
+ AltosDebug.debug("Close exception %s", ce.toString());
+ }
+ local_socket = null;
+ }
+ }
+
+ if (local_socket != null) {
+ connected();
+ } else {
+ connect_failed();
+ }
+
+ AltosDebug.debug("ConnectThread: completed");
+ }
+ }
+
+ private synchronized void wait_connected() throws InterruptedException, IOException {
+ AltosDebug.check_ui("wait_connected\n");
+ if (input == null && socket != null) {
+ AltosDebug.debug("wait_connected...");
+ wait();
+ AltosDebug.debug("wait_connected done");
+ }
+ if (socket == null)
+ throw new IOException();
+ }
+
+ int write(byte[] buffer, int len) {
+ if (output == null)
+ return -1;
+ try {
+ output.write(buffer, 0, len);
+ } catch (IOException ie) {
+ return -1;
+ }
+ return len;
+ }
+
+ int read(byte[] buffer, int len) {
+ if (input == null)
+ return -1;
+ try {
+ return input.read(buffer, 0, len);
+ } catch (IOException ie) {
+ return -1;
+ }
+ }
+
+ // Stubs of required methods when extending AltosLink
+ public boolean can_cancel_reply() { return false; }
+ public boolean show_reply_timeout() { return true; }
+ public void hide_reply_timeout() { }
+
+}
--- /dev/null
+/*
+ * Copyright © 2015 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.
+ */
+package org.altusmetrum.AltosDroid;
+
+import java.lang.*;
+
+import android.content.*;
+import android.util.Log;
+import android.os.*;
+import android.content.pm.*;
+
+public class AltosDebug {
+ // Debugging
+ static final String TAG = "AltosDroid";
+
+ static boolean D = true;
+
+ static void init(Context context) {
+ ApplicationInfo app_info = context.getApplicationInfo();
+
+ if ((app_info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
+ Log.d(TAG, "Enable debugging\n");
+ D = true;
+ } else {
+ Log.d(TAG, "Disable debugging\n");
+ D = false;
+ }
+ }
+
+
+ static void info(String format, Object ... arguments) {
+ Log.i(TAG, String.format(format, arguments));
+ }
+
+ static void debug(String format, Object ... arguments) {
+ if (D)
+ Log.d(TAG, String.format(format, arguments));
+ }
+
+ static void error(String format, Object ... arguments) {
+ Log.e(TAG, String.format(format, arguments));
+ }
+
+ static void check_ui(String format, Object ... arguments) {
+ if (Looper.myLooper() == Looper.getMainLooper()) {
+ Log.e(TAG, String.format("ON UI THREAD " + format, arguments));
+ for (StackTraceElement el : Thread.currentThread().getStackTrace())
+ Log.e(TAG, "\t" + el.toString() + "\n");
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2012-2013 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; 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.
+ */
+
+package org.altusmetrum.AltosDroid;
+
+import java.lang.ref.WeakReference;
+import java.util.*;
+
+import android.app.Activity;
+import android.app.PendingIntent;
+import android.bluetooth.BluetoothAdapter;
+import android.content.Intent;
+import android.content.Context;
+import android.content.ComponentName;
+import android.content.ServiceConnection;
+import android.content.DialogInterface;
+import android.os.IBinder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+import androidx.fragment.app.FragmentActivity;
+import androidx.fragment.app.FragmentManager;
+import android.view.*;
+import android.widget.*;
+import android.app.AlertDialog;
+import android.location.Location;
+import android.location.LocationManager;
+import android.location.LocationListener;
+import android.hardware.usb.*;
+
+import org.altusmetrum.altoslib_13.*;
+
+class SavedState {
+ long received_time;
+ int state;
+ boolean locked;
+ String callsign;
+ int serial;
+ int flight;
+ int rssi;
+
+ SavedState(AltosState state) {
+ received_time = state.received_time;
+ this.state = state.state();
+ if (state.gps != null)
+ locked = state.gps.locked;
+ else
+ locked = false;
+ callsign = state.cal_data().callsign;
+ serial = state.cal_data().serial;
+ flight = state.cal_data().flight;
+ rssi = state.rssi;
+ }
+}
+
+class Tracker implements CharSequence, Comparable {
+ int serial;
+ String call;
+ double frequency;
+
+ String display;
+
+ public Tracker(int serial, String call, double frequency) {
+ if (call == null)
+ call = "none";
+
+ this.serial = serial;
+ this.call = call;
+ this.frequency = frequency;
+ if (frequency == 0.0)
+ display = "Auto";
+ else if (frequency == AltosLib.MISSING) {
+ display = String.format("%-8.8s %6d", call, serial);
+ } else {
+ display = String.format("%-8.8s %7.3f %6d", call, frequency, serial);
+ }
+ }
+
+ public Tracker(AltosState s) {
+ this(s == null ? 0 : s.cal_data().serial,
+ s == null ? null : s.cal_data().callsign,
+ s == null ? 0.0 : s.frequency);
+ }
+
+ /* CharSequence */
+ public char charAt(int index) {
+ return display.charAt(index);
+ }
+
+ public int length() {
+ return display.length();
+ }
+
+ public CharSequence subSequence(int start, int end) throws IndexOutOfBoundsException {
+ return display.subSequence(start, end);
+ }
+
+ public String toString() {
+ return display.toString();
+ }
+
+ /* Comparable */
+ public int compareTo (Object other) {
+ Tracker o = (Tracker) other;
+ if (frequency == 0.0) {
+ if (o.frequency == 0.0)
+ return 0;
+ return -1;
+ }
+ if (o.frequency == 0.0)
+ return 1;
+
+ int a = serial - o.serial;
+ int b = call.compareTo(o.call);
+ int c = (int) Math.signum(frequency - o.frequency);
+
+ if (b != 0)
+ return b;
+ if (c != 0)
+ return c;
+ return a;
+ }
+}
+
+public class AltosDroid extends FragmentActivity implements AltosUnitsListener, LocationListener {
+
+ // Actions sent to the telemetry server at startup time
+
+ public static final String ACTION_BLUETOOTH = "org.altusmetrum.AltosDroid.BLUETOOTH";
+ public static final String ACTION_USB = "org.altusmetrum.AltosDroid.USB";
+
+ // Message types received by our Handler
+
+ public static final int MSG_STATE = 1;
+ public static final int MSG_UPDATE_AGE = 2;
+ public static final int MSG_IDLE_MODE = 3;
+ public static final int MSG_IGNITER_STATUS = 4;
+
+ // Intent request codes
+ public static final int REQUEST_CONNECT_DEVICE = 1;
+ public static final int REQUEST_ENABLE_BT = 2;
+ public static final int REQUEST_PRELOAD_MAPS = 3;
+ public static final int REQUEST_IDLE_MODE = 5;
+ public static final int REQUEST_IGNITERS = 6;
+ public static final int REQUEST_SETUP = 7;
+
+ public static final String EXTRA_IDLE_MODE = "idle_mode";
+ public static final String EXTRA_IDLE_RESULT = "idle_result";
+ public static final String EXTRA_TELEMETRY_SERVICE = "telemetry_service";
+
+ // Setup result bits
+ public static final int SETUP_BAUD = 1;
+ public static final int SETUP_UNITS = 2;
+ public static final int SETUP_MAP_SOURCE = 4;
+ public static final int SETUP_MAP_TYPE = 8;
+
+ public static FragmentManager fm;
+
+ private BluetoothAdapter mBluetoothAdapter = null;
+
+ // Flight state values
+ private TextView mCallsignView;
+ private TextView mRSSIView;
+ private TextView mSerialView;
+ private TextView mFlightView;
+ private RelativeLayout mStateLayout;
+ private TextView mStateView;
+ private TextView mAgeView;
+ private boolean mAgeViewOld;
+ private int mAgeNewColor;
+ private int mAgeOldColor;
+
+ public static final String tab_pad_name = "pad";
+ public static final String tab_flight_name = "flight";
+ public static final String tab_recover_name = "recover";
+ public static final String tab_map_name = "map";
+
+ // field to display the version at the bottom of the screen
+ private TextView mVersion;
+
+ private boolean idle_mode = false;
+
+ public Location location = null;
+
+ private AltosState state;
+ private SavedState saved_state;
+
+ // Tabs
+ TabHost mTabHost;
+ AltosViewPager mViewPager;
+ TabsAdapter mTabsAdapter;
+ ArrayList<AltosDroidTab> mTabs = new ArrayList<AltosDroidTab>();
+ int tabHeight;
+
+ // Timer and Saved flight state for Age calculation
+ private Timer timer;
+
+ TelemetryState telemetry_state;
+ Tracker[] trackers;
+
+
+ UsbDevice pending_usb_device;
+ boolean start_with_usb;
+
+ // Service
+ private boolean mIsBound = false;
+ private Messenger mService = null;
+ final Messenger mMessenger = new Messenger(new IncomingHandler(this));
+
+ // Text to Speech
+ private AltosVoice mAltosVoice = null;
+
+ // The Handler that gets information back from the Telemetry Service
+ static class IncomingHandler extends Handler {
+ private final WeakReference<AltosDroid> mAltosDroid;
+ IncomingHandler(AltosDroid ad) { mAltosDroid = new WeakReference<AltosDroid>(ad); }
+
+ @Override
+ public void handleMessage(Message msg) {
+ AltosDroid ad = mAltosDroid.get();
+
+ switch (msg.what) {
+ case MSG_STATE:
+ if (msg.obj == null) {
+ AltosDebug.debug("telemetry_state null!");
+ return;
+ }
+ ad.update_state((TelemetryState) msg.obj);
+ break;
+ case MSG_UPDATE_AGE:
+ ad.update_age();
+ break;
+ case MSG_IDLE_MODE:
+ ad.idle_mode = (Boolean) msg.obj;
+ ad.update_state(null);
+ break;
+ }
+ }
+ };
+
+
+ private ServiceConnection mConnection = new ServiceConnection() {
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ mService = new Messenger(service);
+ try {
+ Message msg = Message.obtain(null, TelemetryService.MSG_REGISTER_CLIENT);
+ msg.replyTo = mMessenger;
+ mService.send(msg);
+ } catch (RemoteException e) {
+ // In this case the service has crashed before we could even do anything with it
+ }
+ if (pending_usb_device != null) {
+ try {
+ mService.send(Message.obtain(null, TelemetryService.MSG_OPEN_USB, pending_usb_device));
+ pending_usb_device = null;
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
+ public void onServiceDisconnected(ComponentName className) {
+ // This is called when the connection with the service has been unexpectedly disconnected - process crashed.
+ mService = null;
+ }
+ };
+
+ void doBindService() {
+ bindService(new Intent(this, TelemetryService.class), mConnection, Context.BIND_AUTO_CREATE);
+ mIsBound = true;
+ }
+
+ void doUnbindService() {
+ if (mIsBound) {
+ // If we have received the service, and hence registered with it, then now is the time to unregister.
+ if (mService != null) {
+ try {
+ Message msg = Message.obtain(null, TelemetryService.MSG_UNREGISTER_CLIENT);
+ msg.replyTo = mMessenger;
+ mService.send(msg);
+ } catch (RemoteException e) {
+ // There is nothing special we need to do if the service has crashed.
+ }
+ }
+ // Detach our existing connection.
+ unbindService(mConnection);
+ mIsBound = false;
+ }
+ }
+
+ public void registerTab(AltosDroidTab mTab) {
+ mTabs.add(mTab);
+ }
+
+ public void unregisterTab(AltosDroidTab mTab) {
+ mTabs.remove(mTab);
+ }
+
+ public void units_changed(boolean imperial_units) {
+ for (AltosDroidTab mTab : mTabs)
+ mTab.units_changed(imperial_units);
+ }
+
+ void update_title(TelemetryState telemetry_state) {
+ switch (telemetry_state.connect) {
+ case TelemetryState.CONNECT_CONNECTED:
+ if (telemetry_state.config != null) {
+ String str = String.format("S/N %d %6.3f MHz%s", telemetry_state.config.serial,
+ telemetry_state.frequency, idle_mode ? " (idle)" : "");
+ if (telemetry_state.telemetry_rate != AltosLib.ao_telemetry_rate_38400)
+ str = str.concat(String.format(" %d bps",
+ AltosLib.ao_telemetry_rate_values[telemetry_state.telemetry_rate]));
+ setTitle(str);
+ } else {
+ setTitle(R.string.title_connected_to);
+ }
+ break;
+ case TelemetryState.CONNECT_CONNECTING:
+ if (telemetry_state.address != null)
+ setTitle(String.format("Connecting to %s...", telemetry_state.address.name));
+ else
+ setTitle("Connecting to something...");
+ break;
+ case TelemetryState.CONNECT_DISCONNECTED:
+ case TelemetryState.CONNECT_NONE:
+ setTitle(R.string.title_not_connected);
+ break;
+ }
+ }
+
+ void start_timer() {
+ if (timer == null) {
+ timer = new Timer();
+ timer.scheduleAtFixedRate(new TimerTask(){ public void run() {onTimerTick();}}, 1000L, 1000L);
+ }
+ }
+
+ void stop_timer() {
+ if (timer != null) {
+ timer.cancel();
+ timer.purge();
+ timer = null;
+ }
+ }
+
+ int selected_serial = 0;
+ int current_serial;
+ long switch_time;
+
+ void set_switch_time() {
+ switch_time = System.currentTimeMillis();
+ selected_serial = 0;
+ }
+
+ boolean registered_units_listener;
+
+ void update_state(TelemetryState new_telemetry_state) {
+
+ if (new_telemetry_state != null)
+ telemetry_state = new_telemetry_state;
+
+ if (selected_serial != 0)
+ current_serial = selected_serial;
+
+ if (current_serial == 0)
+ current_serial = telemetry_state.latest_serial;
+
+ if (!registered_units_listener) {
+ registered_units_listener = true;
+ AltosPreferences.register_units_listener(this);
+ }
+
+ int num_trackers = 0;
+ for (AltosState s : telemetry_state.states.values()) {
+ num_trackers++;
+ }
+
+ trackers = new Tracker[num_trackers + 1];
+
+ int n = 0;
+ trackers[n++] = new Tracker(0, "auto", 0.0);
+
+ for (AltosState s : telemetry_state.states.values())
+ trackers[n++] = new Tracker(s);
+
+ Arrays.sort(trackers);
+
+ update_title(telemetry_state);
+
+ AltosState state = null;
+ boolean aged = true;
+
+ if (telemetry_state.states.containsKey(current_serial)) {
+ state = telemetry_state.states.get(current_serial);
+ int age = state_age(state.received_time);
+ if (age < 20)
+ aged = false;
+ if (current_serial == selected_serial)
+ aged = false;
+ else if (switch_time != 0 && (switch_time - state.received_time) > 0)
+ aged = true;
+ }
+
+ if (aged) {
+ AltosState newest_state = null;
+ int newest_age = 0;
+
+ for (int serial : telemetry_state.states.keySet()) {
+ AltosState existing = telemetry_state.states.get(serial);
+ int existing_age = state_age(existing.received_time);
+
+ if (newest_state == null || existing_age < newest_age) {
+ newest_state = existing;
+ newest_age = existing_age;
+ }
+ }
+
+ if (newest_state != null)
+ state = newest_state;
+ }
+
+ update_ui(telemetry_state, state, telemetry_state.quiet);
+
+ start_timer();
+ }
+
+ boolean same_string(String a, String b) {
+ if (a == null) {
+ if (b == null)
+ return true;
+ return false;
+ } else {
+ if (b == null)
+ return false;
+ return a.equals(b);
+ }
+ }
+
+
+ private int blend_component(int a, int b, double r, int shift, int mask) {
+ return ((int) (((a >> shift) & mask) * r + ((b >> shift) & mask) * (1 - r)) & mask) << shift;
+ }
+ private int blend_color(int a, int b, double r) {
+ return (blend_component(a, b, r, 0, 0xff) |
+ blend_component(a, b, r, 8, 0xff) |
+ blend_component(a, b, r, 16, 0xff) |
+ blend_component(a, b, r, 24, 0xff));
+ }
+
+ int state_age(long received_time) {
+ return (int) ((System.currentTimeMillis() - received_time + 500) / 1000);
+ }
+
+ void set_screen_on(int age) {
+ if (age < 60)
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ else
+ getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ }
+
+ void update_age() {
+ if (saved_state != null) {
+ int age = state_age(saved_state.received_time);
+
+ double age_scale = age / 100.0;
+
+ if (age_scale > 1.0)
+ age_scale = 1.0;
+
+ mAgeView.setTextColor(blend_color(mAgeOldColor, mAgeNewColor, age_scale));
+
+ set_screen_on(age);
+
+ String text;
+ if (age < 60)
+ text = String.format("%ds", age);
+ else if (age < 60 * 60)
+ text = String.format("%dm", age / 60);
+ else if (age < 60 * 60 * 24)
+ text = String.format("%dh", age / (60 * 60));
+ else
+ text = String.format("%dd", age / (24 * 60 * 60));
+ mAgeView.setText(text);
+ }
+ }
+
+ void update_ui(TelemetryState telem_state, AltosState state, boolean quiet) {
+
+ this.state = state;
+
+ int prev_state = AltosLib.ao_flight_invalid;
+
+ AltosGreatCircle from_receiver = null;
+
+ if (saved_state != null)
+ prev_state = saved_state.state;
+
+ if (state != null) {
+ set_screen_on(state_age(state.received_time));
+
+ if (state.state() == AltosLib.ao_flight_stateless) {
+ boolean prev_locked = false;
+ boolean locked = false;
+
+ if(state.gps != null)
+ locked = state.gps.locked;
+ if (saved_state != null)
+ prev_locked = saved_state.locked;
+ if (prev_locked != locked) {
+ String currentTab = mTabHost.getCurrentTabTag();
+ if (locked) {
+ if (currentTab.equals(tab_pad_name)) mTabHost.setCurrentTabByTag(tab_flight_name);
+ } else {
+ if (currentTab.equals(tab_flight_name)) mTabHost.setCurrentTabByTag(tab_pad_name);
+ }
+ }
+ } else {
+ if (prev_state != state.state()) {
+ String currentTab = mTabHost.getCurrentTabTag();
+ switch (state.state()) {
+ case AltosLib.ao_flight_boost:
+ if (currentTab.equals(tab_pad_name)) mTabHost.setCurrentTabByTag(tab_flight_name);
+ break;
+ case AltosLib.ao_flight_landed:
+ if (currentTab.equals(tab_flight_name)) mTabHost.setCurrentTabByTag(tab_recover_name);
+ break;
+ case AltosLib.ao_flight_stateless:
+ if (currentTab.equals(tab_pad_name)) mTabHost.setCurrentTabByTag(tab_flight_name);
+ break;
+ }
+ }
+ }
+
+ if (location != null && state.gps != null && state.gps.locked) {
+ double altitude = 0;
+ if (location.hasAltitude())
+ altitude = location.getAltitude();
+ from_receiver = new AltosGreatCircle(location.getLatitude(),
+ location.getLongitude(),
+ altitude,
+ state.gps.lat,
+ state.gps.lon,
+ state.gps.alt);
+ }
+
+ if (saved_state == null || !same_string(saved_state.callsign, state.cal_data().callsign)) {
+ mCallsignView.setText(state.cal_data().callsign);
+ }
+ if (saved_state == null || state.cal_data().serial != saved_state.serial) {
+ if (state.cal_data().serial == AltosLib.MISSING)
+ mSerialView.setText("");
+ else
+ mSerialView.setText(String.format("%d", state.cal_data().serial));
+ }
+ if (saved_state == null || state.cal_data().flight != saved_state.flight) {
+ if (state.cal_data().flight == AltosLib.MISSING)
+ mFlightView.setText("");
+ else
+ mFlightView.setText(String.format("%d", state.cal_data().flight));
+ }
+ if (saved_state == null || state.state() != saved_state.state) {
+ if (state.state() == AltosLib.ao_flight_stateless) {
+ mStateLayout.setVisibility(View.GONE);
+ } else {
+ mStateView.setText(state.state_name());
+ mStateLayout.setVisibility(View.VISIBLE);
+ }
+ }
+ if (saved_state == null || state.rssi != saved_state.rssi) {
+ if (state.rssi == AltosLib.MISSING)
+ mRSSIView.setText("");
+ else
+ mRSSIView.setText(String.format("%d", state.rssi));
+ }
+ saved_state = new SavedState(state);
+ }
+
+ for (AltosDroidTab mTab : mTabs)
+ mTab.update_ui(telem_state, state, from_receiver, location, mTab == mTabsAdapter.currentItem());
+
+ AltosDebug.debug("quiet %b\n", quiet);
+ if (mAltosVoice != null && mTabsAdapter.currentItem() != null)
+ mAltosVoice.tell(telem_state, state, from_receiver, location, (AltosDroidTab) mTabsAdapter.currentItem(), quiet);
+
+ }
+
+ private void onTimerTick() {
+ try {
+ mMessenger.send(Message.obtain(null, MSG_UPDATE_AGE));
+ } catch (RemoteException e) {
+ }
+ }
+
+ static String pos(double p, String pos, String neg) {
+ String h = pos;
+ if (p == AltosLib.MISSING)
+ return "";
+ if (p < 0) {
+ h = neg;
+ p = -p;
+ }
+ int deg = (int) Math.floor(p);
+ double min = (p - Math.floor(p)) * 60.0;
+ return String.format("%d°%9.4f\" %s", deg, min, h);
+ }
+
+ static String number(String format, double value) {
+ if (value == AltosLib.MISSING)
+ return "";
+ return String.format(format, value);
+ }
+
+ static String integer(String format, int value) {
+ if (value == AltosLib.MISSING)
+ return "";
+ return String.format(format, value);
+ }
+
+ private View create_tab_view(String label) {
+ LayoutInflater inflater = (LayoutInflater) this.getLayoutInflater();
+ View tab_view = inflater.inflate(R.layout.tab_layout, null);
+ TextView text_view = (TextView) tab_view.findViewById (R.id.tabLabel);
+ text_view.setText(label);
+ return tab_view;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ AltosDebug.init(this);
+ AltosDebug.debug("+++ ON CREATE +++");
+
+ // Initialise preferences
+ AltosDroidPreferences.init(this);
+
+ fm = getSupportFragmentManager();
+
+ // Set up the window layout
+ setContentView(R.layout.altosdroid);
+
+ // Create the Tabs and ViewPager
+ mTabHost = (TabHost)findViewById(android.R.id.tabhost);
+ mTabHost.setup();
+
+ mViewPager = (AltosViewPager)findViewById(R.id.pager);
+ mViewPager.setOffscreenPageLimit(4);
+
+ mTabsAdapter = new TabsAdapter(this, mTabHost, mViewPager);
+
+ mTabsAdapter.addTab(mTabHost.newTabSpec(tab_pad_name).setIndicator(create_tab_view("Pad")), TabPad.class, null);
+ mTabsAdapter.addTab(mTabHost.newTabSpec(tab_flight_name).setIndicator(create_tab_view("Flight")), TabFlight.class, null);
+ mTabsAdapter.addTab(mTabHost.newTabSpec(tab_recover_name).setIndicator(create_tab_view("Recover")), TabRecover.class, null);
+ mTabsAdapter.addTab(mTabHost.newTabSpec(tab_map_name).setIndicator(create_tab_view("Map")), TabMap.class, null);
+
+ // Display the Version
+ mVersion = (TextView) findViewById(R.id.version);
+ mVersion.setText("Version: " + BuildInfo.version +
+ " Built: " + BuildInfo.builddate + " " + BuildInfo.buildtime + " " + BuildInfo.buildtz +
+ " (" + BuildInfo.branch + "-" + BuildInfo.commitnum + "-" + BuildInfo.commithash + ")");
+
+ mCallsignView = (TextView) findViewById(R.id.callsign_value);
+ mRSSIView = (TextView) findViewById(R.id.rssi_value);
+ mSerialView = (TextView) findViewById(R.id.serial_value);
+ mFlightView = (TextView) findViewById(R.id.flight_value);
+ mStateLayout = (RelativeLayout) findViewById(R.id.state_container);
+ mStateView = (TextView) findViewById(R.id.state_value);
+ mAgeView = (TextView) findViewById(R.id.age_value);
+ mAgeNewColor = mAgeView.getTextColors().getDefaultColor();
+ mAgeOldColor = getResources().getColor(R.color.old_color);
+ }
+
+ private void ensureBluetooth() {
+ // Get local Bluetooth adapter
+ mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+
+ /* if there is a BT adapter and it isn't turned on, then turn it on */
+ if (mBluetoothAdapter != null && !mBluetoothAdapter.isEnabled()) {
+ Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
+ startActivityForResult(enableIntent, AltosDroid.REQUEST_ENABLE_BT);
+ }
+ }
+
+ private boolean check_usb() {
+ UsbDevice device = AltosUsb.find_device(this, AltosLib.product_basestation);
+
+ if (device != null) {
+ Intent i = new Intent(this, AltosDroid.class);
+ PendingIntent pi = PendingIntent.getActivity(this, 0, new Intent("hello world", null, this, AltosDroid.class), 0);
+
+ if (AltosUsb.request_permission(this, device, pi)) {
+ connectUsb(device);
+ }
+ start_with_usb = true;
+ return true;
+ }
+
+ start_with_usb = false;
+
+ return false;
+ }
+
+ private void noticeIntent(Intent intent) {
+
+ /* Ok, this is pretty convenient.
+ *
+ * When a USB device is plugged in, and our 'hotplug'
+ * intent registration fires, we get an Intent with
+ * EXTRA_DEVICE set.
+ *
+ * When we start up and see a usb device and request
+ * permission to access it, that queues a
+ * PendingIntent, which has the EXTRA_DEVICE added in,
+ * along with the EXTRA_PERMISSION_GRANTED field as
+ * well.
+ *
+ * So, in both cases, we get the device name using the
+ * same call. We check to see if access was granted,
+ * in which case we ignore the device field and do our
+ * usual startup thing.
+ */
+
+ UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
+ boolean granted = intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, true);
+
+ AltosDebug.debug("intent %s device %s granted %s", intent, device, granted);
+
+ if (!granted)
+ device = null;
+
+ if (device != null) {
+ AltosDebug.debug("intent has usb device " + device.toString());
+ connectUsb(device);
+ } else {
+
+ /* 'granted' is only false if this intent came
+ * from the request_permission call and
+ * permission was denied. In which case, we
+ * don't want to loop forever...
+ */
+ if (granted) {
+ AltosDebug.debug("check for a USB device at startup");
+ if (check_usb())
+ return;
+ }
+ AltosDebug.debug("Starting by looking for bluetooth devices");
+ ensureBluetooth();
+ }
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ AltosDebug.debug("++ ON START ++");
+
+ set_switch_time();
+
+ noticeIntent(getIntent());
+
+ // Start Telemetry Service
+ String action = start_with_usb ? ACTION_USB : ACTION_BLUETOOTH;
+
+ startService(new Intent(action, null, AltosDroid.this, TelemetryService.class));
+
+ doBindService();
+
+ if (mAltosVoice == null)
+ mAltosVoice = new AltosVoice(this);
+
+ }
+
+ @Override
+ public void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
+ AltosDebug.debug("onNewIntent");
+ noticeIntent(intent);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ AltosDebug.debug("+ ON RESUME +");
+
+ // Listen for GPS and Network position updates
+ LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
+ locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 1, this);
+
+ location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
+
+ if (location != null)
+ AltosDebug.debug("Resume, location is %f,%f\n",
+ location.getLatitude(),
+ location.getLongitude());
+
+ update_ui(telemetry_state, state, true);
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ AltosDebug.debug("- ON PAUSE -");
+ // Stop listening for location updates
+ ((LocationManager) getSystemService(Context.LOCATION_SERVICE)).removeUpdates(this);
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ AltosDebug.debug("-- ON STOP --");
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ AltosDebug.debug("--- ON DESTROY ---");
+
+ doUnbindService();
+ if (mAltosVoice != null) {
+ mAltosVoice.stop();
+ mAltosVoice = null;
+ }
+ stop_timer();
+ }
+
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ AltosDebug.debug("onActivityResult " + resultCode);
+ switch (requestCode) {
+ case REQUEST_CONNECT_DEVICE:
+ // When DeviceListActivity returns with a device to connect to
+ if (resultCode == Activity.RESULT_OK) {
+ connectDevice(data);
+ }
+ break;
+ case REQUEST_ENABLE_BT:
+ // When the request to enable Bluetooth returns
+ if (resultCode == Activity.RESULT_OK) {
+ // Bluetooth is now enabled, so set up a chat session
+ //setupChat();
+ AltosDebug.debug("BT enabled");
+ bluetoothEnabled(data);
+ } else {
+ // User did not enable Bluetooth or an error occured
+ AltosDebug.debug("BT not enabled");
+ }
+ break;
+ case REQUEST_IDLE_MODE:
+ if (resultCode == Activity.RESULT_OK)
+ idle_mode(data);
+ break;
+ case REQUEST_IGNITERS:
+ break;
+ case REQUEST_SETUP:
+ if (resultCode == Activity.RESULT_OK)
+ note_setup_changes(data);
+ break;
+ }
+ }
+
+ private void note_setup_changes(Intent data) {
+ int changes = data.getIntExtra(SetupActivity.EXTRA_SETUP_CHANGES, 0);
+
+ if ((changes & SETUP_BAUD) != 0) {
+ try {
+ mService.send(Message.obtain(null, TelemetryService.MSG_SETBAUD,
+ AltosPreferences.telemetry_rate(1)));
+ } catch (RemoteException re) {
+ }
+ }
+ if ((changes & SETUP_UNITS) != 0) {
+ /* nothing to do here */
+ }
+ if ((changes & SETUP_MAP_SOURCE) != 0) {
+ /* nothing to do here */
+ }
+ if ((changes & SETUP_MAP_TYPE) != 0) {
+ /* nothing to do here */
+ }
+ set_switch_time();
+ }
+
+ private void connectUsb(UsbDevice device) {
+ if (mService == null)
+ pending_usb_device = device;
+ else {
+ // Attempt to connect to the device
+ try {
+ mService.send(Message.obtain(null, TelemetryService.MSG_OPEN_USB, device));
+ AltosDebug.debug("Sent OPEN_USB message");
+ } catch (RemoteException e) {
+ AltosDebug.debug("connect device message failed");
+ }
+ }
+ }
+
+ private void bluetoothEnabled(Intent data) {
+ try {
+ mService.send(Message.obtain(null, TelemetryService.MSG_BLUETOOTH_ENABLED, null));
+ } catch (RemoteException e) {
+ AltosDebug.debug("send BT enabled message failed");
+ }
+ }
+
+ private void connectDevice(Intent data) {
+ // Attempt to connect to the device
+ try {
+ String address = data.getExtras().getString(DeviceListActivity.EXTRA_DEVICE_ADDRESS);
+ String name = data.getExtras().getString(DeviceListActivity.EXTRA_DEVICE_NAME);
+
+ AltosDebug.debug("Connecting to " + address + " " + name);
+ DeviceAddress a = new DeviceAddress(address, name);
+ mService.send(Message.obtain(null, TelemetryService.MSG_CONNECT, a));
+ AltosDebug.debug("Sent connecting message");
+ } catch (RemoteException e) {
+ AltosDebug.debug("connect device message failed");
+ }
+ }
+
+ private void disconnectDevice(boolean remember) {
+ try {
+ mService.send(Message.obtain(null, TelemetryService.MSG_DISCONNECT, (Boolean) remember));
+ } catch (RemoteException e) {
+ }
+ }
+
+ private void idle_mode(Intent data) {
+ int type = data.getIntExtra(IdleModeActivity.EXTRA_IDLE_RESULT, -1);
+ Message msg;
+
+ AltosDebug.debug("intent idle_mode %d", type);
+ switch (type) {
+ case IdleModeActivity.IDLE_MODE_CONNECT:
+ msg = Message.obtain(null, TelemetryService.MSG_MONITOR_IDLE_START);
+ try {
+ mService.send(msg);
+ } catch (RemoteException re) {
+ }
+ break;
+ case IdleModeActivity.IDLE_MODE_DISCONNECT:
+ msg = Message.obtain(null, TelemetryService.MSG_MONITOR_IDLE_STOP);
+ try {
+ mService.send(msg);
+ } catch (RemoteException re) {
+ }
+ break;
+ case IdleModeActivity.IDLE_MODE_REBOOT:
+ msg = Message.obtain(null, TelemetryService.MSG_REBOOT);
+ try {
+ mService.send(msg);
+ } catch (RemoteException re) {
+ }
+ break;
+ case IdleModeActivity.IDLE_MODE_IGNITERS:
+ Intent serverIntent = new Intent(this, IgniterActivity.class);
+ startActivityForResult(serverIntent, REQUEST_IGNITERS);
+ break;
+ }
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ MenuInflater inflater = getMenuInflater();
+ inflater.inflate(R.menu.option_menu, menu);
+ return true;
+ }
+
+ void setFrequency(double freq) {
+ try {
+ mService.send(Message.obtain(null, TelemetryService.MSG_SETFREQUENCY, freq));
+ set_switch_time();
+ } catch (RemoteException e) {
+ }
+ }
+
+ void setFrequency(AltosFrequency frequency) {
+ setFrequency (frequency.frequency);
+ }
+
+ void setBaud(int baud) {
+ try {
+ mService.send(Message.obtain(null, TelemetryService.MSG_SETBAUD, baud));
+ set_switch_time();
+ } catch (RemoteException e) {
+ }
+ }
+
+ void setBaud(String baud) {
+ try {
+ int value = Integer.parseInt(baud);
+ int rate = AltosLib.ao_telemetry_rate_38400;
+ switch (value) {
+ case 2400:
+ rate = AltosLib.ao_telemetry_rate_2400;
+ break;
+ case 9600:
+ rate = AltosLib.ao_telemetry_rate_9600;
+ break;
+ case 38400:
+ rate = AltosLib.ao_telemetry_rate_38400;
+ break;
+ }
+ setBaud(rate);
+ } catch (NumberFormatException e) {
+ }
+ }
+
+ void select_tracker(int serial) {
+ int i;
+
+ AltosDebug.debug("select tracker %d\n", serial);
+
+ if (serial == selected_serial) {
+ AltosDebug.debug("%d already selected\n", serial);
+ return;
+ }
+
+ if (serial != 0) {
+ for (i = 0; i < trackers.length; i++)
+ if (trackers[i].serial == serial)
+ break;
+
+ if (i == trackers.length) {
+ AltosDebug.debug("attempt to select unknown tracker %d\n", serial);
+ return;
+ }
+ }
+
+ current_serial = selected_serial = serial;
+ update_state(null);
+ }
+
+ void touch_trackers(Integer[] serials) {
+ AlertDialog.Builder builder_tracker = new AlertDialog.Builder(this);
+ builder_tracker.setTitle("Select Tracker");
+
+ final Tracker[] my_trackers = new Tracker[serials.length + 1];
+
+ my_trackers[0] = new Tracker(null);
+
+ for (int i = 0; i < serials.length; i++) {
+ AltosState s = telemetry_state.states.get(serials[i]);
+ my_trackers[i+1] = new Tracker(s);
+ }
+ builder_tracker.setItems(my_trackers,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int item) {
+ if (item == 0)
+ select_tracker(0);
+ else
+ select_tracker(my_trackers[item].serial);
+ }
+ });
+ AlertDialog alert_tracker = builder_tracker.create();
+ alert_tracker.show();
+ }
+
+ void delete_track(int serial) {
+ try {
+ mService.send(Message.obtain(null, TelemetryService.MSG_DELETE_SERIAL, (Integer) serial));
+ } catch (Exception ex) {
+ }
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ Intent serverIntent = null;
+ switch (item.getItemId()) {
+ case R.id.connect_scan:
+ ensureBluetooth();
+ // Launch the DeviceListActivity to see devices and do scan
+ serverIntent = new Intent(this, DeviceListActivity.class);
+ startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE);
+ return true;
+ case R.id.disconnect:
+ /* Disconnect the device
+ */
+ disconnectDevice(false);
+ return true;
+ case R.id.quit:
+ AltosDebug.debug("R.id.quit");
+ disconnectDevice(true);
+ finish();
+ return true;
+ case R.id.setup:
+ serverIntent = new Intent(this, SetupActivity.class);
+ startActivityForResult(serverIntent, REQUEST_SETUP);
+ return true;
+ case R.id.select_freq:
+ // Set the TBT radio frequency
+
+ final AltosFrequency[] frequencies = AltosPreferences.common_frequencies();
+ String[] frequency_strings = new String[frequencies.length];
+ for (int i = 0; i < frequencies.length; i++)
+ frequency_strings[i] = frequencies[i].toString();
+
+ AlertDialog.Builder builder_freq = new AlertDialog.Builder(this);
+ builder_freq.setTitle("Pick a frequency");
+ builder_freq.setItems(frequency_strings,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int item) {
+ setFrequency(frequencies[item]);
+ }
+ });
+ AlertDialog alert_freq = builder_freq.create();
+ alert_freq.show();
+ return true;
+ case R.id.select_tracker:
+ if (trackers != null) {
+ AlertDialog.Builder builder_serial = new AlertDialog.Builder(this);
+ builder_serial.setTitle("Select a tracker");
+ builder_serial.setItems(trackers,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int item) {
+ System.out.printf("select item %d %s\n", item, trackers[item].display);
+ if (item == 0)
+ select_tracker(0);
+ else
+ select_tracker(trackers[item].serial);
+ }
+ });
+ AlertDialog alert_serial = builder_serial.create();
+ alert_serial.show();
+
+ }
+ return true;
+ case R.id.delete_track:
+ if (trackers != null) {
+ AlertDialog.Builder builder_serial = new AlertDialog.Builder(this);
+ builder_serial.setTitle("Delete a track");
+ final Tracker[] my_trackers = new Tracker[trackers.length - 1];
+ for (int i = 0; i < trackers.length - 1; i++)
+ my_trackers[i] = trackers[i+1];
+ builder_serial.setItems(my_trackers,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int item) {
+ delete_track(my_trackers[item].serial);
+ }
+ });
+ AlertDialog alert_serial = builder_serial.create();
+ alert_serial.show();
+
+ }
+ return true;
+ case R.id.idle_mode:
+ serverIntent = new Intent(this, IdleModeActivity.class);
+ serverIntent.putExtra(EXTRA_IDLE_MODE, idle_mode);
+ startActivityForResult(serverIntent, REQUEST_IDLE_MODE);
+ return true;
+ }
+ return false;
+ }
+
+ static String direction(AltosGreatCircle from_receiver,
+ Location receiver) {
+ if (from_receiver == null)
+ return null;
+
+ if (receiver == null)
+ return null;
+
+ if (!receiver.hasBearing())
+ return null;
+
+ float bearing = receiver.getBearing();
+ float heading = (float) from_receiver.bearing - bearing;
+
+ while (heading <= -180.0f)
+ heading += 360.0f;
+ while (heading > 180.0f)
+ heading -= 360.0f;
+
+ int iheading = (int) (heading + 0.5f);
+
+ if (-1 < iheading && iheading < 1)
+ return "ahead";
+ else if (iheading < -179 || 179 < iheading)
+ return "backwards";
+ else if (iheading < 0)
+ return String.format("left %d°", -iheading);
+ else
+ return String.format("right %d°", iheading);
+ }
+
+ public void onLocationChanged(Location location) {
+ this.location = location;
+ AltosDebug.debug("Location changed to %f,%f",
+ location.getLatitude(),
+ location.getLongitude());
+ update_ui(telemetry_state, state, false);
+ }
+
+ public void onStatusChanged(String provider, int status, Bundle extras) {
+ AltosDebug.debug("Location status now %d\n", status);
+ }
+
+ public void onProviderEnabled(String provider) {
+ AltosDebug.debug("Location provider enabled %s\n", provider);
+ }
+
+ public void onProviderDisabled(String provider) {
+ AltosDebug.debug("Location provider disabled %s\n", provider);
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2015 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.
+ */
+
+package org.altusmetrum.AltosDroid;
+
+import android.os.Handler;
+
+import org.altusmetrum.altoslib_13.*;
+
+public abstract class AltosDroidLink extends AltosLink {
+
+ Handler handler;
+
+ Thread input_thread = null;
+
+ public double frequency() {
+ return frequency;
+ }
+
+ public int telemetry_rate() {
+ return telemetry_rate;
+ }
+
+ public void save_frequency() {
+ AltosPreferences.set_frequency(0, frequency);
+ }
+
+ public void save_telemetry_rate() {
+ AltosPreferences.set_telemetry_rate(0, telemetry_rate);
+ }
+
+ Object closed_lock = new Object();
+ boolean closing = false;
+ boolean closed = false;
+
+ public boolean closed() {
+ synchronized(closed_lock) {
+ return closing;
+ }
+ }
+
+ void connected() throws InterruptedException {
+ input_thread = new Thread(this);
+ input_thread.start();
+
+ // Configure the newly connected device for telemetry
+ print("~\nE 0\n");
+ set_monitor(false);
+ AltosDebug.debug("ConnectThread: connected");
+
+ /* Let TelemetryService know we're connected
+ */
+ handler.obtainMessage(TelemetryService.MSG_CONNECTED, this).sendToTarget();
+
+ /* Notify other waiting threads that we're connected now
+ */
+ notifyAll();
+ }
+
+ public void closing() {
+ synchronized(closed_lock) {
+ AltosDebug.debug("Marked closing true");
+ closing = true;
+ }
+ }
+
+ private boolean actually_closed() {
+ synchronized(closed_lock) {
+ return closed;
+ }
+ }
+
+ abstract void close_device();
+
+ public void close() {
+ AltosDebug.debug("close(): begin");
+
+ closing();
+
+ flush_output();
+
+ synchronized (closed_lock) {
+ AltosDebug.debug("Marked closed true");
+ closed = true;
+ }
+
+ close_device();
+
+ synchronized(this) {
+
+ if (input_thread != null) {
+ AltosDebug.debug("close(): stopping input_thread");
+ try {
+ AltosDebug.debug("close(): input_thread.interrupt().....");
+ input_thread.interrupt();
+ AltosDebug.debug("close(): input_thread.join().....");
+ input_thread.join();
+ } catch (Exception e) {}
+ input_thread = null;
+ }
+ notifyAll();
+ }
+ }
+
+ abstract int write(byte[] buffer, int len);
+
+ abstract int read(byte[] buffer, int len);
+
+ private static final int buffer_size = 64;
+
+ private byte[] in_buffer = new byte[buffer_size];
+ private byte[] out_buffer = new byte[buffer_size];
+ private int buffer_len = 0;
+ private int buffer_off = 0;
+ private int out_buffer_off = 0;
+
+ private byte[] debug_chars = new byte[buffer_size];
+ private int debug_off;
+
+ private void debug_input(byte b) {
+ if (b == '\n') {
+ AltosDebug.debug(" " + new String(debug_chars, 0, debug_off));
+ debug_off = 0;
+ } else {
+ if (debug_off < buffer_size)
+ debug_chars[debug_off++] = b;
+ }
+ }
+
+ private void disconnected() {
+ if (closed()) {
+ AltosDebug.debug("disconnected after closed");
+ return;
+ }
+
+ AltosDebug.debug("Sending disconnected message");
+ handler.obtainMessage(TelemetryService.MSG_DISCONNECTED, this).sendToTarget();
+ }
+
+ public int getchar() {
+
+ if (actually_closed())
+ return ERROR;
+
+ while (buffer_off == buffer_len) {
+ buffer_len = read(in_buffer, buffer_size);
+ if (buffer_len < 0) {
+ AltosDebug.debug("ERROR returned from getchar()");
+ disconnected();
+ return ERROR;
+ }
+ buffer_off = 0;
+ }
+// if (AltosDebug.D)
+// debug_input(in_buffer[buffer_off]);
+ return in_buffer[buffer_off++];
+ }
+
+ public void flush_output() {
+ super.flush_output();
+
+ if (actually_closed()) {
+ out_buffer_off = 0;
+ return;
+ }
+
+ while (out_buffer_off != 0) {
+ int sent = write(out_buffer, out_buffer_off);
+
+ if (sent <= 0) {
+ AltosDebug.debug("flush_output() failed");
+ out_buffer_off = 0;
+ break;
+ }
+
+ if (sent < out_buffer_off)
+ System.arraycopy(out_buffer, 0, out_buffer, sent, out_buffer_off - sent);
+
+ out_buffer_off -= sent;
+ }
+ }
+
+ public void putchar(byte c) {
+ out_buffer[out_buffer_off++] = c;
+ if (out_buffer_off == buffer_size)
+ flush_output();
+ }
+
+ public void print(String data) {
+ byte[] bytes = data.getBytes();
+// AltosDebug.debug(data.replace('\n', '\\'));
+ for (byte b : bytes)
+ putchar(b);
+ }
+
+ public AltosDroidLink(Handler handler) {
+ this.handler = handler;
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2015 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.
+ */
+
+package org.altusmetrum.AltosDroid;
+
+import android.location.Location;
+import org.altusmetrum.altoslib_13.*;
+
+public interface AltosDroidMapInterface {
+ public void onCreateView(AltosDroid altos_droid);
+
+ public void onDestroyView();
+
+ public void set_visible(boolean visible);
+
+ public void center(double lat, double lon, double accuracy);
+
+ public void show(TelemetryState telem_state, AltosState state, AltosGreatCircle from_receiver, Location receiver);
+}
--- /dev/null
+/*
+ * Copyright © 2016 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.
+ */
+
+package org.altusmetrum.AltosDroid;
+
+public interface AltosDroidMapSourceListener {
+ public void map_source_changed(int map_source);
+}
--- /dev/null
+/*
+ * Copyright © 2014 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.
+ */
+package org.altusmetrum.AltosDroid;
+
+import java.util.*;
+
+import android.content.Context;
+import org.altusmetrum.altoslib_13.*;
+
+public class AltosDroidPreferences extends AltosPreferences {
+
+ /* Active device preference name */
+ final static String activeDeviceAddressPreference = "ACTIVE-DEVICE-ADDRESS";
+ final static String activeDeviceNamePreference = "ACTIVE-DEVICE-NAME";
+
+ static DeviceAddress active_device_address;
+
+ /* Map source preference name */
+ final static String mapSourcePreference = "MAP-SOURCE";
+
+ static final int MAP_SOURCE_OFFLINE = 0;
+ static final int MAP_SOURCE_ONLINE = 1;
+
+ static int map_source;
+
+ public static void init(Context context) {
+ if (backend != null)
+ return;
+
+ AltosPreferences.init(new AltosDroidPreferencesBackend(context));
+
+ String address = backend.getString(activeDeviceAddressPreference, null);
+ String name = backend.getString(activeDeviceNamePreference, null);
+
+ if (address != null && name != null)
+ active_device_address = new DeviceAddress (address, name);
+
+ map_source = backend.getInt(mapSourcePreference, MAP_SOURCE_ONLINE);
+ }
+
+ public static void set_active_device(DeviceAddress address) {
+ synchronized(backend) {
+ active_device_address = address;
+ if (active_device_address != null) {
+ backend.putString(activeDeviceAddressPreference, active_device_address.address);
+ backend.putString(activeDeviceNamePreference, active_device_address.name);
+ } else {
+ backend.remove(activeDeviceAddressPreference);
+ backend.remove(activeDeviceNamePreference);
+ }
+ flush_preferences();
+ }
+ }
+
+ public static DeviceAddress active_device() {
+ synchronized(backend) {
+ return active_device_address;
+ }
+ }
+
+ static LinkedList<AltosDroidMapSourceListener> map_source_listeners;
+
+ public static void set_map_source(int map_source) {
+ synchronized(backend) {
+ AltosDroidPreferences.map_source = map_source;
+ backend.putInt(mapSourcePreference, map_source);
+ flush_preferences();
+ }
+ if (map_source_listeners != null) {
+ for (AltosDroidMapSourceListener l : map_source_listeners) {
+ l.map_source_changed(map_source);
+ }
+ }
+ }
+
+ public static int map_source() {
+ synchronized(backend) {
+ return map_source;
+ }
+ }
+
+ public static void register_map_source_listener(AltosDroidMapSourceListener l) {
+ synchronized(backend) {
+ if (map_source_listeners == null)
+ map_source_listeners = new LinkedList<AltosDroidMapSourceListener>();
+ map_source_listeners.add(l);
+ }
+ }
+
+ public static void unregister_map_source_listener(AltosDroidMapSourceListener l) {
+ synchronized(backend) {
+ map_source_listeners.remove(l);
+ }
+ }
+}
--- /dev/null
+/*
+ * 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; 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.
+ */
+
+package org.altusmetrum.AltosDroid;
+
+import java.io.File;
+import java.util.Map;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.Environment;
+import android.util.*;
+
+import org.altusmetrum.altoslib_13.*;
+
+public class AltosDroidPreferencesBackend extends AltosPreferencesBackend {
+ public final static String NAME = "org.altusmetrum.AltosDroid";
+ private Context context = null;
+ private SharedPreferences prefs = null;
+ private SharedPreferences.Editor editor = null;
+
+ public AltosDroidPreferencesBackend(Context in_context) {
+ this(in_context, NAME);
+ }
+
+ public AltosDroidPreferencesBackend(Context in_context, String in_prefs) {
+ context = in_context;
+ prefs = context.getSharedPreferences(in_prefs, 0);
+ editor = prefs.edit();
+ }
+
+ public String[] keys() {
+ Map<String, ?> all = prefs.getAll();
+ Object[] ao = all.keySet().toArray();
+
+ String[] as = new String[ao.length];
+ for (int i = 0; i < ao.length; i++)
+ as[i] = (String) ao[i];
+ return as;
+ }
+
+ public AltosPreferencesBackend node(String key) {
+ if (!nodeExists(key))
+ putBoolean(key, true);
+ return new AltosDroidPreferencesBackend(context, key);
+ }
+
+ public boolean nodeExists(String key) {
+ return prefs.contains(key);
+ }
+
+ public boolean getBoolean(String key, boolean def) {
+ return prefs.getBoolean(key, def);
+ }
+
+ public double getDouble(String key, double def) {
+ Float f = Float.valueOf(prefs.getFloat(key, (float)def));
+ return f.doubleValue();
+ }
+
+ public int getInt(String key, int def) {
+ return prefs.getInt(key, def);
+ }
+
+ public String getString(String key, String def) {
+ String ret;
+ ret = prefs.getString(key, def);
+// AltosDebug.debug("AltosDroidPreferencesBackend get string %s:\n", key);
+// if (ret == null)
+// AltosDebug.debug(" (null)\n");
+// else {
+// String[] lines = ret.split("\n");
+// for (String l : lines)
+// AltosDebug.debug(" %s\n", l);
+// }
+ return ret;
+ }
+
+ public byte[] getBytes(String key, byte[] def) {
+ String save = prefs.getString(key, null);
+
+ if (save == null)
+ return def;
+
+ byte[] bytes = Base64.decode(save, Base64.DEFAULT);
+ return bytes;
+ }
+
+ public void putBoolean(String key, boolean value) {
+ editor.putBoolean(key, value);
+ }
+
+ public void putDouble(String key, double value) {
+ editor.putFloat(key, (float)value);
+ }
+
+ public void putInt(String key, int value) {
+ editor.putInt(key, value);
+ }
+
+ public void putString(String key, String value) {
+// AltosDebug.debug("AltosDroidPreferencesBackend put string %s:\n", key);
+// String[] lines = value.split("\n");
+// for (String l : lines)
+// AltosDebug.debug(" %s\n", l);
+ editor.putString(key, value);
+ }
+
+ public void putBytes(String key, byte[] bytes) {
+ String save = Base64.encodeToString(bytes, Base64.DEFAULT);
+ editor.putString(key, save);
+ }
+
+ public void remove(String key) {
+ AltosDebug.debug("remove preference %s\n", key);
+ editor.remove(key);
+ }
+
+ public void flush() {
+ editor.apply();
+ }
+
+ public File homeDirectory() {
+ return Environment.getExternalStorageDirectory();
+ }
+
+ public void debug(String format, Object ... arguments) {
+ AltosDebug.debug(format, arguments);
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2013 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; 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.
+ */
+
+package org.altusmetrum.AltosDroid;
+
+import org.altusmetrum.altoslib_13.*;
+import android.location.Location;
+import android.app.Activity;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentTransaction;
+import android.widget.TextView;
+
+public abstract class AltosDroidTab extends Fragment implements AltosUnitsListener {
+ TelemetryState last_telem_state;
+ AltosState last_state;
+ AltosGreatCircle last_from_receiver;
+ Location last_receiver;
+ AltosDroid altos_droid;
+
+ public abstract void show(TelemetryState telem_state, AltosState state, AltosGreatCircle from_receiver, Location receiver);
+
+ public abstract String tab_name();
+
+ public void units_changed(boolean imperial_units) {
+ if (!isHidden())
+ show(last_telem_state, last_state, last_from_receiver, last_receiver);
+ }
+
+ public void set_value(TextView text_view,
+ AltosUnits units,
+ int width,
+ double value) {
+ if (value == AltosLib.MISSING)
+ text_view.setText("");
+ else
+ text_view.setText(units.show(width, value));
+ }
+
+ public void set_visible(boolean visible) {
+ FragmentTransaction ft = AltosDroid.fm.beginTransaction();
+ AltosDebug.debug("set visible %b %s\n", visible, tab_name());
+ if (visible) {
+ ft.show(this);
+ show(last_telem_state, last_state, last_from_receiver, last_receiver);
+ } else
+ ft.hide(this);
+ try {
+ ft.commitAllowingStateLoss();
+ } catch (IllegalStateException ie) {
+ }
+ }
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ altos_droid = (AltosDroid) activity;
+ altos_droid.registerTab(this);
+ }
+
+ @Override
+ public void onDetach() {
+ super.onDetach();
+ altos_droid.unregisterTab(this);
+ altos_droid = null;
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ AltosDebug.debug("onResume tab %s\n", tab_name());
+ set_visible(true);
+ }
+
+ public void update_ui(TelemetryState telem_state, AltosState state,
+ AltosGreatCircle from_receiver, Location receiver, boolean is_current)
+ {
+ last_telem_state = telem_state;
+ last_state = state;
+ last_from_receiver = from_receiver;
+ last_receiver = receiver;
+ if (is_current)
+ show(telem_state, state, from_receiver, receiver);
+ else
+ return;
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2015 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.
+ */
+
+package org.altusmetrum.AltosDroid;
+
+import java.util.*;
+import java.io.*;
+
+import org.altusmetrum.altoslib_13.*;
+
+import android.graphics.*;
+import android.view.*;
+import android.location.Location;
+import android.content.*;
+import android.util.*;
+
+class Rocket implements Comparable {
+ AltosLatLon position;
+ String name;
+ int serial;
+ long last_packet;
+ boolean active;
+ AltosMapOffline map_offline;
+
+ void paint() {
+ map_offline.draw_bitmap(position, map_offline.rocket_bitmap, map_offline.rocket_off_x, map_offline.rocket_off_y);
+ map_offline.draw_text(position, name, 0, 3*map_offline.rocket_bitmap.getHeight()/4);
+ }
+
+ void set_position(AltosLatLon position, long last_packet) {
+ this.position = position;
+ this.last_packet = last_packet;
+ }
+
+ void set_active(boolean active) {
+ this.active = active;
+ }
+
+ public int compareTo(Object o) {
+ Rocket other = (Rocket) o;
+
+ if (active && !other.active)
+ return 1;
+ if (other.active && !active)
+ return -1;
+
+ long diff = last_packet - other.last_packet;
+
+ if (diff > 0)
+ return 1;
+ if (diff < 0)
+ return -1;
+ return 0;
+ }
+
+ Rocket(int serial, AltosMapOffline map_offline) {
+ this.serial = serial;
+ this.name = String.format("%d", serial);
+ this.map_offline = map_offline;
+ }
+}
+
+public class AltosMapOffline extends View implements ScaleGestureDetector.OnScaleGestureListener, AltosMapInterface, AltosDroidMapInterface, AltosMapTypeListener {
+ ScaleGestureDetector scale_detector;
+ boolean scaling;
+ AltosMap map;
+ AltosDroid altos_droid;
+
+ static int scale = 1;
+
+ AltosLatLon here;
+ AltosLatLon there;
+ AltosLatLon pad;
+
+ Canvas canvas;
+ Paint paint;
+
+ Bitmap pad_bitmap;
+ int pad_off_x, pad_off_y;
+ Bitmap rocket_bitmap;
+ int rocket_off_x, rocket_off_y;
+ Bitmap here_bitmap;
+ int here_off_x, here_off_y;
+
+ static final int WHITE = 0xffffffff;
+ static final int RED = 0xffff0000;
+ static final int PINK = 0xffff8080;
+ static final int YELLOW= 0xffffff00;
+ static final int CYAN = 0xff00ffff;
+ static final int BLUE = 0xff0000ff;
+ static final int BLACK = 0xff000000;
+
+ public static final int stateColors[] = {
+ WHITE, // startup
+ WHITE, // idle
+ WHITE, // pad
+ RED, // boost
+ PINK, // fast
+ YELLOW, // coast
+ CYAN, // drogue
+ BLUE, // main
+ BLACK, // landed
+ BLACK, // invalid
+ CYAN, // stateless
+ };
+
+ /* AltosMapInterface */
+ public void debug(String format, Object ... arguments) {
+ AltosDebug.debug(format, arguments);
+ }
+
+ class MapTile extends AltosMapTile {
+ public void paint(AltosMapTransform t) {
+ AltosPointInt pt = new AltosPointInt(t.screen(upper_left));
+
+ if (canvas.quickReject(pt.x, pt.y, pt.x + px_size, pt.y + px_size, Canvas.EdgeType.AA))
+ return;
+
+ AltosImage altos_image = this.get_image();
+
+ MapImage map_image = (MapImage) altos_image;
+
+ Bitmap bitmap = null;
+
+ if (map_image != null)
+ bitmap = map_image.bitmap;
+
+ if (bitmap != null) {
+ canvas.drawBitmap(bitmap, pt.x, pt.y, paint);
+ } else {
+ paint.setColor(0xff808080);
+ canvas.drawRect(pt.x, pt.y, pt.x + px_size, pt.y + px_size, paint);
+ if (t.has_location()) {
+ String message = null;
+ switch (status) {
+ case AltosMapTile.fetching:
+ message = "Fetching...";
+ break;
+ case AltosMapTile.bad_request:
+ message = "Internal error";
+ break;
+ case AltosMapTile.failed:
+ message = "Network error";
+ break;
+ case AltosMapTile.forbidden:
+ message = "Outside of known launch areas";
+ break;
+ }
+ if (message != null) {
+ Rect bounds = new Rect();
+ paint.getTextBounds(message, 0, message.length(), bounds);
+
+ int width = bounds.right - bounds.left;
+ int height = bounds.bottom - bounds.top;
+
+ float x = pt.x + px_size / 2.0f;
+ float y = pt.y + px_size / 2.0f;
+ x = x - width / 2.0f;
+ y = y + height / 2.0f;
+ paint.setColor(0xff000000);
+ canvas.drawText(message, 0, message.length(), x, y, paint);
+ }
+ }
+ }
+ }
+
+ public MapTile(AltosMapCache cache, AltosLatLon upper_left, AltosLatLon center, int zoom, int maptype, int px_size, int scale) {
+ super(cache, upper_left, center, zoom, maptype, px_size, scale);
+ }
+
+ }
+
+ public AltosMapTile new_tile(AltosMapCache cache, AltosLatLon upper_left, AltosLatLon center, int zoom, int maptype, int px_size, int scale) {
+ return new MapTile(cache, upper_left, center, zoom, maptype, px_size, scale);
+ }
+
+ public AltosMapPath new_path() {
+ return null;
+ }
+
+ public AltosMapLine new_line() {
+ return null;
+ }
+
+ class MapImage implements AltosImage {
+ public Bitmap bitmap;
+
+ public void flush() {
+ if (bitmap != null) {
+ bitmap.recycle();
+ bitmap = null;
+ }
+ }
+
+ public MapImage(File file) {
+ bitmap = BitmapFactory.decodeFile(file.getPath());
+ }
+ }
+
+ public AltosImage load_image(File file) throws Exception {
+ return new MapImage(file);
+ }
+
+ class MapMark extends AltosMapMark {
+ public void paint(AltosMapTransform t) {
+ }
+
+ MapMark(double lat, double lon, int state) {
+ super(lat, lon, state);
+ }
+ }
+
+ public AltosMapMark new_mark(double lat, double lon, int state) {
+ return new MapMark(lat, lon, state);
+ }
+
+ public int width() {
+ return getWidth();
+ }
+
+ public int height() {
+ return getHeight();
+ }
+
+ public void repaint() {
+ postInvalidate();
+ }
+
+ public void repaint(AltosRectangle damage) {
+ postInvalidate(damage.x, damage.y, damage.x + damage.width, damage.y + damage.height);
+ }
+
+ public void set_zoom_label(String label) {
+ }
+
+ public void select_object(AltosLatLon latlon) {
+ if (map.transform == null)
+ return;
+ ArrayList<Integer> near = new ArrayList<Integer>();
+
+ for (Rocket rocket : sorted_rockets()) {
+ if (rocket.position == null) {
+ debug("rocket %d has no position\n", rocket.serial);
+ continue;
+ }
+ double distance = map.transform.hypot(latlon, rocket.position);
+ debug("check select %d distance %g width %d\n", rocket.serial, distance, rocket_bitmap.getWidth());
+ if (distance < rocket_bitmap.getWidth() * 2.0) {
+ debug("selecting %d\n", rocket.serial);
+ near.add(rocket.serial);
+ }
+ }
+ if (near.size() != 0)
+ altos_droid.touch_trackers(near.toArray(new Integer[0]));
+ }
+
+ class Line {
+ AltosLatLon a, b;
+
+ void paint() {
+ if (a != null && b != null) {
+ AltosPointDouble a_screen = map.transform.screen(a);
+ AltosPointDouble b_screen = map.transform.screen(b);
+ paint.setColor(0xff8080ff);
+ canvas.drawLine((float) a_screen.x, (float) a_screen.y,
+ (float) b_screen.x, (float) b_screen.y,
+ paint);
+ }
+ }
+
+ void set_a(AltosLatLon a) {
+ this.a = a;
+ }
+
+ void set_b(AltosLatLon b) {
+ this.b = b;
+ }
+
+ Line() {
+ }
+ }
+
+ Line line = new Line();
+
+ int stroke_width = 20;
+
+ void draw_text(AltosLatLon lat_lon, String text, int off_x, int off_y) {
+ if (lat_lon != null && map != null && map.transform != null) {
+ AltosPointInt pt = new AltosPointInt(map.transform.screen(lat_lon));
+
+ Rect bounds = new Rect();
+ paint.getTextBounds(text, 0, text.length(), bounds);
+
+ int width = bounds.right - bounds.left;
+ int height = bounds.bottom - bounds.top;
+
+ float x = pt.x;
+ float y = pt.y;
+ x = x - width / 2.0f - off_x;
+ y = y + height / 2.0f - off_y;
+ paint.setColor(0xff000000);
+ canvas.drawText(text, 0, text.length(), x, y, paint);
+ }
+ }
+
+ HashMap<Integer,Rocket> rockets = new HashMap<Integer,Rocket>();
+
+ void draw_bitmap(AltosLatLon lat_lon, Bitmap bitmap, int off_x, int off_y) {
+ if (lat_lon != null && map != null && map.transform != null) {
+ AltosPointInt pt = new AltosPointInt(map.transform.screen(lat_lon));
+
+ canvas.drawBitmap(bitmap, pt.x - off_x, pt.y - off_y, paint);
+ }
+ }
+
+ private Rocket[] sorted_rockets() {
+ Rocket[] rocket_array = rockets.values().toArray(new Rocket[0]);
+
+ Arrays.sort(rocket_array);
+ return rocket_array;
+ }
+
+ private void draw_positions() {
+ line.set_a(there);
+ line.set_b(here);
+ line.paint();
+ draw_bitmap(pad, pad_bitmap, pad_off_x, pad_off_y);
+
+ for (Rocket rocket : sorted_rockets())
+ rocket.paint();
+ draw_bitmap(here, here_bitmap, here_off_x, here_off_y);
+ }
+
+ @Override public void invalidate() {
+ Rect r = new Rect();
+ getDrawingRect(r);
+ super.invalidate();
+ }
+
+ @Override public void invalidate(int l, int t, int r, int b) {
+ Rect rect = new Rect();
+ getDrawingRect(rect);
+ super.invalidate();
+ }
+
+ @Override
+ protected void onDraw(Canvas view_canvas) {
+ if (map == null) {
+ debug("MapView draw without map\n");
+ return;
+ }
+ canvas = view_canvas;
+ paint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ paint.setStrokeWidth(stroke_width);
+ paint.setStrokeCap(Paint.Cap.ROUND);
+ paint.setStrokeJoin(Paint.Join.ROUND);
+ paint.setTextSize(40);
+ map.paint();
+ draw_positions();
+ canvas = null;
+ }
+
+ public boolean onScale(ScaleGestureDetector detector) {
+ float f = detector.getScaleFactor();
+
+ if (f <= 0.8) {
+ map.set_zoom_centre(map.get_zoom() - 1, new AltosPointInt((int) detector.getFocusX(), (int) detector.getFocusY()));
+ return true;
+ }
+ if (f >= 1.2) {
+ map.set_zoom_centre(map.get_zoom() + 1, new AltosPointInt((int) detector.getFocusX(), (int) detector.getFocusY()));
+ return true;
+ }
+ return false;
+ }
+
+ public boolean onScaleBegin(ScaleGestureDetector detector) {
+ return true;
+ }
+
+ public void onScaleEnd(ScaleGestureDetector detector) {
+ }
+
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent event) {
+ scale_detector.onTouchEvent(event);
+
+ if (scale_detector.isInProgress()) {
+ scaling = true;
+ }
+
+ if (scaling) {
+ if (event.getAction() == MotionEvent.ACTION_UP) {
+ scaling = false;
+ }
+ return true;
+ }
+
+ if (event.getAction() == MotionEvent.ACTION_DOWN) {
+ map.touch_start((int) event.getX(), (int) event.getY(), true);
+ } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
+ map.touch_continue((int) event.getX(), (int) event.getY(), true);
+ } else if (event.getAction() == MotionEvent.ACTION_UP) {
+ map.touch_stop((int) event.getX(), (int) event.getY(), true);
+ }
+ return true;
+ }
+
+ double mapAccuracy;
+
+ public void center(double lat, double lon, double accuracy) {
+ if (mapAccuracy <= 0 || accuracy < mapAccuracy/10 || (map != null && !map.has_centre())) {
+ if (map != null)
+ map.maybe_centre(lat, lon);
+ mapAccuracy = accuracy;
+ }
+ }
+
+ public void set_visible(boolean visible) {
+ if (visible)
+ setVisibility(VISIBLE);
+ else
+ setVisibility(GONE);
+ }
+
+ public void show(TelemetryState telem_state, AltosState state, AltosGreatCircle from_receiver, Location receiver) {
+ boolean changed = false;
+
+ if (state != null) {
+ map.show(state, null);
+ if (state.pad_lat != AltosLib.MISSING && pad == null)
+ pad = new AltosLatLon(state.pad_lat, state.pad_lon);
+ }
+
+ if (telem_state != null) {
+ Integer[] old_serial = rockets.keySet().toArray(new Integer[0]);
+ Integer[] new_serial = telem_state.states.keySet().toArray(new Integer[0]);
+
+ /* remove deleted keys */
+ for (int serial : old_serial) {
+ if (!telem_state.states.containsKey(serial))
+ rockets.remove(serial);
+ }
+
+ /* set remaining keys */
+
+ for (int serial : new_serial) {
+ Rocket rocket;
+ AltosState t_state = telem_state.states.get(serial);
+ if (rockets.containsKey(serial))
+ rocket = rockets.get(serial);
+ else {
+ rocket = new Rocket(serial, this);
+ rockets.put(serial, rocket);
+ }
+ if (t_state.gps != null) {
+ AltosLatLon latlon = new AltosLatLon(t_state.gps.lat, t_state.gps.lon);
+ rocket.set_position(latlon, t_state.received_time);
+ if (state.cal_data().serial == serial)
+ there = latlon;
+ }
+ if (state != null)
+ rocket.set_active(state.cal_data().serial == serial);
+ }
+ }
+ if (receiver != null) {
+ AltosLatLon new_here = new AltosLatLon(receiver.getLatitude(), receiver.getLongitude());
+ if (!new_here.equals(here)) {
+ here = new_here;
+ AltosDebug.debug("Location changed, redraw");
+ repaint();
+ }
+ }
+ }
+
+ public void onCreateView(AltosDroid altos_droid) {
+ this.altos_droid = altos_droid;
+ map = new AltosMap(this, scale);
+ AltosPreferences.register_map_type_listener(this);
+ map.set_maptype(AltosPreferences.map_type());
+
+ pad_bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.pad);
+ /* arrow at the bottom of the launchpad image */
+ pad_off_x = pad_bitmap.getWidth() / 2;
+ pad_off_y = pad_bitmap.getHeight();
+
+ rocket_bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.rocket);
+ /* arrow at the bottom of the rocket image */
+ rocket_off_x = rocket_bitmap.getWidth() / 2;
+ rocket_off_y = rocket_bitmap.getHeight();
+
+ here_bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_maps_indicator_current_position);
+ /* Center of the dot */
+ here_off_x = here_bitmap.getWidth() / 2;
+ here_off_y = here_bitmap.getHeight() / 2;
+ }
+
+ public void onDestroyView() {
+ AltosPreferences.unregister_map_type_listener(this);
+ }
+
+ public void map_type_changed(int map_type) {
+ if (map != null)
+ map.set_maptype(map_type);
+ }
+
+ public AltosMapOffline(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ this.altos_droid = altos_droid;
+ scale_detector = new ScaleGestureDetector(context, this);
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2013 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; 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.
+ */
+
+package org.altusmetrum.AltosDroid;
+
+import java.util.*;
+
+import org.altusmetrum.altoslib_13.*;
+
+import com.google.android.gms.maps.*;
+import com.google.android.gms.maps.model.*;
+
+import android.graphics.Color;
+import android.graphics.*;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.location.Location;
+import android.content.*;
+
+class RocketOnline implements Comparable {
+ Marker marker;
+ int serial;
+ long last_packet;
+ int size;
+
+ void set_position(AltosLatLon position, long last_packet) {
+ marker.setPosition(new LatLng(position.lat, position.lon));
+ this.last_packet = last_packet;
+ }
+
+ private Bitmap rocket_bitmap(Context context, String text) {
+
+ /* From: http://mapicons.nicolasmollet.com/markers/industry/military/missile-2/
+ */
+ Bitmap orig_bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.rocket);
+ Bitmap bitmap = orig_bitmap.copy(Bitmap.Config.ARGB_8888, true);
+
+ Canvas canvas = new Canvas(bitmap);
+ Paint paint = new Paint();
+ paint.setTextSize(40);
+ paint.setColor(0xff000000);
+
+ Rect bounds = new Rect();
+ paint.getTextBounds(text, 0, text.length(), bounds);
+
+ int width = bounds.right - bounds.left;
+ int height = bounds.bottom - bounds.top;
+
+ float x = bitmap.getWidth() / 2.0f - width / 2.0f;
+ float y = bitmap.getHeight() / 2.0f - height / 2.0f;
+
+ size = bitmap.getWidth();
+
+ canvas.drawText(text, 0, text.length(), x, y, paint);
+ return bitmap;
+ }
+
+ public void remove() {
+ marker.remove();
+ }
+
+ public int compareTo(Object o) {
+ RocketOnline other = (RocketOnline) o;
+
+ long diff = last_packet - other.last_packet;
+
+ if (diff > 0)
+ return 1;
+ if (diff < 0)
+ return -1;
+ return 0;
+ }
+
+ RocketOnline(Context context, int serial, GoogleMap map, double lat, double lon, long last_packet) {
+ this.serial = serial;
+ String name = String.format("%d", serial);
+ this.marker = map.addMarker(new MarkerOptions()
+ .icon(BitmapDescriptorFactory.fromBitmap(rocket_bitmap(context, name)))
+ .position(new LatLng(lat, lon))
+ .visible(true));
+ this.last_packet = last_packet;
+ }
+}
+
+public class AltosMapOnline implements AltosDroidMapInterface, GoogleMap.OnMarkerClickListener, GoogleMap.OnMapClickListener, OnMapReadyCallback, AltosMapTypeListener {
+ public AltosOnlineMapFragment mMapFragment;
+ private GoogleMap mMap;
+ private boolean mapLoaded = false;
+ Context context;
+
+ private HashMap<Integer,RocketOnline> rockets = new HashMap<Integer,RocketOnline>();
+ private Marker mPadMarker;
+ private boolean pad_set;
+ private Polyline mPolyline;
+
+ private double mapAccuracy = -1;
+
+ private AltosLatLon my_position = null;
+ private AltosLatLon target_position = null;
+
+ private AltosDroid altos_droid;
+
+ public static class AltosOnlineMapFragment extends SupportMapFragment {
+ AltosMapOnline c;
+ View map_view;
+
+ public AltosOnlineMapFragment(AltosMapOnline c) {
+ this.c = c;
+ }
+
+ public AltosOnlineMapFragment() {
+ }
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ if (c != null)
+ getMapAsync(c);
+ }
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ map_view = super.onCreateView(inflater, container, savedInstanceState);
+ return map_view;
+ }
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ map_view = null;
+ }
+ public void set_visible(boolean visible) {
+ if (map_view == null)
+ return;
+ if (visible)
+ map_view.setVisibility(View.VISIBLE);
+ else
+ map_view.setVisibility(View.GONE);
+ }
+ }
+
+ public void onCreateView(AltosDroid altos_droid) {
+ this.altos_droid = altos_droid;
+ AltosPreferences.register_map_type_listener(this);
+ mMapFragment = new AltosOnlineMapFragment(this);
+ }
+
+ public void onDestroyView() {
+ AltosPreferences.unregister_map_type_listener(this);
+ }
+
+ private double pixel_distance(LatLng a, LatLng b) {
+ Projection projection = mMap.getProjection();
+
+ Point a_pt = projection.toScreenLocation(a);
+ Point b_pt = projection.toScreenLocation(b);
+
+ return Math.hypot((double) (a_pt.x - b_pt.x), (double) (a_pt.y - b_pt.y));
+ }
+
+ private RocketOnline[] sorted_rockets() {
+ RocketOnline[] rocket_array = rockets.values().toArray(new RocketOnline[0]);
+
+ Arrays.sort(rocket_array);
+ return rocket_array;
+ }
+
+ public void onMapClick(LatLng lat_lng) {
+ ArrayList<Integer> near = new ArrayList<Integer>();
+
+ for (RocketOnline rocket : sorted_rockets()) {
+ LatLng pos = rocket.marker.getPosition();
+
+ if (pos == null)
+ continue;
+
+ double distance = pixel_distance(lat_lng, pos);
+ if (distance < rocket.size * 2)
+ near.add(rocket.serial);
+ }
+
+ if (near.size() != 0)
+ altos_droid.touch_trackers(near.toArray(new Integer[0]));
+ }
+
+ public boolean onMarkerClick(Marker marker) {
+ onMapClick(marker.getPosition());
+ return true;
+ }
+
+ @Override
+ public void onMapReady(GoogleMap googleMap) {
+ final int map_type = AltosPreferences.map_type();
+ mMap = googleMap;
+ if (mMap != null) {
+ map_type_changed(map_type);
+ mMap.setMyLocationEnabled(true);
+ mMap.getUiSettings().setTiltGesturesEnabled(false);
+ mMap.getUiSettings().setZoomControlsEnabled(false);
+ mMap.setOnMarkerClickListener(this);
+ mMap.setOnMapClickListener(this);
+
+ mPadMarker = mMap.addMarker(
+ new MarkerOptions().icon(BitmapDescriptorFactory.fromResource(R.drawable.pad))
+ .position(new LatLng(0,0))
+ .visible(false)
+ );
+
+ mPolyline = mMap.addPolyline(
+ new PolylineOptions().add(new LatLng(0,0), new LatLng(0,0))
+ .width(20)
+ .color(Color.BLUE)
+ .visible(false)
+ );
+
+ mapLoaded = true;
+ }
+ }
+
+ public void center(double lat, double lon, double accuracy) {
+ if (mMap == null)
+ return;
+
+ if (mapAccuracy < 0 || accuracy < mapAccuracy/10) {
+ mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(lat, lon),14));
+ mapAccuracy = accuracy;
+ }
+ }
+
+ private void set_rocket(int serial, AltosState state) {
+ RocketOnline rocket;
+
+ if (state.gps == null || state.gps.lat == AltosLib.MISSING)
+ return;
+
+ if (mMap == null)
+ return;
+
+ if (rockets.containsKey(serial)) {
+ rocket = rockets.get(serial);
+ rocket.set_position(new AltosLatLon(state.gps.lat, state.gps.lon), state.received_time);
+ } else {
+ rocket = new RocketOnline(context,
+ serial,
+ mMap, state.gps.lat, state.gps.lon,
+ state.received_time);
+ rockets.put(serial, rocket);
+ }
+ }
+
+ private void remove_rocket(int serial) {
+ RocketOnline rocket = rockets.get(serial);
+ rocket.remove();
+ rockets.remove(serial);
+ }
+
+ public void set_visible(boolean visible) {
+ if (mMapFragment != null)
+ mMapFragment.set_visible(visible);
+ }
+
+ public void show(TelemetryState telem_state, AltosState state, AltosGreatCircle from_receiver, Location receiver) {
+
+ if (telem_state != null) {
+ for (int serial : rockets.keySet()) {
+ if (!telem_state.states.containsKey(serial))
+ remove_rocket(serial);
+ }
+
+ for (int serial : telem_state.states.keySet()) {
+ set_rocket(serial, telem_state.states.get(serial));
+ }
+ }
+
+ if (state != null) {
+ if (mapLoaded) {
+ if (!pad_set && state.pad_lat != AltosLib.MISSING) {
+ pad_set = true;
+ mPadMarker.setPosition(new LatLng(state.pad_lat, state.pad_lon));
+ mPadMarker.setVisible(true);
+ }
+ }
+ if (state.gps != null && state.gps.lat != AltosLib.MISSING) {
+
+ target_position = new AltosLatLon(state.gps.lat, state.gps.lon);
+ if (state.gps.locked && state.gps.nsat >= 4)
+ center (state.gps.lat, state.gps.lon, 10);
+ }
+ }
+
+ if (receiver != null) {
+ double accuracy;
+
+ if (receiver.hasAccuracy())
+ accuracy = receiver.getAccuracy();
+ else
+ accuracy = 1000;
+
+ my_position = new AltosLatLon(receiver.getLatitude(), receiver.getLongitude());
+ center (my_position.lat, my_position.lon, accuracy);
+ }
+
+ if (my_position != null && target_position != null && mPolyline != null) {
+ mPolyline.setPoints(Arrays.asList(new LatLng(my_position.lat, my_position.lon), new LatLng(target_position.lat, target_position.lon)));
+ mPolyline.setVisible(true);
+ }
+
+ }
+
+ public void map_type_changed(int map_type) {
+ if (mMap != null) {
+ if (map_type == AltosMap.maptype_hybrid)
+ mMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
+ else if (map_type == AltosMap.maptype_satellite)
+ mMap.setMapType(GoogleMap.MAP_TYPE_SATELLITE);
+ else if (map_type == AltosMap.maptype_terrain)
+ mMap.setMapType(GoogleMap.MAP_TYPE_TERRAIN);
+ else
+ mMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
+ }
+ }
+
+ public AltosMapOnline(Context context) {
+ this.context = context;
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2015 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.
+ */
+
+package org.altusmetrum.AltosDroid;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.HashMap;
+
+import android.content.Context;
+import android.hardware.usb.*;
+import android.app.*;
+import android.os.Handler;
+
+import org.altusmetrum.altoslib_13.*;
+
+public class AltosUsb extends AltosDroidLink {
+
+ private Thread input_thread = null;
+
+ private Handler handler;
+
+ private UsbManager manager;
+ private UsbDevice device;
+ private UsbDeviceConnection connection;
+ private UsbInterface iface;
+ private UsbEndpoint in, out;
+
+ private InputStream input;
+ private OutputStream output;
+
+ // Constructor
+ public AltosUsb(Context context, UsbDevice device, Handler handler) {
+ super(handler);
+// set_debug(D);
+ this.handler = handler;
+
+ iface = null;
+ in = null;
+ out = null;
+
+ int niface = device.getInterfaceCount();
+
+ for (int i = 0; i < niface; i++) {
+
+ iface = device.getInterface(i);
+
+ in = null;
+ out = null;
+
+ int nendpoints = iface.getEndpointCount();
+
+ for (int e = 0; e < nendpoints; e++) {
+ UsbEndpoint endpoint = iface.getEndpoint(e);
+
+ if (endpoint.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
+ switch (endpoint.getDirection()) {
+ case UsbConstants.USB_DIR_OUT:
+ out = endpoint;
+ break;
+ case UsbConstants.USB_DIR_IN:
+ in = endpoint;
+ break;
+ }
+ }
+ }
+
+ if (in != null && out != null)
+ break;
+ }
+
+ if (in != null && out != null) {
+ AltosDebug.debug("\tin %s out %s\n", in.toString(), out.toString());
+
+ manager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
+
+ if (manager == null) {
+ AltosDebug.debug("USB_SERVICE failed");
+ return;
+ }
+
+ connection = manager.openDevice(device);
+
+ if (connection == null) {
+ AltosDebug.debug("openDevice failed");
+ return;
+ }
+
+ connection.claimInterface(iface, true);
+
+ input_thread = new Thread(this);
+ input_thread.start();
+
+ // Configure the newly connected device for telemetry
+ print("~\nE 0\n");
+ set_monitor(false);
+ }
+ }
+
+ static private boolean isAltusMetrum(UsbDevice device) {
+ if (device.getVendorId() != AltosLib.vendor_altusmetrum)
+ return false;
+ if (device.getProductId() < AltosLib.product_altusmetrum_min)
+ return false;
+ if (device.getProductId() > AltosLib.product_altusmetrum_max)
+ return false;
+ return true;
+ }
+
+ static boolean matchProduct(int want_product, UsbDevice device) {
+
+ if (!isAltusMetrum(device))
+ return false;
+
+ if (want_product == AltosLib.product_any)
+ return true;
+
+ int have_product = device.getProductId();
+
+ if (want_product == AltosLib.product_basestation)
+ return have_product == AltosLib.product_teledongle ||
+ have_product == AltosLib.product_teleterra ||
+ have_product == AltosLib.product_telebt ||
+ have_product == AltosLib.product_megadongle;
+
+ if (want_product == AltosLib.product_altimeter)
+ return have_product == AltosLib.product_telemetrum ||
+ have_product == AltosLib.product_telemega ||
+ have_product == AltosLib.product_easymega ||
+ have_product == AltosLib.product_telegps ||
+ have_product == AltosLib.product_easymini ||
+ have_product == AltosLib.product_telemini;
+
+ if (have_product == AltosLib.product_altusmetrum) /* old devices match any request */
+ return true;
+
+ if (want_product == have_product)
+ return true;
+
+ return false;
+ }
+
+ static public boolean request_permission(Context context, UsbDevice device, PendingIntent pi) {
+ UsbManager manager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
+
+// if (manager.hasPermission(device))
+// return true;
+
+ AltosDebug.debug("request permission for USB device " + device.toString());
+
+ manager.requestPermission(device, pi);
+ return false;
+ }
+
+ static public UsbDevice find_device(Context context, int match_product) {
+ UsbManager manager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
+
+ HashMap<String,UsbDevice> devices = manager.getDeviceList();
+
+ for (UsbDevice device : devices.values()) {
+ int vendor = device.getVendorId();
+ int product = device.getProductId();
+
+ if (matchProduct(match_product, device)) {
+ AltosDebug.debug("found USB device " + device.toString());
+ return device;
+ }
+ }
+
+ return null;
+ }
+
+ private void disconnected() {
+ if (closed()) {
+ AltosDebug.debug("disconnected after closed");
+ return;
+ }
+
+ AltosDebug.debug("Sending disconnected message");
+ handler.obtainMessage(TelemetryService.MSG_DISCONNECTED, this).sendToTarget();
+ }
+
+ void close_device() {
+ UsbDeviceConnection tmp_connection;
+
+ synchronized(this) {
+ tmp_connection = connection;
+ connection = null;
+ }
+
+ if (tmp_connection != null) {
+ AltosDebug.debug("Closing USB device");
+ tmp_connection.close();
+ }
+ }
+
+ int read(byte[] buffer, int len) {
+ int ret = connection.bulkTransfer(in, buffer, len, -1);
+ AltosDebug.debug("read(%d) = %d\n", len, ret);
+ return ret;
+ }
+
+ int write(byte[] buffer, int len) {
+ int ret = connection.bulkTransfer(out, buffer, len, -1);
+ AltosDebug.debug("write(%d) = %d\n", len, ret);
+ return ret;
+ }
+
+ // Stubs of required methods when extending AltosLink
+ public boolean can_cancel_reply() { return false; }
+ public boolean show_reply_timeout() { return true; }
+ public void hide_reply_timeout() { }
+
+}
--- /dev/null
+/*
+ * Copyright © 2013 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; 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.
+ */
+
+package org.altusmetrum.AltosDroid;
+
+import android.content.Context;
+import androidx.viewpager.widget.ViewPager;
+import android.util.AttributeSet;
+import android.view.View;
+
+public class AltosViewPager extends ViewPager {
+
+ public AltosViewPager(Context context) {
+ super(context);
+ }
+
+ public AltosViewPager(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
+
+ if (v.getClass() != null &&
+ v.getClass().getName() != null &&
+ v.getClass().getName().endsWith("MapOffline"))
+ return true;
+
+ if(v.getClass() != null &&
+ v.getClass().getPackage() != null &&
+ v.getClass().getPackage().getName() != null &&
+ v.getClass().getPackage().getName().startsWith("maps."))
+ return true;
+
+ return super.canScroll(v, checkV, dx, x, y);
+ }
+
+}
--- /dev/null
+/*
+ * 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; 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.
+ */
+
+package org.altusmetrum.AltosDroid;
+
+import android.speech.tts.TextToSpeech;
+import android.speech.tts.TextToSpeech.OnInitListener;
+import android.location.Location;
+
+import org.altusmetrum.altoslib_13.*;
+
+public class AltosVoice {
+
+ private TextToSpeech tts = null;
+ private boolean tts_enabled = false;
+
+ static final int TELL_MODE_NONE = 0;
+ static final int TELL_MODE_PAD = 1;
+ static final int TELL_MODE_FLIGHT = 2;
+ static final int TELL_MODE_RECOVER = 3;
+
+ static final int TELL_FLIGHT_NONE = 0;
+ static final int TELL_FLIGHT_STATE = 1;
+ static final int TELL_FLIGHT_SPEED = 2;
+ static final int TELL_FLIGHT_HEIGHT = 3;
+ static final int TELL_FLIGHT_TRACK = 4;
+
+ private int last_tell_mode;
+ private int last_tell_serial = AltosLib.MISSING;
+ private int last_state;
+ private AltosGPS last_gps;
+ private double last_height = AltosLib.MISSING;
+ private Location last_receiver;
+ private long last_speak_time;
+ private int last_flight_tell = TELL_FLIGHT_NONE;
+ private boolean quiet = false;
+
+ private long now() {
+ return System.currentTimeMillis();
+ }
+
+ private void reset_last() {
+ last_tell_mode = TELL_MODE_NONE;
+ last_speak_time = now() - 100 * 1000;
+ last_gps = null;
+ last_height = AltosLib.MISSING;
+ last_receiver = null;
+ last_state = AltosLib.ao_flight_invalid;
+ last_flight_tell = TELL_FLIGHT_NONE;
+ }
+
+ public AltosVoice(AltosDroid a) {
+ tts = new TextToSpeech(a, new OnInitListener() {
+ public void onInit(int status) {
+ if (status == TextToSpeech.SUCCESS) tts_enabled = true;
+ }
+ });
+ reset_last();
+ }
+
+ public synchronized void set_enable(boolean enable) {
+ tts_enabled = enable;
+ }
+
+ public synchronized void speak(String s) {
+ if (!tts_enabled) return;
+ last_speak_time = now();
+ if (!quiet)
+ tts.speak(s, TextToSpeech.QUEUE_ADD, null);
+ }
+
+ public synchronized long time_since_speak() {
+ return now() - last_speak_time;
+ }
+
+ public synchronized void speak(String format, Object ... arguments) {
+ speak(String.format(format, arguments));
+ }
+
+ public synchronized boolean is_speaking() {
+ return tts.isSpeaking();
+ }
+
+ public void stop() {
+ if (tts != null) {
+ tts.stop();
+ tts.shutdown();
+ }
+ }
+
+ private boolean last_apogee_good;
+ private boolean last_main_good;
+ private boolean last_gps_good;
+
+ private boolean tell_gonogo(String name,
+ boolean current,
+ boolean previous,
+ boolean new_mode) {
+ if (current != previous || new_mode)
+ speak("%s %s.", name, current ? "ready" : "not ready");
+ return current;
+ }
+
+ private boolean tell_pad(TelemetryState telem_state, AltosState state,
+ AltosGreatCircle from_receiver, Location receiver) {
+
+ if (state == null)
+ return false;
+
+ AltosDebug.debug("tell_pad lag %b ltm %d\n", last_apogee_good, last_tell_mode);
+
+ if (state.apogee_voltage != AltosLib.MISSING)
+ last_apogee_good = tell_gonogo("apogee",
+ state.apogee_voltage >= AltosLib.ao_igniter_good,
+ last_apogee_good,
+ last_tell_mode != TELL_MODE_PAD);
+
+ if (state.main_voltage != AltosLib.MISSING)
+ last_main_good = tell_gonogo("main",
+ state.main_voltage >= AltosLib.ao_igniter_good,
+ last_main_good,
+ last_tell_mode != TELL_MODE_PAD);
+
+ if (state.gps != null)
+ last_gps_good = tell_gonogo("G P S",
+ state.gps_ready,
+ last_gps_good,
+ last_tell_mode != TELL_MODE_PAD);
+ return true;
+ }
+
+
+ private boolean descending(int state) {
+ return AltosLib.ao_flight_drogue <= state && state <= AltosLib.ao_flight_landed;
+ }
+
+ private boolean target_moved(AltosState state) {
+ if (last_gps != null && state != null && state.gps != null) {
+ AltosGreatCircle moved = new AltosGreatCircle(last_gps.lat, last_gps.lon, last_gps.alt,
+ state.gps.lat, state.gps.lon, state.gps.alt);
+ double height_change = 0;
+ double height = state.height();
+
+ if (height != AltosLib.MISSING && last_height != AltosLib.MISSING)
+ height_change = Math.abs(last_height - height);
+
+ if (moved.range < 10 && height_change < 10)
+ return false;
+ }
+ return true;
+ }
+
+ private boolean receiver_moved(Location receiver) {
+ if (last_receiver != null && receiver != null) {
+ AltosGreatCircle moved = new AltosGreatCircle(last_receiver.getLatitude(),
+ last_receiver.getLongitude(),
+ last_receiver.getAltitude(),
+ receiver.getLatitude(),
+ receiver.getLongitude(),
+ receiver.getAltitude());
+ if (moved.range < 10)
+ return false;
+ }
+ return true;
+ }
+
+ private boolean tell_flight(TelemetryState telem_state, AltosState state,
+ AltosGreatCircle from_receiver, Location receiver) {
+
+ boolean spoken = false;
+
+ if (state == null)
+ return false;
+
+ if (last_tell_mode != TELL_MODE_FLIGHT)
+ last_flight_tell = TELL_FLIGHT_NONE;
+
+ if (state.state() != last_state && AltosLib.ao_flight_boost <= state.state() && state.state() <= AltosLib.ao_flight_landed) {
+ speak(state.state_name());
+ if (descending(state.state()) && !descending(last_state)) {
+ if (state.max_height() != AltosLib.MISSING) {
+ speak("max height: %s.",
+ AltosConvert.height.say_units(state.max_height()));
+ }
+ }
+ last_flight_tell = TELL_FLIGHT_STATE;
+ return true;
+ }
+
+ if (last_tell_mode == TELL_MODE_FLIGHT && last_flight_tell == TELL_FLIGHT_TRACK) {
+ if (time_since_speak() < 10 * 1000)
+ return false;
+ if (!target_moved(state) && !receiver_moved(receiver))
+ return false;
+ }
+
+ double speed;
+ double height;
+
+ if (last_flight_tell == TELL_FLIGHT_NONE || last_flight_tell == TELL_FLIGHT_STATE || last_flight_tell == TELL_FLIGHT_TRACK) {
+ last_flight_tell = TELL_FLIGHT_SPEED;
+
+ if (state.state() <= AltosLib.ao_flight_coast) {
+ speed = state.speed();
+ } else {
+ speed = state.gps_speed();
+ if (speed == AltosLib.MISSING)
+ speed = state.speed();
+ }
+
+ if (speed != AltosLib.MISSING) {
+ speak("speed: %s.", AltosConvert.speed.say_units(speed));
+ return true;
+ }
+ }
+
+ if (last_flight_tell == TELL_FLIGHT_SPEED) {
+ last_flight_tell = TELL_FLIGHT_HEIGHT;
+ height = state.height();
+
+ if (height != AltosLib.MISSING) {
+ speak("height: %s.", AltosConvert.height.say_units(height));
+ return true;
+ }
+ }
+
+ if (last_flight_tell == TELL_FLIGHT_HEIGHT) {
+ last_flight_tell = TELL_FLIGHT_TRACK;
+ if (from_receiver != null) {
+ speak("bearing %s %d, elevation %d, distance %s.",
+ from_receiver.bearing_words(
+ AltosGreatCircle.BEARING_VOICE),
+ (int) (from_receiver.bearing + 0.5),
+ (int) (from_receiver.elevation + 0.5),
+ AltosConvert.distance.say(from_receiver.distance));
+ return true;
+ }
+ }
+
+ return spoken;
+ }
+
+ private boolean tell_recover(TelemetryState telem_state, AltosState state,
+ AltosGreatCircle from_receiver, Location receiver) {
+
+ if (from_receiver == null)
+ return false;
+
+ if (last_tell_mode == TELL_MODE_RECOVER) {
+ if (!target_moved(state) && !receiver_moved(receiver))
+ return false;
+ if (time_since_speak() <= 10 * 1000)
+ return false;
+ }
+
+ String direction = AltosDroid.direction(from_receiver, receiver);
+ if (direction == null)
+ direction = String.format("Bearing %d", (int) (from_receiver.bearing + 0.5));
+
+ speak("%s, distance %s.", direction,
+ AltosConvert.distance.say_units(from_receiver.distance));
+
+ return true;
+ }
+
+ public void tell(TelemetryState telem_state, AltosState state,
+ AltosGreatCircle from_receiver, Location receiver,
+ AltosDroidTab tab, boolean quiet) {
+
+ this.quiet = quiet;
+
+ boolean spoken = false;
+
+ if (!tts_enabled) return;
+
+ if (is_speaking()) return;
+
+ int tell_serial = last_tell_serial;
+
+ if (state != null)
+ tell_serial = state.cal_data().serial;
+
+ if (tell_serial != last_tell_serial)
+ reset_last();
+
+ int tell_mode = TELL_MODE_NONE;
+
+ if (tab.tab_name().equals(AltosDroid.tab_pad_name))
+ tell_mode = TELL_MODE_PAD;
+ else if (tab.tab_name().equals(AltosDroid.tab_flight_name))
+ tell_mode = TELL_MODE_FLIGHT;
+ else
+ tell_mode = TELL_MODE_RECOVER;
+
+ if (tell_mode == TELL_MODE_PAD)
+ spoken = tell_pad(telem_state, state, from_receiver, receiver);
+ else if (tell_mode == TELL_MODE_FLIGHT)
+ spoken = tell_flight(telem_state, state, from_receiver, receiver);
+ else
+ spoken = tell_recover(telem_state, state, from_receiver, receiver);
+
+ if (spoken) {
+ last_tell_mode = tell_mode;
+ last_tell_serial = tell_serial;
+ if (state != null) {
+ last_state = state.state();
+ last_height = state.height();
+ if (state.gps != null)
+ last_gps = state.gps;
+ }
+ if (receiver != null)
+ last_receiver = receiver;
+ }
+ }
+}
--- /dev/null
+/*
+ * 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; 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.
+ */
+
+package org.altusmetrum.AltosDroid;
+
+public class BuildInfo {
+ public static final String version = "@VERSION@";
+ public static final String git_describe = "@DESCRIBE@";
+ public static final String branch = "@BRANCH@";
+ public static final String commitnum = "@COMMITNUM@";
+ public static final String commithash = "@COMMITHASH@";
+ public static final String builddate = "@BUILDDATE@";
+ public static final String buildtime = "@BUILDTIME@";
+ public static final String buildtz = "@BUILDTZ@";
+}
+
--- /dev/null
+/*
+ * Copyright © 2015 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.
+ */
+
+package org.altusmetrum.AltosDroid;
+
+public class DeviceAddress {
+ public String address;
+ public String name;
+
+ public DeviceAddress(String address, String name) {
+ this.address = address;
+ this.name = name;
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.altusmetrum.AltosDroid;
+
+import java.util.Set;
+
+import android.app.Activity;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.view.View;
+import android.view.Window;
+import android.view.View.OnClickListener;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.ListView;
+import android.widget.TextView;
+import android.widget.AdapterView.OnItemClickListener;
+
+/**
+ * This Activity appears as a dialog. It lists any paired devices and
+ * devices detected in the area after discovery. When a device is chosen
+ * by the user, the MAC address of the device is sent back to the parent
+ * Activity in the result Intent.
+ */
+public class DeviceListActivity extends Activity {
+
+ // Return Intent extra
+ public static final String EXTRA_DEVICE_ADDRESS = "device_address";
+ public static final String EXTRA_DEVICE_NAME = "device_name";
+
+ // Member fields
+ private BluetoothAdapter mBtAdapter;
+ private ArrayAdapter<String> mPairedDevicesArrayAdapter;
+ private ArrayAdapter<String> mNewDevicesArrayAdapter;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Setup the window
+ requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
+ setContentView(R.layout.device_list);
+
+ // Set result CANCELED incase the user backs out
+ setResult(Activity.RESULT_CANCELED);
+
+ // Initialize the button to perform device discovery
+ Button scanButton = (Button) findViewById(R.id.button_scan);
+ scanButton.setOnClickListener(new OnClickListener() {
+ public void onClick(View v) {
+ doDiscovery();
+ v.setVisibility(View.GONE);
+ }
+ });
+
+ // Initialize array adapters. One for already paired devices and
+ // one for newly discovered devices
+ mPairedDevicesArrayAdapter = new ArrayAdapter<String>(this, R.layout.device_name);
+ mNewDevicesArrayAdapter = new ArrayAdapter<String>(this, R.layout.device_name);
+
+ // Find and set up the ListView for paired devices
+ ListView pairedListView = (ListView) findViewById(R.id.paired_devices);
+ pairedListView.setAdapter(mPairedDevicesArrayAdapter);
+ pairedListView.setOnItemClickListener(mDeviceClickListener);
+
+ // Find and set up the ListView for newly discovered devices
+ ListView newDevicesListView = (ListView) findViewById(R.id.new_devices);
+ newDevicesListView.setAdapter(mNewDevicesArrayAdapter);
+ newDevicesListView.setOnItemClickListener(mDeviceClickListener);
+
+ // Register for broadcasts when a device is discovered
+ IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
+ this.registerReceiver(mReceiver, filter);
+
+ // Register for broadcasts when discovery has finished
+ filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
+ this.registerReceiver(mReceiver, filter);
+
+ // Get the local Bluetooth adapter
+ mBtAdapter = BluetoothAdapter.getDefaultAdapter();
+
+ // Get a set of currently paired devices
+ Set<BluetoothDevice> pairedDevices = mBtAdapter.getBondedDevices();
+
+ // If there are paired devices, add each one to the ArrayAdapter
+ if (pairedDevices.size() > 0) {
+ findViewById(R.id.title_paired_devices).setVisibility(View.VISIBLE);
+ for (BluetoothDevice device : pairedDevices)
+ if (device.getName().startsWith("TeleBT"))
+ mPairedDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
+
+ } else {
+ String noDevices = getResources().getText(R.string.none_paired).toString();
+ mPairedDevicesArrayAdapter.add(noDevices);
+ }
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+
+ // Make sure we're not doing discovery anymore
+ if (mBtAdapter != null) {
+ mBtAdapter.cancelDiscovery();
+ }
+
+ // Unregister broadcast listeners
+ this.unregisterReceiver(mReceiver);
+ }
+
+ /**
+ * Start device discover with the BluetoothAdapter
+ */
+ private void doDiscovery() {
+ AltosDebug.debug("doDiscovery()");
+
+ // Indicate scanning in the title
+ setProgressBarIndeterminateVisibility(true);
+ setTitle(R.string.scanning);
+
+ // Turn on sub-title for new devices
+ findViewById(R.id.title_new_devices).setVisibility(View.VISIBLE);
+
+ // If we're already discovering, stop it
+ if (mBtAdapter.isDiscovering()) {
+ mBtAdapter.cancelDiscovery();
+ }
+
+ // Request discover from BluetoothAdapter
+ mBtAdapter.startDiscovery();
+ }
+
+ // The on-click listener for all devices in the ListViews
+ private OnItemClickListener mDeviceClickListener = new OnItemClickListener() {
+ public void onItemClick(AdapterView<?> av, View v, int arg2, long arg3) {
+ // Cancel discovery because it's costly and we're about to connect
+ mBtAdapter.cancelDiscovery();
+
+ // Get the device MAC address, which is the last 17 chars in the View
+ String info = ((TextView) v).getText().toString();
+ String address = info.substring(info.length() - 17);
+
+ int newline = info.indexOf('\n');
+
+ String name = null;
+ if (newline > 0)
+ name = info.substring(0, newline);
+ else
+ name = info;
+
+ AltosDebug.debug("******* selected item '%s'", info);
+
+ // Create the result Intent and include the MAC address
+ Intent intent = new Intent();
+ intent.putExtra(EXTRA_DEVICE_ADDRESS, address);
+ intent.putExtra(EXTRA_DEVICE_NAME, name);
+
+ // Set result and finish this Activity
+ setResult(Activity.RESULT_OK, intent);
+ finish();
+ }
+ };
+
+ // The BroadcastReceiver that listens for discovered devices and
+ // changes the title when discovery is finished
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+
+ // When discovery finds a device
+ if (BluetoothDevice.ACTION_FOUND.equals(action)) {
+
+ /* Get the BluetoothDevice object from the Intent
+ */
+ BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+
+ /* If it's already paired, skip it, because it's been listed already
+ */
+ if (device != null && device.getBondState() != BluetoothDevice.BOND_BONDED)
+ {
+ String name = device.getName();
+ if (name != null && name.startsWith("TeleBT"))
+ mNewDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
+ }
+
+ /* When discovery is finished, change the Activity title
+ */
+ } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
+ setProgressBarIndeterminateVisibility(false);
+ setTitle(R.string.select_device);
+ if (mNewDevicesArrayAdapter.getCount() == 0) {
+ String noDevices = getResources().getText(R.string.none_found).toString();
+ mNewDevicesArrayAdapter.add(noDevices);
+ }
+ }
+ }
+ };
+
+}
--- /dev/null
+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;
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2013 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; 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.
+ */
+
+package org.altusmetrum.AltosDroid;
+
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.widget.ImageView;
+
+public class GoNoGoLights {
+ private Boolean state;
+ private Boolean missing;
+ private Boolean set;
+
+ private ImageView red;
+ private ImageView green;
+
+ private Drawable dRed;
+ private Drawable dGreen;
+ private Drawable dGray;
+
+ public GoNoGoLights(ImageView in_red, ImageView in_green, Resources r) {
+ red = in_red;
+ green = in_green;
+ state = false;
+ missing = true;
+ set = false;
+
+ dRed = r.getDrawable(R.drawable.redled);
+ dGreen = r.getDrawable(R.drawable.greenled);
+ dGray = r.getDrawable(R.drawable.grayled);
+ }
+
+ public void set(Boolean s, Boolean m) {
+ if (set && s == state && m == missing) return;
+ state = s;
+ missing = m;
+ set = true;
+ if (missing) {
+ red.setImageDrawable(dGray);
+ green.setImageDrawable(dGray);
+ } else if (state) {
+ red.setImageDrawable(dGray);
+ green.setImageDrawable(dGreen);
+ } else {
+ red.setImageDrawable(dRed);
+ green.setImageDrawable(dGray);
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2016 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.
+ */
+
+package org.altusmetrum.AltosDroid;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.View;
+import android.view.Window;
+import android.view.View.OnClickListener;
+import android.widget.*;
+
+import org.altusmetrum.altoslib_13.*;
+
+public class IdleModeActivity extends Activity {
+ private EditText callsign;
+ private Button connect;
+ private Button disconnect;
+ private Button reboot;
+ private Button igniters;
+
+ public static final String EXTRA_IDLE_MODE = "idle_mode";
+ public static final String EXTRA_IDLE_RESULT = "idle_result";
+
+ public static final int IDLE_MODE_CONNECT = 1;
+ public static final int IDLE_MODE_REBOOT = 2;
+ public static final int IDLE_MODE_IGNITERS = 3;
+ public static final int IDLE_MODE_DISCONNECT = 4;
+
+ private void done(int type) {
+ AltosPreferences.set_callsign(callsign());
+ Intent intent = new Intent();
+ intent.putExtra(EXTRA_IDLE_RESULT, type);
+ setResult(Activity.RESULT_OK, intent);
+ finish();
+ }
+
+ private String callsign() {
+ return callsign.getEditableText().toString();
+ }
+
+ public void connect_idle() {
+ done(IDLE_MODE_CONNECT);
+ }
+
+ public void disconnect_idle() {
+ AltosDebug.debug("Disconnect idle button pressed");
+ done(IDLE_MODE_DISCONNECT);
+ }
+
+ public void reboot_idle() {
+ done(IDLE_MODE_REBOOT);
+ }
+
+ public void igniters_idle() {
+ done(IDLE_MODE_IGNITERS);
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Setup the window
+ requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
+ setContentView(R.layout.idle_mode);
+
+ callsign = (EditText) findViewById(R.id.set_callsign);
+ callsign.setText(new StringBuffer(AltosPreferences.callsign()));
+
+ connect = (Button) findViewById(R.id.connect_idle);
+ connect.setOnClickListener(new OnClickListener() {
+ public void onClick(View v) {
+ connect_idle();
+ }
+ });
+ disconnect = (Button) findViewById(R.id.disconnect_idle);
+ disconnect.setOnClickListener(new OnClickListener() {
+ public void onClick(View v) {
+ disconnect_idle();
+ }
+ });
+
+ boolean idle_mode = getIntent().getBooleanExtra(AltosDroid.EXTRA_IDLE_MODE, false);
+
+ if (idle_mode)
+ connect.setVisibility(View.GONE);
+ else
+ disconnect.setVisibility(View.GONE);
+
+ reboot = (Button) findViewById(R.id.reboot_idle);
+ reboot.setOnClickListener(new OnClickListener() {
+ public void onClick(View v) {
+ reboot_idle();
+ }
+ });
+ igniters = (Button) findViewById(R.id.igniters_idle);
+ igniters.setOnClickListener(new OnClickListener() {
+ public void onClick(View v) {
+ igniters_idle();
+ }
+ });
+
+ // Set result CANCELED incase the user backs out
+ setResult(Activity.RESULT_CANCELED);
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2016 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.
+ */
+
+package org.altusmetrum.AltosDroid;
+
+import java.lang.ref.WeakReference;
+import java.util.*;
+
+import android.app.Activity;
+import android.content.*;
+import android.graphics.*;
+import android.os.*;
+import android.view.*;
+import android.view.View.*;
+import android.widget.*;
+
+import org.altusmetrum.altoslib_13.*;
+
+class IgniterItem {
+ public String name;
+ public String pretty;
+ public String status;
+ public LinearLayout igniter_view = null;
+ public TextView pretty_view = null;
+ public TextView status_view = null;
+
+ private void update() {
+ if (pretty_view != null)
+ pretty_view.setText(pretty);
+ if (status_view != null)
+ status_view.setText(status);
+ }
+
+ public void set(String name, String pretty, String status) {
+ if (!name.equals(this.name) ||
+ !pretty.equals(this.pretty) ||
+ !status.equals(this.status))
+ {
+ this.name = name;
+ this.pretty = pretty;
+ this.status = status;
+ update();
+ }
+ }
+
+ public void realize(LinearLayout igniter_view,
+ TextView pretty_view,
+ TextView status_view) {
+ if (igniter_view != this.igniter_view ||
+ pretty_view != this.pretty_view ||
+ status_view != this.status_view)
+ {
+ this.igniter_view = igniter_view;
+ this.pretty_view = pretty_view;
+ this.status_view = status_view;
+ update();
+ }
+ }
+
+ public IgniterItem() {
+ }
+}
+
+class IgniterAdapter extends ArrayAdapter<IgniterItem> {
+ int resource;
+ int selected_item = -1;
+
+ public IgniterAdapter(Context context, int in_resource) {
+ super(context, in_resource);
+ resource = in_resource;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ IgniterItem item = getItem(position);
+ if (item.igniter_view == null) {
+ LinearLayout igniter_view = new LinearLayout(getContext());
+ String inflater = Context.LAYOUT_INFLATER_SERVICE;
+ LayoutInflater li = (LayoutInflater) getContext().getSystemService(inflater);
+ li.inflate(resource, igniter_view, true);
+
+ item.realize(igniter_view,
+ (TextView) igniter_view.findViewById(R.id.igniter_name),
+ (TextView) igniter_view.findViewById(R.id.igniter_status));
+ }
+ if (position == selected_item)
+ item.igniter_view.setBackgroundColor(Color.RED);
+ else
+ item.igniter_view.setBackgroundColor(Color.BLACK);
+ return item.igniter_view;
+ }
+}
+
+public class IgniterActivity extends Activity {
+ private ListView igniters_view;
+ private ToggleButton arm;
+ private Button fire;
+
+ private HashMap<String,IgniterItem> igniters = new HashMap<String,IgniterItem>();;
+
+ private IgniterAdapter igniters_adapter;
+
+ private boolean is_bound;
+ private Messenger service = null;
+ private final Messenger messenger = new Messenger(new IncomingHandler(this));
+
+ private Timer query_timer;
+ private boolean query_timer_running;
+
+ private Timer arm_timer;
+ private int arm_remaining;
+
+ public static final int IGNITER_QUERY = 1;
+ public static final int IGNITER_FIRE = 2;
+
+ // The Handler that gets information back from the Telemetry Service
+ static class IncomingHandler extends Handler {
+ private final WeakReference<IgniterActivity> igniter_activity;
+ IncomingHandler(IgniterActivity ia) { igniter_activity = new WeakReference<IgniterActivity>(ia); }
+
+ @Override
+ public void handleMessage(Message msg) {
+ IgniterActivity ia = igniter_activity.get();
+
+ switch (msg.what) {
+ case AltosDroid.MSG_IGNITER_STATUS:
+ ia.igniter_status((HashMap <String,Integer>) msg.obj);
+ break;
+ }
+ }
+ };
+
+
+ private ServiceConnection connection = new ServiceConnection() {
+ public void onServiceConnected(ComponentName className, IBinder binder) {
+ service = new Messenger(binder);
+ query_timer_tick();
+ }
+
+ public void onServiceDisconnected(ComponentName className) {
+ // This is called when the connection with the service has been unexpectedly disconnected - process crashed.
+ service = null;
+ }
+ };
+
+ void doBindService() {
+ bindService(new Intent(this, TelemetryService.class), connection, Context.BIND_AUTO_CREATE);
+ is_bound = true;
+ }
+
+ void doUnbindService() {
+ if (is_bound) {
+ // If we have received the service, and hence registered with it, then now is the time to unregister.
+ unbindService(connection);
+ is_bound = false;
+ }
+ }
+
+ private void done() {
+ Intent intent = new Intent();
+ setResult(Activity.RESULT_OK, intent);
+ finish();
+ }
+
+ class FireThread extends Thread {
+ private final String igniter;
+
+ @Override
+ public void run() {
+ Message msg = Message.obtain(null, TelemetryService.MSG_IGNITER_FIRE, igniter);
+ try {
+ service.send(msg);
+ } catch (RemoteException re) {
+ }
+ }
+
+ public FireThread(String igniter) {
+ this.igniter = igniter;
+ }
+ }
+
+ private void fire_igniter() {
+ if (igniters_adapter.selected_item >= 0) {
+ IgniterItem item = igniters_adapter.getItem(igniters_adapter.selected_item);
+ FireThread ft = new FireThread(item.name);
+ ft.run();
+ arm.setChecked(false);
+ }
+ }
+
+ private void arm_igniter(boolean is_checked) {
+ if (is_checked) {
+ arm_timer_stop();
+ arm_timer = new Timer();
+ arm_remaining = 10;
+ arm_set_text();
+ fire.setEnabled(true);
+ arm_timer.scheduleAtFixedRate(new TimerTask() {
+ public void run() {
+ arm_timer_tick();
+ }},
+ 1000L, 1000L);
+ } else {
+ arm_timer_stop();
+ fire.setEnabled(false);
+ }
+ }
+
+ private synchronized void query_timer_tick() {
+ if (query_timer_running)
+ return;
+ if (service == null)
+ return;
+ query_timer_running = true;
+ Thread thread = new Thread(new Runnable() {
+ public void run() {
+ try {
+ Message msg = Message.obtain(null, TelemetryService.MSG_IGNITER_QUERY);
+ msg.replyTo = messenger;
+ if (service == null) {
+ synchronized(IgniterActivity.this) {
+ query_timer_running = false;
+ }
+ } else
+ service.send(msg);
+ } catch (RemoteException re) {
+ AltosDebug.debug("igniter query thread failed");
+ synchronized(IgniterActivity.this) {
+ query_timer_running = false;
+ }
+ }
+ }
+ });
+ thread.start();
+ }
+
+ private boolean set_igniter(HashMap <String,Integer> status, String name, String pretty) {
+ if (!status.containsKey(name))
+ return false;
+
+ IgniterItem item;
+ if (!igniters.containsKey(name)) {
+ item = new IgniterItem();
+ igniters.put(name, item);
+ igniters_adapter.add(item);
+ } else
+ item = igniters.get(name);
+
+ item.set(name, pretty, AltosIgnite.status_string(status.get(name)));
+ return true;
+ }
+
+ private synchronized void igniter_status(HashMap <String,Integer> status) {
+ query_timer_running = false;
+ if (status == null) {
+ AltosDebug.debug("no igniter status");
+ return;
+ }
+ set_igniter(status, "drogue", "Apogee");
+ set_igniter(status, "main", "Main");
+ for (int extra = 0;; extra++) {
+ String name = String.format("%d", extra);
+ String pretty = String.format("%c", 'A' + extra);
+ if (!set_igniter(status, name, pretty))
+ break;
+ }
+ }
+
+ private synchronized void arm_timer_stop() {
+ if (arm_timer != null) {
+ arm_timer.cancel();
+ arm_timer = null;
+ }
+ arm_remaining = 0;
+ }
+
+ private void arm_set_text() {
+ String text = String.format("Armed %d", arm_remaining);
+
+ if (arm.isChecked())
+ arm.setText(text);
+ arm.setTextOn(text);
+ }
+
+ private void arm_timer_tick() {
+ --arm_remaining;
+ if (arm_remaining <= 0) {
+ arm_timer_stop();
+ runOnUiThread(new Runnable() {
+ public void run() {
+ arm.setChecked(false);
+ fire.setEnabled(false);
+ }
+ });
+ } else {
+ runOnUiThread(new Runnable() {
+ public void run() {
+ arm_set_text();
+ }
+ });
+ }
+ }
+
+ private void select_item(int position) {
+ if (position != igniters_adapter.selected_item) {
+ if (igniters_adapter.selected_item >= 0)
+ igniters_view.setItemChecked(igniters_adapter.selected_item, false);
+ if (position >= 0) {
+ igniters_view.setItemChecked(position, true);
+ arm.setEnabled(true);
+ } else
+ arm.setEnabled(false);
+ igniters_adapter.selected_item = position;
+ }
+ }
+
+ private class IgniterItemClickListener implements ListView.OnItemClickListener {
+ @Override
+ public void onItemClick(AdapterView<?> av, View v, int position, long id) {
+ AltosDebug.debug("select %d\n", position);
+ select_item(position);
+ }
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Setup the window
+ requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
+ setContentView(R.layout.igniters);
+
+ igniters_view = (ListView) findViewById(R.id.igniters);
+ igniters_view.setClickable(true);
+
+ igniters_adapter = new IgniterAdapter(this, R.layout.igniter_status);
+
+ igniters_view.setAdapter(igniters_adapter);
+ igniters_view.setOnItemClickListener(new IgniterItemClickListener());
+
+ fire = (Button) findViewById(R.id.igniter_fire);
+ fire.setEnabled(false);
+ fire.setOnClickListener(new OnClickListener() {
+ public void onClick(View v) {
+ fire_igniter();
+ }
+ });
+
+ arm = (ToggleButton) findViewById(R.id.igniter_arm);
+ arm.setEnabled(false);
+ arm.setOnCheckedChangeListener(new ToggleButton.OnCheckedChangeListener() {
+ public void onCheckedChanged(CompoundButton v, boolean is_checked) {
+ arm_igniter(is_checked);
+ }
+ });
+
+ // Set result CANCELED incase the user backs out
+ setResult(Activity.RESULT_CANCELED);
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ doBindService();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ query_timer = new Timer(true);
+ query_timer.scheduleAtFixedRate(new TimerTask() {
+ public void run() {
+ query_timer_tick();
+ }},
+ 0L, 5000L);
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ if (query_timer != null) {
+ query_timer.cancel();
+ query_timer = null;
+ }
+ arm_timer_stop();
+ arm.setChecked(false);
+ fire.setEnabled(false);
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ doUnbindService();
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2016 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.
+ */
+
+package org.altusmetrum.AltosDroid;
+
+import java.util.*;
+import java.text.*;
+
+import android.app.Activity;
+import android.content.*;
+import android.graphics.*;
+import android.os.*;
+import android.view.*;
+import android.view.View.*;
+import android.view.inputmethod.*;
+import android.widget.*;
+
+import org.altusmetrum.altoslib_13.*;
+
+class FrequencyItem {
+ public AltosFrequency frequency;
+ public LinearLayout frequency_view = null;
+ public TextView pretty_view = null;
+
+ private void update() {
+ if (pretty_view != null && frequency != null)
+ pretty_view.setText(frequency.toString());
+ }
+
+ public void realize(LinearLayout frequency_view,
+ TextView pretty_view) {
+ if (frequency_view != this.frequency_view ||
+ pretty_view != this.pretty_view)
+ {
+ this.frequency_view = frequency_view;
+ this.pretty_view = pretty_view;
+ update();
+ }
+ }
+
+ public void set_frequency(AltosFrequency frequency) {
+ this.frequency = frequency;
+ update();
+ }
+
+ public FrequencyItem(AltosFrequency frequency) {
+ this.frequency = frequency;
+ }
+}
+
+class FrequencyAdapter extends ArrayAdapter<FrequencyItem> {
+ int resource;
+ int selected_item = -1;
+
+ public FrequencyAdapter(Context context, int in_resource) {
+ super(context, in_resource);
+ resource = in_resource;
+ }
+
+ public int count() {
+ int count;
+
+ for (count = 0;; count++) {
+ try {
+ getItem(count);
+ } catch (IndexOutOfBoundsException ie) {
+ return count;
+ }
+ }
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ FrequencyItem item = getItem(position);
+ if (item.frequency_view == null) {
+ LinearLayout frequency_view = new LinearLayout(getContext());
+ String inflater = Context.LAYOUT_INFLATER_SERVICE;
+ LayoutInflater li = (LayoutInflater) getContext().getSystemService(inflater);
+ li.inflate(resource, frequency_view, true);
+
+ item.realize(frequency_view,
+ (TextView) frequency_view.findViewById(R.id.frequency));
+ }
+ if (position == selected_item)
+ item.frequency_view.setBackgroundColor(Color.RED);
+ else
+ item.frequency_view.setBackgroundColor(Color.BLACK);
+ return item.frequency_view;
+ }
+}
+
+public class ManageFrequenciesActivity extends Activity {
+ private ListView frequencies_view;
+
+ private Button set;
+ private Button remove;
+ private Button done;
+
+ private EditText set_frequency;
+ private EditText set_description;
+
+ private HashMap<String,FrequencyItem> frequencies = new HashMap<String,FrequencyItem>();;
+
+ private FrequencyAdapter frequencies_adapter;
+
+ private boolean is_bound;
+ private boolean changed = false;
+
+ private void done() {
+
+ set();
+
+ if (changed) {
+ AltosFrequency[] frequencies = new AltosFrequency[frequencies_adapter.count()];
+ for (int i = 0; i < frequencies.length; i++)
+ frequencies[i] = frequencies_adapter.getItem(i).frequency;
+ AltosPreferences.set_common_frequencies(frequencies);
+ }
+
+ Intent intent = new Intent();
+ setResult(Activity.RESULT_OK, intent);
+ finish();
+ }
+
+ private void load_item() {
+ if (frequencies_adapter.selected_item >= 0) {
+ FrequencyItem item = frequencies_adapter.getItem(frequencies_adapter.selected_item);
+
+ set_frequency.setText(item.frequency.frequency_string());
+ set_description.setText(item.frequency.description);
+ } else {
+ set_frequency.setText("");
+ set_description.setText("");
+ }
+ }
+
+ private void select_item(int position) {
+ if (position != frequencies_adapter.selected_item) {
+ if (frequencies_adapter.selected_item >= 0)
+ frequencies_view.setItemChecked(frequencies_adapter.selected_item, false);
+ if (position >= 0)
+ frequencies_view.setItemChecked(position, true);
+ frequencies_adapter.selected_item = position;
+ } else {
+ if (frequencies_adapter.selected_item >= 0)
+ frequencies_view.setItemChecked(frequencies_adapter.selected_item, false);
+ frequencies_adapter.selected_item = -1;
+ }
+ load_item();
+ }
+
+ private int find(AltosFrequency frequency) {
+ for (int pos = 0; pos < frequencies_adapter.getCount(); pos++) {
+ FrequencyItem item = frequencies_adapter.getItem(pos);
+ if (item.frequency.frequency == frequency.frequency &&
+ item.frequency.description.equals(frequency.description))
+ return pos;
+ }
+ return -1;
+ }
+
+ private int insert_item(AltosFrequency frequency) {
+ FrequencyItem new_item = new FrequencyItem(frequency);
+ int pos;
+ for (pos = 0; pos < frequencies_adapter.getCount(); pos++) {
+ FrequencyItem item = frequencies_adapter.getItem(pos);
+ if (item.frequency.frequency == new_item.frequency.frequency) {
+ item.set_frequency(frequency);
+ return pos;
+ }
+ if (item.frequency.frequency > new_item.frequency.frequency)
+ break;
+ }
+ frequencies_adapter.insert(new_item, pos);
+ return pos;
+ }
+
+ private class FrequencyItemClickListener implements ListView.OnItemClickListener {
+ @Override
+ public void onItemClick(AdapterView<?> av, View v, int position, long id) {
+ select_item(position);
+ }
+ }
+
+ private void hide_keyboard() {
+ InputMethodManager imm = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
+ View view = getCurrentFocus();
+ if (view != null)
+ imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
+ }
+
+ private void set() {
+ String frequency_text = set_frequency.getEditableText().toString();
+ String description_text = set_description.getEditableText().toString();
+
+ try {
+ double f = AltosParse.parse_double_locale(frequency_text);
+ AltosFrequency frequency = new AltosFrequency(f, description_text);
+ int pos;
+
+ pos = find(frequency);
+ if (pos < 0) {
+ pos = insert_item(frequency);
+ changed = true;
+ }
+ frequencies_adapter.selected_item = -1;
+ select_item(pos);
+ } catch (ParseException pe) {
+ }
+ hide_keyboard();
+ }
+
+ private void remove() {
+ if (frequencies_adapter.selected_item >= 0) {
+ frequencies_adapter.remove(frequencies_adapter.getItem(frequencies_adapter.selected_item));
+ select_item(-1);
+ frequencies_view.setAdapter(frequencies_adapter);
+ changed = true;
+ }
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Setup the window
+ requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
+ setContentView(R.layout.manage_frequencies);
+
+ frequencies_view = (ListView) findViewById(R.id.frequencies);
+ frequencies_view.setClickable(true);
+
+ frequencies_adapter = new FrequencyAdapter(this, R.layout.frequency);
+
+ frequencies_view.setAdapter(frequencies_adapter);
+ frequencies_view.setOnItemClickListener(new FrequencyItemClickListener());
+
+ AltosFrequency[] frequencies = AltosPreferences.common_frequencies();
+ for (AltosFrequency frequency : frequencies)
+ insert_item(frequency);
+
+ set_frequency = (EditText) findViewById(R.id.set_frequency);
+ set_description = (EditText) findViewById(R.id.set_description);
+
+ set = (Button) findViewById(R.id.set);
+ set.setOnClickListener(new OnClickListener() {
+ public void onClick(View v) {
+ set();
+ }
+ });
+
+ remove = (Button) findViewById(R.id.remove);
+ remove.setOnClickListener(new OnClickListener() {
+ public void onClick(View v) {
+ remove();
+ }
+ });
+
+ done = (Button) findViewById(R.id.done);
+ done.setOnClickListener(new OnClickListener() {
+ public void onClick(View v) {
+ done();
+ }
+ });
+
+ // Set result CANCELED incase the user backs out
+ setResult(Activity.RESULT_CANCELED);
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2015 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.
+ */
+
+package org.altusmetrum.AltosDroid;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.View;
+import android.view.Window;
+import android.widget.*;
+
+import org.altusmetrum.altoslib_13.*;
+
+public class MapTypeActivity extends Activity {
+ private Button hybrid;
+ private Button satellite;
+ private Button roadmap;
+ private Button terrain;
+ private int selected_type;
+
+ public static final String EXTRA_MAP_TYPE = "map_type";
+
+ private void done(int type) {
+
+ Intent intent = new Intent();
+ intent.putExtra(EXTRA_MAP_TYPE, type);
+ setResult(Activity.RESULT_OK, intent);
+ finish();
+ }
+
+ public void selectType(View view) {
+ AltosDebug.debug("selectType %s", view.toString());
+ if (view == hybrid)
+ done(AltosMap.maptype_hybrid);
+ if (view == satellite)
+ done(AltosMap.maptype_satellite);
+ if (view == roadmap)
+ done(AltosMap.maptype_roadmap);
+ if (view == terrain)
+ done(AltosMap.maptype_terrain);
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Setup the window
+ requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
+ setContentView(R.layout.map_type);
+
+ hybrid = (Button) findViewById(R.id.map_type_hybrid);
+ satellite = (Button) findViewById(R.id.map_type_satellite);
+ roadmap = (Button) findViewById(R.id.map_type_roadmap);
+ terrain = (Button) findViewById(R.id.map_type_terrain);
+
+ // Set result CANCELED incase the user backs out
+ setResult(Activity.RESULT_CANCELED);
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2015 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.
+ */
+
+package org.altusmetrum.AltosDroid;
+
+import java.util.*;
+import java.text.*;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.View;
+import android.view.Window;
+import android.view.View.OnClickListener;
+import android.widget.*;
+import android.widget.AdapterView.*;
+import android.location.Location;
+import android.location.LocationManager;
+import android.location.LocationListener;
+
+import org.altusmetrum.altoslib_13.*;
+
+/**
+ * This Activity appears as a dialog. It lists any paired devices and
+ * devices detected in the area after discovery. When a device is chosen
+ * by the user, the MAC address of the device is sent back to the parent
+ * Activity in the result Intent.
+ */
+public class PreloadMapActivity extends Activity implements AltosLaunchSiteListener, AltosMapLoaderListener, LocationListener {
+
+ private ArrayAdapter<AltosLaunchSite> known_sites_adapter;
+
+/*
+ private CheckBox hybrid;
+ private CheckBox satellite;
+ private CheckBox roadmap;
+ private CheckBox terrain;
+*/
+
+ private Spinner known_sites_spinner;
+ private Spinner min_zoom;
+ private Spinner max_zoom;
+ private TextView radius_label;
+ private Spinner radius;
+
+ private EditText latitude;
+ private EditText longitude;
+
+ private ProgressBar progress;
+
+ private AltosMapLoader loader;
+
+ long loader_notify_time;
+
+ /* AltosMapLoaderListener interfaces */
+ public void loader_start(final int max) {
+ loader_notify_time = System.currentTimeMillis();
+
+ this.runOnUiThread(new Runnable() {
+ public void run() {
+ progress.setMax(max);
+ progress.setProgress(0);
+ }
+ });
+ }
+
+ public void loader_notify(final int cur, final int max, final String name) {
+ long now = System.currentTimeMillis();
+
+ if (now - loader_notify_time < 100)
+ return;
+
+ loader_notify_time = now;
+
+ this.runOnUiThread(new Runnable() {
+ public void run() {
+ progress.setProgress(cur);
+ }
+ });
+ }
+
+ public void loader_done(int max) {
+ loader = null;
+ this.runOnUiThread(new Runnable() {
+ public void run() {
+ progress.setProgress(0);
+ finish();
+ }
+ });
+ }
+
+ public void debug(String format, Object ... arguments) {
+ AltosDebug.debug(format, arguments);
+ }
+
+ /* AltosLaunchSiteListener interface */
+
+ public void notify_launch_sites(final List<AltosLaunchSite> sites) {
+ this.runOnUiThread(new Runnable() {
+ public void run() {
+ for (AltosLaunchSite site : sites)
+ known_sites_adapter.add(site);
+ }
+ });
+ }
+
+ /* LocationProvider interface */
+
+ AltosLaunchSite current_location_site;
+
+ public void onLocationChanged(Location location) {
+ AltosDebug.debug("location changed");
+ if (current_location_site == null) {
+ AltosLaunchSite selected_item = (AltosLaunchSite) known_sites_spinner.getSelectedItem();
+
+ current_location_site = new AltosLaunchSite("Current Location", location.getLatitude(), location.getLongitude());
+ known_sites_adapter.insert(current_location_site, 0);
+
+ if (selected_item != null)
+ known_sites_spinner.setSelection(known_sites_adapter.getPosition(selected_item));
+ else {
+ latitude.setText(new StringBuffer(String.format("%12.6f", current_location_site.latitude)));
+ longitude.setText(new StringBuffer(String.format("%12.6f", current_location_site.longitude)));
+ }
+ } else {
+ current_location_site.latitude = location.getLatitude();
+ current_location_site.longitude = location.getLongitude();
+ }
+ }
+
+ public void onStatusChanged(String provider, int status, Bundle extras) {
+ }
+
+ public void onProviderEnabled(String provider) {
+ }
+
+ public void onProviderDisabled(String provider) {
+ }
+
+ private double text(EditText view) throws ParseException {
+ return AltosParse.parse_double_locale(view.getEditableText().toString());
+ }
+
+ private double latitude() throws ParseException {
+ return text(latitude);
+ }
+
+ private double longitude() throws ParseException {
+ return text(longitude);
+ }
+
+ private int value(Spinner spinner) {
+ return (Integer) spinner.getSelectedItem();
+ }
+
+ private int min_z() {
+ return value(min_zoom);
+ }
+
+ private int max_z() {
+ return value(max_zoom);
+ }
+
+ private double value_distance(Spinner spinner) {
+ return (Double) spinner.getSelectedItem();
+ }
+
+ private double radius() {
+ double r = value_distance(radius);
+ if (AltosPreferences.imperial_units())
+ r = AltosConvert.miles_to_meters(r);
+ else
+ r = r * 1000;
+ return r;
+ }
+
+/*
+ private int bit(CheckBox box, int value) {
+ if (box.isChecked())
+ return 1 << value;
+ return 0;
+ }
+*/
+
+ private int types() {
+/*
+ return (bit(hybrid, AltosMap.maptype_hybrid) |
+ bit(satellite, AltosMap.maptype_satellite) |
+ bit(roadmap, AltosMap.maptype_roadmap) |
+ bit(terrain, AltosMap.maptype_terrain));
+*/
+ return 1 << AltosMap.maptype_hybrid;
+ }
+
+ private void load() {
+ if (loader != null)
+ return;
+
+ try {
+ double lat = latitude();
+ double lon = longitude();
+ int min = min_z();
+ int max = max_z();
+ double r = radius();
+ int t = types();
+
+ AltosDebug.debug("PreloadMap load %f %f %d %d %f %d\n",
+ lat, lon, min, max, r, t);
+ loader = new AltosMapLoader(this, lat, lon, min, max, r, t, AltosMapOffline.scale);
+ } catch (ParseException e) {
+ AltosDebug.debug("PreloadMap load raised exception %s", e.toString());
+ }
+ }
+
+ private void add_numbers(Spinner spinner, int min, int max, int def) {
+
+ ArrayAdapter<Integer> adapter = new ArrayAdapter<Integer>(this, android.R.layout.simple_spinner_item);
+
+ int spinner_def = 0;
+ int pos = 0;
+
+ for (int i = min; i <= max; i++) {
+ adapter.add(new Integer(i));
+ if (i == def)
+ spinner_def = pos;
+ pos++;
+ }
+
+ spinner.setAdapter(adapter);
+ spinner.setSelection(spinner_def);
+ }
+
+
+ private void add_distance(Spinner spinner, double[] distances_km, double def_km, double[] distances_mi, double def_mi) {
+
+ ArrayAdapter<Double> adapter = new ArrayAdapter<Double>(this, android.R.layout.simple_spinner_item);
+
+ int spinner_def = 0;
+ int pos = 0;
+
+ double[] distances;
+ double def;
+ if (AltosPreferences.imperial_units()) {
+ distances = distances_mi;
+ def = def_mi;
+ } else {
+ distances = distances_km;
+ def = def_km;
+ }
+
+ for (int i = 0; i < distances.length; i++) {
+ adapter.add(distances[i]);
+ if (distances[i] == def)
+ spinner_def = pos;
+ pos++;
+ }
+
+ spinner.setAdapter(adapter);
+ spinner.setSelection(spinner_def);
+ }
+
+
+
+ class SiteListListener implements OnItemSelectedListener {
+ public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
+ AltosLaunchSite site = (AltosLaunchSite) parent.getItemAtPosition(pos);
+ latitude.setText(new StringBuffer(String.format("%12.6f", site.latitude)));
+ longitude.setText(new StringBuffer(String.format("%12.6f", site.longitude)));
+ }
+ public void onNothingSelected(AdapterView<?> parent) {
+ }
+
+ public SiteListListener() {
+ }
+ }
+
+ double[] radius_mi = { 1, 2, 5, 10, 20 };
+ double radius_def_mi = 2;
+ double[] radius_km = { 1, 2, 5, 10, 20, 30 };
+ double radius_def_km = 2;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Setup the window
+ requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
+ setContentView(R.layout.map_preload);
+
+ // Set result CANCELED incase the user backs out
+ setResult(Activity.RESULT_CANCELED);
+
+ // Initialize the button to perform device discovery
+ Button loadButton = (Button) findViewById(R.id.preload_load);
+ loadButton.setOnClickListener(new OnClickListener() {
+ public void onClick(View v) {
+ load();
+ }
+ });
+
+ latitude = (EditText) findViewById(R.id.preload_latitude);
+ longitude = (EditText) findViewById(R.id.preload_longitude);
+
+/*
+ hybrid = (CheckBox) findViewById(R.id.preload_hybrid);
+ satellite = (CheckBox) findViewById(R.id.preload_satellite);
+ roadmap = (CheckBox) findViewById(R.id.preload_roadmap);
+ terrain = (CheckBox) findViewById(R.id.preload_terrain);
+
+ hybrid.setChecked(true);
+*/
+
+ min_zoom = (Spinner) findViewById(R.id.preload_min_zoom);
+ add_numbers(min_zoom,
+ AltosMap.min_zoom - AltosMap.default_zoom,
+ AltosMap.max_zoom - AltosMap.default_zoom, -2);
+ max_zoom = (Spinner) findViewById(R.id.preload_max_zoom);
+ add_numbers(max_zoom,
+ AltosMap.min_zoom - AltosMap.default_zoom,
+ AltosMap.max_zoom - AltosMap.default_zoom, 2);
+ radius_label = (TextView) findViewById(R.id.preload_radius_label);
+ radius = (Spinner) findViewById(R.id.preload_radius);
+ if (AltosPreferences.imperial_units())
+ radius_label.setText("Radius (miles)");
+ else
+ radius_label.setText("Radius (km)");
+ add_distance(radius, radius_km, radius_def_km, radius_mi, radius_def_mi);
+
+ progress = (ProgressBar) findViewById(R.id.preload_progress);
+
+ // Initialize array adapters. One for already paired devices and
+ // one for newly discovered devices
+ known_sites_spinner = (Spinner) findViewById(R.id.preload_site_list);
+
+ known_sites_adapter = new ArrayAdapter<AltosLaunchSite>(this, android.R.layout.simple_spinner_item);
+
+ known_sites_adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+
+ known_sites_spinner.setAdapter(known_sites_adapter);
+ known_sites_spinner.setOnItemSelectedListener(new SiteListListener());
+
+ // Listen for GPS and Network position updates
+ LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
+
+ locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 1, this);
+
+ new AltosLaunchSites(this);
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+
+ if (loader != null)
+ loader.abort();
+
+ // Stop listening for location updates
+ ((LocationManager) getSystemService(Context.LOCATION_SERVICE)).removeUpdates(this);
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2016 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.
+ */
+
+package org.altusmetrum.AltosDroid;
+
+import android.app.Activity;
+import android.content.*;
+import android.os.*;
+import android.view.*;
+import android.view.View.*;
+import android.widget.*;
+import android.widget.AdapterView.*;
+
+import org.altusmetrum.altoslib_13.*;
+
+public class SetupActivity extends Activity {
+ private Spinner select_rate;
+ private Spinner set_units;
+ private Spinner map_type;
+ private Spinner map_source;
+ private Button manage_frequencies;
+ private Button preload_maps;
+ private Button done;
+
+ private boolean is_bound;
+ private Messenger service = null;
+
+ public final static String EXTRA_SETUP_CHANGES = "setup_changes";
+
+ private ServiceConnection connection = new ServiceConnection() {
+ public void onServiceConnected(ComponentName className, IBinder binder) {
+ service = new Messenger(binder);
+ }
+
+ public void onServiceDisconnected(ComponentName className) {
+ // This is called when the connection with the service has been unexpectedly disconnected - process crashed.
+ service = null;
+ }
+ };
+
+ void doBindService() {
+ bindService(new Intent(this, TelemetryService.class), connection, Context.BIND_AUTO_CREATE);
+ is_bound = true;
+ }
+
+ void doUnbindService() {
+ if (is_bound) {
+ // If we have received the service, and hence registered with it, then now is the time to unregister.
+ unbindService(connection);
+ is_bound = false;
+ }
+ }
+
+ static final String[] rates = {
+ "38400",
+ "9600",
+ "2400",
+ };
+
+ static final String[] map_types = {
+ "Hybrid",
+ "Satellite",
+ "Roadmap",
+ "Terrain"
+ };
+
+ static final int[] map_type_values = {
+ AltosMap.maptype_hybrid,
+ AltosMap.maptype_satellite,
+ AltosMap.maptype_roadmap,
+ AltosMap.maptype_terrain,
+ };
+
+ static final String[] map_sources = {
+ "Online",
+ "Offline"
+ };
+
+ private int set_telemetry_rate;
+ private int set_map_source;
+ private int set_map_type;
+ private boolean set_imperial_units;
+
+ private int changes = 0;
+
+ private void add_change(int change) {
+ changes |= change;
+ }
+
+ private void done() {
+ Intent intent = new Intent();
+ if ((changes & AltosDroid.SETUP_BAUD) != 0)
+ AltosPreferences.set_telemetry_rate(1, set_telemetry_rate);
+ if ((changes & AltosDroid.SETUP_UNITS) != 0)
+ AltosPreferences.set_imperial_units(set_imperial_units);
+ if ((changes & AltosDroid.SETUP_MAP_SOURCE) != 0)
+ AltosDroidPreferences.set_map_source(set_map_source);
+ if ((changes & AltosDroid.SETUP_MAP_TYPE) != 0)
+ AltosPreferences.set_map_type(set_map_type);
+ intent.putExtra(EXTRA_SETUP_CHANGES, changes);
+ setResult(Activity.RESULT_OK, intent);
+ finish();
+ }
+
+ private void add_strings(Spinner spinner, String[] strings, int def) {
+ ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item);
+
+ for (int i = 0; i < strings.length; i++)
+ adapter.add(strings[i]);
+
+ spinner.setAdapter(adapter);
+ if (def >= 0)
+ spinner.setSelection(def);
+ }
+
+ private int default_rate_pos() {
+ int default_rate = AltosPreferences.telemetry_rate(1);
+
+ for (int pos = 0; pos < rates.length; pos++) {
+ if (string_to_rate(rates[pos]) == default_rate)
+ return pos;
+ }
+ return -1;
+ }
+
+ private void setBaud(int baud) {
+ try {
+ service.send(Message.obtain(null, TelemetryService.MSG_SETBAUD, baud));
+ set_telemetry_rate = baud;
+ add_change(AltosDroid.SETUP_BAUD);
+ } catch (RemoteException e) {
+ }
+ }
+
+ private int string_to_rate(String baud) {
+ int rate = AltosLib.ao_telemetry_rate_38400;
+ try {
+ int value = Integer.parseInt(baud);
+ switch (value) {
+ case 2400:
+ rate = AltosLib.ao_telemetry_rate_2400;
+ break;
+ case 9600:
+ rate = AltosLib.ao_telemetry_rate_9600;
+ break;
+ case 38400:
+ rate = AltosLib.ao_telemetry_rate_38400;
+ break;
+ }
+ } catch (NumberFormatException e) {
+ }
+ return rate;
+ }
+
+ private void setBaud(String baud) {
+ setBaud(string_to_rate(baud));
+ }
+
+ private void select_rate(int pos) {
+ setBaud(rates[pos]);
+ }
+
+ static final String[] units = {
+ "Metric",
+ "Imperial"
+ };
+
+ private int default_units_pos() {
+ boolean imperial = AltosPreferences.imperial_units();
+
+ if (imperial)
+ return 1;
+ return 0;
+ }
+
+ private void set_units(int pos) {
+ switch (pos) {
+ default:
+ set_imperial_units = false;
+ break;
+ case 1:
+ set_imperial_units = true;
+ break;
+ }
+ add_change(AltosDroid.SETUP_UNITS);
+ }
+
+ private int default_map_type_pos() {
+ int default_map_type = AltosPreferences.map_type();
+
+ for (int pos = 0; pos < map_types.length; pos++)
+ if (map_type_values[pos] == default_map_type)
+ return pos;
+ return 0;
+ }
+
+ private void select_map_type(int pos) {
+ set_map_type = map_type_values[pos];
+ add_change(AltosDroid.SETUP_MAP_TYPE);
+ }
+
+ private int default_map_source_pos() {
+ int default_source = AltosDroidPreferences.map_source();
+
+ switch (default_source) {
+ case AltosDroidPreferences.MAP_SOURCE_OFFLINE:
+ return 1;
+ default:
+ return 0;
+ }
+ }
+
+ private void select_map_source(int pos) {
+ switch (pos) {
+ default:
+ set_map_source = AltosDroidPreferences.MAP_SOURCE_ONLINE;
+ break;
+ case 1:
+ set_map_source = AltosDroidPreferences.MAP_SOURCE_OFFLINE;
+ break;
+ }
+ add_change(AltosDroid.SETUP_MAP_SOURCE);
+ }
+
+ private void manage_frequencies(){
+ Intent intent = new Intent(this, ManageFrequenciesActivity.class);
+ startActivity(intent);
+ }
+
+ private void preload_maps(){
+ Intent intent = new Intent(this, PreloadMapActivity.class);
+ startActivity(intent);
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ AltosDebug.init(this);
+ AltosDebug.debug("+++ ON CREATE +++");
+
+ // Initialise preferences
+ AltosDroidPreferences.init(this);
+
+ // Setup the window
+ requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
+ setContentView(R.layout.setup);
+
+ select_rate = (Spinner) findViewById(R.id.select_rate);
+ add_strings(select_rate, rates, default_rate_pos());
+ select_rate.setOnItemSelectedListener(new OnItemSelectedListener() {
+ public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
+ select_rate(pos);
+ }
+ public void onNothingSelected(AdapterView<?> parent) {
+ }
+ });
+
+ set_units = (Spinner) findViewById(R.id.set_units);
+ add_strings(set_units, units, default_units_pos());
+ set_units.setOnItemSelectedListener(new OnItemSelectedListener() {
+ public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
+ set_units(pos);
+ }
+ public void onNothingSelected(AdapterView<?> parent) {
+ }
+ });
+
+ map_type = (Spinner) findViewById(R.id.map_type);
+ add_strings(map_type, map_types, default_map_type_pos());
+ map_type.setOnItemSelectedListener(new OnItemSelectedListener() {
+ public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
+ select_map_type(pos);
+ }
+ public void onNothingSelected(AdapterView<?> parent) {
+ }
+ });
+
+ map_source = (Spinner) findViewById(R.id.map_source);
+ add_strings(map_source, map_sources, default_map_source_pos());
+ map_source.setOnItemSelectedListener(new OnItemSelectedListener() {
+ public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
+ select_map_source(pos);
+ }
+ public void onNothingSelected(AdapterView<?> parent) {
+ }
+ });
+
+
+ manage_frequencies = (Button) findViewById(R.id.manage_frequencies);
+ manage_frequencies.setOnClickListener(new OnClickListener() {
+ public void onClick(View v) {
+ manage_frequencies();
+ }
+ });
+
+ preload_maps = (Button) findViewById(R.id.preload_maps);
+ preload_maps.setOnClickListener(new OnClickListener() {
+ public void onClick(View v) {
+ preload_maps();
+ }
+ });
+
+ done = (Button) findViewById(R.id.done);
+ done.setOnClickListener(new OnClickListener() {
+ public void onClick(View v) {
+ done();
+ }
+ });
+
+ // Set result for when the user backs out
+ setResult(Activity.RESULT_CANCELED);
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ doBindService();
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ doUnbindService();
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2013 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; 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.
+ */
+
+package org.altusmetrum.AltosDroid;
+
+import org.altusmetrum.altoslib_13.*;
+
+import android.os.Bundle;
+import android.view.*;
+import android.widget.*;
+import android.location.Location;
+
+public class TabFlight extends AltosDroidTab {
+ private TextView speed_view;
+ private TextView height_view;
+ private TextView max_speed_view;
+ private TextView max_height_view;
+ private TextView elevation_view;
+ private TextView range_view;
+ private TextView bearing_view;
+ private TextView compass_view;
+ private TextView distance_view;
+ private TextView latitude_view;
+ private TextView longitude_view;
+ private View apogee_view;
+ private TextView apogee_voltage_view;
+ private TextView apogee_voltage_label;
+ private GoNoGoLights apogee_lights;
+ private View main_view;
+ private TextView main_voltage_view;
+ private TextView main_voltage_label;
+ private GoNoGoLights main_lights;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ View v = inflater.inflate(R.layout.tab_flight, container, false);
+
+ speed_view = (TextView) v.findViewById(R.id.speed_value);
+ height_view = (TextView) v.findViewById(R.id.height_value);
+ max_speed_view = (TextView) v.findViewById(R.id.max_speed_value);
+ max_height_view= (TextView) v.findViewById(R.id.max_height_value);
+ elevation_view = (TextView) v.findViewById(R.id.elevation_value);
+ range_view = (TextView) v.findViewById(R.id.range_value);
+ bearing_view = (TextView) v.findViewById(R.id.bearing_value);
+ compass_view = (TextView) v.findViewById(R.id.compass_value);
+ distance_view = (TextView) v.findViewById(R.id.distance_value);
+ latitude_view = (TextView) v.findViewById(R.id.lat_value);
+ longitude_view = (TextView) v.findViewById(R.id.lon_value);
+
+ apogee_view = v.findViewById(R.id.apogee_view);
+ apogee_voltage_view = (TextView) v.findViewById(R.id.apogee_voltage_value);
+ apogee_lights = new GoNoGoLights((ImageView) v.findViewById(R.id.apogee_redled),
+ (ImageView) v.findViewById(R.id.apogee_greenled),
+ getResources());
+ apogee_voltage_label = (TextView) v.findViewById(R.id.apogee_voltage_label);
+
+ main_view = v.findViewById(R.id.main_view);
+ main_voltage_view = (TextView) v.findViewById(R.id.main_voltage_value);
+ main_lights = new GoNoGoLights((ImageView) v.findViewById(R.id.main_redled),
+ (ImageView) v.findViewById(R.id.main_greenled),
+ getResources());
+ main_voltage_label = (TextView) v.findViewById(R.id.main_voltage_label);
+
+ return v;
+ }
+
+ public String tab_name() { return AltosDroid.tab_flight_name; }
+
+ public void show(TelemetryState telem_state, AltosState state, AltosGreatCircle from_receiver, Location receiver) {
+ if (state != null) {
+ set_value(speed_view, AltosConvert.speed, 6, state.speed());
+ set_value(height_view, AltosConvert.height, 6, state.height());
+ set_value(max_speed_view, AltosConvert.speed, 6, state.max_speed());
+ set_value(max_height_view, AltosConvert.height, 6, state.max_height());
+ if (from_receiver != null) {
+ elevation_view.setText(AltosDroid.number("%3.0f°", from_receiver.elevation));
+ set_value(range_view, AltosConvert.distance, 6, from_receiver.range);
+ bearing_view.setText(AltosDroid.number("%3.0f°", from_receiver.bearing));
+ compass_view.setText(from_receiver.bearing_words(AltosGreatCircle.BEARING_LONG));
+ set_value(distance_view, AltosConvert.distance, 6, from_receiver.distance);
+ } else {
+ elevation_view.setText("<unknown>");
+ range_view.setText("<unknown>");
+ bearing_view.setText("<unknown>");
+ compass_view.setText("<unknown>");
+ distance_view.setText("<unknown>");
+ }
+ if (state.gps != null) {
+ latitude_view.setText(AltosDroid.pos(state.gps.lat, "N", "S"));
+ longitude_view.setText(AltosDroid.pos(state.gps.lon, "E", "W"));
+ }
+
+ if (state.apogee_voltage == AltosLib.MISSING) {
+ apogee_view.setVisibility(View.GONE);
+ } else {
+ apogee_voltage_view.setText(AltosDroid.number("%4.2f V", state.apogee_voltage));
+ apogee_lights.set(state.apogee_voltage > 3.2, state.apogee_voltage == AltosLib.MISSING);
+ apogee_view.setVisibility(View.VISIBLE);
+ }
+
+ if (state.main_voltage == AltosLib.MISSING) {
+ main_view.setVisibility(View.GONE);
+ } else {
+ main_voltage_view.setText(AltosDroid.number("%4.2f V", state.main_voltage));
+ main_lights.set(state.main_voltage > 3.2, state.main_voltage == AltosLib.MISSING);
+ main_view.setVisibility(View.VISIBLE);
+ }
+ }
+ }
+
+}
--- /dev/null
+/*
+ * Copyright © 2013 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; 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.
+ */
+
+package org.altusmetrum.AltosDroid;
+
+import org.altusmetrum.altoslib_13.*;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.*;
+import android.widget.*;
+import android.location.Location;
+
+public class TabMap extends AltosDroidTab implements AltosDroidMapSourceListener {
+
+ AltosLatLon here;
+
+ private TextView mDistanceView;
+ private TextView mBearingLabel;
+ private TextView mBearingView;
+ private TextView mTargetLatitudeView;
+ private TextView mTargetLongitudeView;
+ private TextView mReceiverLatitudeView;
+ private TextView mReceiverLongitudeView;
+ private AltosMapOffline map_offline;
+ private AltosMapOnline map_online;
+ private View view;
+ private int map_source;
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ view = inflater.inflate(R.layout.tab_map, container, false);
+ int map_source = AltosDroidPreferences.map_source();
+
+ mDistanceView = (TextView)view.findViewById(R.id.distance_value);
+ mBearingLabel = (TextView)view.findViewById(R.id.bearing_label);
+ mBearingView = (TextView)view.findViewById(R.id.bearing_value);
+ mTargetLatitudeView = (TextView)view.findViewById(R.id.target_lat_value);
+ mTargetLongitudeView = (TextView)view.findViewById(R.id.target_lon_value);
+ mReceiverLatitudeView = (TextView)view.findViewById(R.id.receiver_lat_value);
+ mReceiverLongitudeView = (TextView)view.findViewById(R.id.receiver_lon_value);
+ map_offline = (AltosMapOffline)view.findViewById(R.id.map_offline);
+ map_offline.onCreateView(altos_droid);
+ map_online = new AltosMapOnline(view.getContext());
+ map_online.onCreateView(altos_droid);
+ map_source_changed(AltosDroidPreferences.map_source());
+ AltosDroidPreferences.register_map_source_listener(this);
+ return view;
+ }
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ if (map_online != null)
+ getChildFragmentManager().beginTransaction().add(R.id.map_online, map_online.mMapFragment).commit();
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ map_offline.onDestroyView();
+ map_online.onDestroyView();
+ AltosDroidPreferences.unregister_map_source_listener(this);
+ }
+
+ public String tab_name() { return AltosDroid.tab_map_name; }
+
+ private void center(double lat, double lon, double accuracy) {
+ if (map_offline != null)
+ map_offline.center(lat, lon, accuracy);
+ if (map_online != null)
+ map_online.center(lat, lon, accuracy);
+ }
+
+ public void show(TelemetryState telem_state, AltosState state, AltosGreatCircle from_receiver, Location receiver) {
+ if (from_receiver != null) {
+ String direction = AltosDroid.direction(from_receiver, receiver);
+ if (direction != null) {
+ mBearingLabel.setText("Direction");
+ mBearingView.setText(direction);
+ } else {
+ mBearingLabel.setText("Bearing");
+ mBearingView.setText(String.format("%3.0f°", from_receiver.bearing));
+ }
+ set_value(mDistanceView, AltosConvert.distance, 6, from_receiver.distance);
+ } else {
+ mBearingLabel.setText("Bearing");
+ mBearingView.setText("");
+ set_value(mDistanceView, AltosConvert.distance, 6, AltosLib.MISSING);
+ }
+
+ if (state != null) {
+ if (state.gps != null) {
+ mTargetLatitudeView.setText(AltosDroid.pos(state.gps.lat, "N", "S"));
+ mTargetLongitudeView.setText(AltosDroid.pos(state.gps.lon, "E", "W"));
+ }
+ }
+
+ if (receiver != null) {
+ double accuracy;
+
+ here = new AltosLatLon(receiver.getLatitude(), receiver.getLongitude());
+ if (receiver.hasAccuracy())
+ accuracy = receiver.getAccuracy();
+ else
+ accuracy = 1000;
+ mReceiverLatitudeView.setText(AltosDroid.pos(here.lat, "N", "S"));
+ mReceiverLongitudeView.setText(AltosDroid.pos(here.lon, "E", "W"));
+ center (here.lat, here.lon, accuracy);
+ }
+ if (map_source == AltosDroidPreferences.MAP_SOURCE_OFFLINE) {
+ if (map_offline != null)
+ map_offline.show(telem_state, state, from_receiver, receiver);
+ } else {
+ if (map_online != null)
+ map_online.show(telem_state, state, from_receiver, receiver);
+ }
+ }
+
+ public void map_source_changed(int map_source) {
+ this.map_source = map_source;
+ if (map_source == AltosDroidPreferences.MAP_SOURCE_OFFLINE) {
+ if (map_online != null)
+ map_online.set_visible(false);
+ if (map_offline != null) {
+ map_offline.set_visible(true);
+ map_offline.show(last_telem_state, last_state, last_from_receiver, last_receiver);
+ }
+ } else {
+ if (map_offline != null)
+ map_offline.set_visible(false);
+ if (map_online != null) {
+ map_online.set_visible(true);
+ map_online.show(last_telem_state, last_state, last_from_receiver, last_receiver);
+ }
+ }
+ }
+
+ public TabMap() {
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2013 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; 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.
+ */
+
+package org.altusmetrum.AltosDroid;
+
+import org.altusmetrum.altoslib_13.*;
+
+import android.os.Bundle;
+import android.view.*;
+import android.widget.*;
+import android.location.Location;
+
+public class TabPad extends AltosDroidTab {
+ private TextView battery_voltage_view;
+ private GoNoGoLights battery_lights;
+
+ private TableRow receiver_row;
+ private TextView receiver_voltage_view;
+ private TextView receiver_voltage_label;
+ private GoNoGoLights receiver_voltage_lights;
+
+ private TableRow apogee_row;
+ private TextView apogee_voltage_view;
+ private TextView apogee_voltage_label;
+ private GoNoGoLights apogee_lights;
+
+ private TableRow main_row;
+ private TextView main_voltage_view;
+ private TextView main_voltage_label;
+ private GoNoGoLights main_lights;
+
+ private TextView data_logging_view;
+ private GoNoGoLights data_logging_lights;
+
+ private TextView gps_locked_view;
+ private GoNoGoLights gps_locked_lights;
+
+ private TextView gps_ready_view;
+ private GoNoGoLights gps_ready_lights;
+
+ private TextView receiver_latitude_view;
+ private TextView receiver_longitude_view;
+ private TextView receiver_altitude_view;
+
+ private TableRow[] ignite_row = new TableRow[4];
+ private TextView[] ignite_voltage_view = new TextView[4];
+ private TextView[] ignite_voltage_label = new TextView[4];
+ private GoNoGoLights[] ignite_lights = new GoNoGoLights[4];
+
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ View v = inflater.inflate(R.layout.tab_pad, container, false);
+ battery_voltage_view = (TextView) v.findViewById(R.id.battery_voltage_value);
+ battery_lights = new GoNoGoLights((ImageView) v.findViewById(R.id.battery_redled),
+ (ImageView) v.findViewById(R.id.battery_greenled),
+ getResources());
+
+ receiver_row = (TableRow) v.findViewById(R.id.receiver_row);
+ receiver_voltage_view = (TextView) v.findViewById(R.id.receiver_voltage_value);
+ receiver_voltage_label = (TextView) v.findViewById(R.id.receiver_voltage_label);
+ receiver_voltage_lights = new GoNoGoLights((ImageView) v.findViewById(R.id.receiver_redled),
+ (ImageView) v.findViewById(R.id.receiver_greenled),
+ getResources());
+
+ apogee_row = (TableRow) v.findViewById(R.id.apogee_row);
+ apogee_voltage_view = (TextView) v.findViewById(R.id.apogee_voltage_value);
+ apogee_voltage_label = (TextView) v.findViewById(R.id.apogee_voltage_label);
+ apogee_lights = new GoNoGoLights((ImageView) v.findViewById(R.id.apogee_redled),
+ (ImageView) v.findViewById(R.id.apogee_greenled),
+ getResources());
+
+ main_row = (TableRow) v.findViewById(R.id.main_row);
+ main_voltage_view = (TextView) v.findViewById(R.id.main_voltage_value);
+ main_voltage_label = (TextView) v.findViewById(R.id.main_voltage_label);
+ main_lights = new GoNoGoLights((ImageView) v.findViewById(R.id.main_redled),
+ (ImageView) v.findViewById(R.id.main_greenled),
+ getResources());
+
+ data_logging_view = (TextView) v.findViewById(R.id.logging_value);
+ data_logging_lights = new GoNoGoLights((ImageView) v.findViewById(R.id.logging_redled),
+ (ImageView) v.findViewById(R.id.logging_greenled),
+ getResources());
+
+ gps_locked_view = (TextView) v.findViewById(R.id.gps_locked_value);
+ gps_locked_lights = new GoNoGoLights((ImageView) v.findViewById(R.id.gps_locked_redled),
+ (ImageView) v.findViewById(R.id.gps_locked_greenled),
+ getResources());
+
+ gps_ready_view = (TextView) v.findViewById(R.id.gps_ready_value);
+ gps_ready_lights = new GoNoGoLights((ImageView) v.findViewById(R.id.gps_ready_redled),
+ (ImageView) v.findViewById(R.id.gps_ready_greenled),
+ getResources());
+
+ for (int i = 0; i < 4; i++) {
+ int row_id, view_id, label_id, lights_id;
+ int red_id, green_id;
+ switch (i) {
+ case 0:
+ default:
+ row_id = R.id.ignite_a_row;
+ view_id = R.id.ignite_a_voltage_value;
+ label_id = R.id.ignite_a_voltage_label;
+ red_id = R.id.ignite_a_redled;
+ green_id = R.id.ignite_a_greenled;
+ break;
+ case 1:
+ row_id = R.id.ignite_b_row;
+ view_id = R.id.ignite_b_voltage_value;
+ label_id = R.id.ignite_b_voltage_label;
+ red_id = R.id.ignite_b_redled;
+ green_id = R.id.ignite_b_greenled;
+ break;
+ case 2:
+ row_id = R.id.ignite_c_row;
+ view_id = R.id.ignite_c_voltage_value;
+ label_id = R.id.ignite_c_voltage_label;
+ red_id = R.id.ignite_c_redled;
+ green_id = R.id.ignite_c_greenled;
+ break;
+ case 3:
+ row_id = R.id.ignite_d_row;
+ view_id = R.id.ignite_d_voltage_value;
+ label_id = R.id.ignite_d_voltage_label;
+ red_id = R.id.ignite_d_redled;
+ green_id = R.id.ignite_d_greenled;
+ break;
+ }
+ ignite_row[i] = (TableRow) v.findViewById(row_id);
+ ignite_voltage_view[i] = (TextView) v.findViewById(view_id);
+ ignite_voltage_label[i] = (TextView) v.findViewById(label_id);
+ ignite_lights[i] = new GoNoGoLights((ImageView) v.findViewById(red_id),
+ (ImageView) v.findViewById(green_id),
+ getResources());
+ }
+
+ receiver_latitude_view = (TextView) v.findViewById(R.id.receiver_lat_value);
+ receiver_longitude_view = (TextView) v.findViewById(R.id.receiver_lon_value);
+ receiver_altitude_view = (TextView) v.findViewById(R.id.receiver_alt_value);
+ return v;
+ }
+
+ public String tab_name() { return AltosDroid.tab_pad_name; }
+
+ public void show(TelemetryState telem_state, AltosState state, AltosGreatCircle from_receiver, Location receiver) {
+ if (state != null) {
+ battery_voltage_view.setText(AltosDroid.number(" %4.2f V", state.battery_voltage));
+ battery_lights.set(state.battery_voltage >= AltosLib.ao_battery_good, state.battery_voltage == AltosLib.MISSING);
+ if (state.apogee_voltage == AltosLib.MISSING) {
+ apogee_row.setVisibility(View.GONE);
+ } else {
+ apogee_voltage_view.setText(AltosDroid.number(" %4.2f V", state.apogee_voltage));
+ apogee_row.setVisibility(View.VISIBLE);
+ }
+ apogee_lights.set(state.apogee_voltage >= AltosLib.ao_igniter_good, state.apogee_voltage == AltosLib.MISSING);
+ if (state.main_voltage == AltosLib.MISSING) {
+ main_row.setVisibility(View.GONE);
+ } else {
+ main_voltage_view.setText(AltosDroid.number(" %4.2f V", state.main_voltage));
+ main_row.setVisibility(View.VISIBLE);
+ }
+ main_lights.set(state.main_voltage >= AltosLib.ao_igniter_good, state.main_voltage == AltosLib.MISSING);
+
+ int num_igniter = state.igniter_voltage == null ? 0 : state.igniter_voltage.length;
+
+ for (int i = 0; i < 4; i++) {
+ double voltage = i >= num_igniter ? AltosLib.MISSING : state.igniter_voltage[i];
+ if (voltage == AltosLib.MISSING) {
+ ignite_row[i].setVisibility(View.GONE);
+ } else {
+ ignite_voltage_view[i].setText(AltosDroid.number(" %4.2f V", voltage));
+ ignite_row[i].setVisibility(View.VISIBLE);
+ }
+ ignite_lights[i].set(voltage >= AltosLib.ao_igniter_good, voltage == AltosLib.MISSING);
+ }
+
+ if (state.cal_data().flight != 0) {
+ if (state.state() <= AltosLib.ao_flight_pad)
+ data_logging_view.setText("Ready to record");
+ else if (state.state() < AltosLib.ao_flight_landed)
+ data_logging_view.setText("Recording data");
+ else
+ data_logging_view.setText("Recorded data");
+ } else {
+ data_logging_view.setText("Storage full");
+ }
+ data_logging_lights.set(state.cal_data().flight != 0, state.cal_data().flight == AltosLib.MISSING);
+
+ if (state.gps != null) {
+ int soln = state.gps.nsat;
+ int nsat = state.gps.cc_gps_sat != null ? state.gps.cc_gps_sat.length : 0;
+ gps_locked_view.setText(String.format("%d in soln, %d in view", soln, nsat));
+ gps_locked_lights.set(state.gps.locked && state.gps.nsat >= 4, false);
+ if (state.gps_ready)
+ gps_ready_view.setText("Ready");
+ else
+ gps_ready_view.setText(AltosDroid.integer("Waiting %d", state.gps_waiting));
+ } else
+ gps_locked_lights.set(false, true);
+ gps_ready_lights.set(state.gps_ready, state.gps == null);
+ }
+
+ if (telem_state != null) {
+ if (telem_state.receiver_battery == AltosLib.MISSING) {
+ receiver_row.setVisibility(View.GONE);
+ } else {
+ receiver_voltage_view.setText(AltosDroid.number(" %4.2f V", telem_state.receiver_battery));
+ receiver_row.setVisibility(View.VISIBLE);
+ }
+ receiver_voltage_lights.set(telem_state.receiver_battery >= AltosLib.ao_battery_good, telem_state.receiver_battery == AltosLib.MISSING);
+ }
+
+ if (receiver != null) {
+ double altitude = AltosLib.MISSING;
+ if (receiver.hasAltitude())
+ altitude = receiver.getAltitude();
+ receiver_latitude_view.setText(AltosDroid.pos(receiver.getLatitude(), "N", "S"));
+ receiver_longitude_view.setText(AltosDroid.pos(receiver.getLongitude(), "E", "W"));
+ set_value(receiver_altitude_view, AltosConvert.height, 1, altitude);
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2013 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; 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.
+ */
+
+package org.altusmetrum.AltosDroid;
+
+import org.altusmetrum.altoslib_13.*;
+
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+import android.location.Location;
+
+public class TabRecover extends AltosDroidTab {
+ private TextView mBearingView;
+ private TextView mDirectionView;
+ private TextView mDistanceView;
+ private TextView mTargetLatitudeView;
+ private TextView mTargetLongitudeView;
+ private TextView mReceiverLatitudeView;
+ private TextView mReceiverLongitudeView;
+ private TextView mMaxHeightView;
+ private TextView mMaxSpeedView;
+ private TextView mMaxAccelView;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ View v = inflater.inflate(R.layout.tab_recover, container, false);
+
+ mBearingView = (TextView) v.findViewById(R.id.bearing_value);
+ mDirectionView = (TextView) v.findViewById(R.id.direction_value);
+ mDistanceView = (TextView) v.findViewById(R.id.distance_value);
+ mTargetLatitudeView = (TextView) v.findViewById(R.id.target_lat_value);
+ mTargetLongitudeView = (TextView) v.findViewById(R.id.target_lon_value);
+ mReceiverLatitudeView = (TextView) v.findViewById(R.id.receiver_lat_value);
+ mReceiverLongitudeView = (TextView) v.findViewById(R.id.receiver_lon_value);
+ mMaxHeightView = (TextView) v.findViewById(R.id.max_height_value);
+ mMaxSpeedView = (TextView) v.findViewById(R.id.max_speed_value);
+ mMaxAccelView = (TextView) v.findViewById(R.id.max_accel_value);
+
+ return v;
+ }
+
+ public String tab_name() { return AltosDroid.tab_recover_name; }
+
+ public void show(TelemetryState telem_state, AltosState state, AltosGreatCircle from_receiver, Location receiver) {
+ if (from_receiver != null) {
+ mBearingView.setText(String.format("%3.0f°", from_receiver.bearing));
+ set_value(mDistanceView, AltosConvert.distance, 6, from_receiver.distance);
+ String direction = AltosDroid.direction(from_receiver, receiver);
+ if (direction == null)
+ mDirectionView.setText("");
+ else
+ mDirectionView.setText(direction);
+ }
+ if (state != null && state.gps != null) {
+ mTargetLatitudeView.setText(AltosDroid.pos(state.gps.lat, "N", "S"));
+ mTargetLongitudeView.setText(AltosDroid.pos(state.gps.lon, "E", "W"));
+ }
+
+ if (receiver != null) {
+ mReceiverLatitudeView.setText(AltosDroid.pos(receiver.getLatitude(), "N", "S"));
+ mReceiverLongitudeView.setText(AltosDroid.pos(receiver.getLongitude(), "E", "W"));
+ }
+
+ if (state != null) {
+ set_value(mMaxHeightView, AltosConvert.height, 6, state.max_height());
+ set_value(mMaxAccelView, AltosConvert.accel, 6, state.max_acceleration());
+ set_value(mMaxSpeedView, AltosConvert.speed, 6, state.max_speed());
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.altusmetrum.AltosDroid;
+
+import java.util.ArrayList;
+
+import android.content.Context;
+import android.os.Bundle;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentActivity;
+import androidx.fragment.app.FragmentPagerAdapter;
+import androidx.viewpager.widget.ViewPager;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TabHost;
+import android.widget.TabWidget;
+
+/**
+ * This is a helper class that implements the management of tabs and all
+ * details of connecting a ViewPager with associated TabHost. It relies on a
+ * trick. Normally a tab host has a simple API for supplying a View or
+ * Intent that each tab will show. This is not sufficient for switching
+ * between pages. So instead we make the content part of the tab host
+ * 0dp high (it is not shown) and the TabsAdapter supplies its own dummy
+ * view to show as the tab content. It listens to changes in tabs, and takes
+ * care of switch to the correct paged in the ViewPager whenever the selected
+ * tab changes.
+ */
+public class TabsAdapter extends FragmentPagerAdapter
+ implements TabHost.OnTabChangeListener, ViewPager.OnPageChangeListener {
+ private final Context mContext;
+ private final TabHost mTabHost;
+ private final ViewPager mViewPager;
+ private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
+ private int position;
+
+ static class TabInfo {
+ private final String tag;
+ private final Class<?> clss;
+ private final Bundle args;
+ private Fragment fragment;
+
+ TabInfo(String _tag, Class<?> _class, Bundle _args) {
+ tag = _tag;
+ clss = _class;
+ args = _args;
+ }
+ }
+
+ static class DummyTabFactory implements TabHost.TabContentFactory {
+ private final Context mContext;
+
+ public DummyTabFactory(Context context) {
+ mContext = context;
+ }
+
+ public View createTabContent(String tag) {
+ View v = new View(mContext);
+ v.setMinimumWidth(0);
+ v.setMinimumHeight(0);
+ return v;
+ }
+ }
+
+ public TabsAdapter(FragmentActivity activity, TabHost tabHost, ViewPager pager) {
+ super(activity.getSupportFragmentManager());
+ mContext = activity;
+ mTabHost = tabHost;
+ mViewPager = pager;
+ mTabHost.setOnTabChangedListener(this);
+ mViewPager.setAdapter(this);
+ mViewPager.setOnPageChangeListener(this);
+ }
+
+ public void addTab(TabHost.TabSpec tabSpec, Class<?> clss, Bundle args) {
+ tabSpec.setContent(new DummyTabFactory(mContext));
+ String tag = tabSpec.getTag();
+
+ TabInfo info = new TabInfo(tag, clss, args);
+ mTabs.add(info);
+ mTabHost.addTab(tabSpec);
+ notifyDataSetChanged();
+ }
+
+ @Override
+ public int getCount() {
+ return mTabs.size();
+ }
+
+ @Override
+ public Fragment getItem(int position) {
+ TabInfo info = mTabs.get(position);
+ AltosDebug.debug("TabsAdapter.getItem(%d)", position);
+ info.fragment = Fragment.instantiate(mContext, info.clss.getName(), info.args);
+ return info.fragment;
+ }
+
+ public Fragment currentItem() {
+ TabInfo info = mTabs.get(position);
+ return info.fragment;
+ }
+
+ public void onTabChanged(String tabId) {
+ AltosDroidTab prev_frag = (AltosDroidTab) mTabs.get(position).fragment;
+
+ position = mTabHost.getCurrentTab();
+
+ AltosDroidTab cur_frag = (AltosDroidTab) mTabs.get(position).fragment;
+
+ if (prev_frag != cur_frag) {
+ if (prev_frag != null) {
+ prev_frag.set_visible(false);
+ }
+ }
+ if (cur_frag != null) {
+ cur_frag.set_visible(true);
+ }
+ AltosDebug.debug("TabsAdapter.onTabChanged(%s) = %d", tabId, position);
+ mViewPager.setCurrentItem(position);
+ }
+
+ public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+ }
+
+ public void onPageSelected(int position) {
+ // Unfortunately when TabHost changes the current tab, it kindly
+ // also takes care of putting focus on it when not in touch mode.
+ // The jerk.
+ // This hack tries to prevent this from pulling focus out of our
+ // ViewPager.
+ TabWidget widget = mTabHost.getTabWidget();
+ int oldFocusability = widget.getDescendantFocusability();
+ widget.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
+ mTabHost.setCurrentTab(position);
+ widget.setDescendantFocusability(oldFocusability);
+ }
+
+ public void onPageScrollStateChanged(int state) {
+ }
+}
--- /dev/null
+package org.altusmetrum.AltosDroid;
+
+import org.altusmetrum.altoslib_13.*;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Environment;
+
+public class TelemetryLogger {
+ private Context context = null;
+ private AltosLink link = null;
+ private AltosLog logger = null;
+
+ private BroadcastReceiver mExternalStorageReceiver;
+
+ public TelemetryLogger(Context in_context, AltosLink in_link) {
+ context = in_context;
+ link = in_link;
+
+ startWatchingExternalStorage();
+ }
+
+ public void stop() {
+ stopWatchingExternalStorage();
+ close();
+ }
+
+ private void close() {
+ if (logger != null) {
+ AltosDebug.debug("Shutting down Telemetry Logging");
+ logger.close();
+ logger = null;
+ }
+ }
+
+ void handleExternalStorageState() {
+ String state = Environment.getExternalStorageState();
+ if (Environment.MEDIA_MOUNTED.equals(state)) {
+ if (logger == null) {
+ AltosDebug.debug("Starting up Telemetry Logging");
+ logger = new AltosLog(link);
+ }
+ } else {
+ AltosDebug.debug("External Storage not present - stopping");
+ close();
+ }
+ }
+
+ void startWatchingExternalStorage() {
+ mExternalStorageReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ handleExternalStorageState();
+ }
+ };
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_MEDIA_MOUNTED);
+ filter.addAction(Intent.ACTION_MEDIA_REMOVED);
+ context.registerReceiver(mExternalStorageReceiver, filter);
+ handleExternalStorageState();
+ }
+
+ void stopWatchingExternalStorage() {
+ context.unregisterReceiver(mExternalStorageReceiver);
+ }
+
+}
--- /dev/null
+/*
+ * 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; 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.
+ */
+
+
+package org.altusmetrum.AltosDroid;
+
+import java.text.*;
+import java.io.*;
+import java.util.concurrent.*;
+import android.os.Handler;
+
+import org.altusmetrum.altoslib_13.*;
+
+
+public class TelemetryReader extends Thread {
+
+ int crc_errors;
+
+ Handler handler;
+
+ AltosLink link;
+
+ LinkedBlockingQueue<AltosLine> telemQueue;
+
+ public AltosTelemetry 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);
+ return telem;
+ }
+
+ public void close() {
+ link.remove_monitor(telemQueue);
+ link = null;
+ telemQueue.clear();
+ telemQueue = null;
+ }
+
+ public void run() {
+ try {
+ AltosDebug.debug("starting loop");
+ while (telemQueue != null) {
+ try {
+ AltosTelemetry telem = read();
+ telem.set_frequency(link.frequency);
+ handler.obtainMessage(TelemetryService.MSG_TELEMETRY, telem).sendToTarget();
+ } catch (ParseException pp) {
+ AltosDebug.error("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) {
+ AltosDebug.error("IO exception in telemetry reader");
+ handler.obtainMessage(TelemetryService.MSG_DISCONNECTED, link).sendToTarget();
+ } finally {
+ close();
+ }
+ }
+
+ public TelemetryReader (AltosLink in_link, Handler in_handler) {
+ AltosDebug.debug("connected TelemetryReader create started");
+ link = in_link;
+ handler = in_handler;
+
+ telemQueue = new LinkedBlockingQueue<AltosLine>();
+ link.add_monitor(telemQueue);
+ link.set_telemetry(AltosLib.ao_telemetry_standard);
+
+ AltosDebug.debug("connected TelemetryReader created");
+ }
+}
--- /dev/null
+/*
+ * 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; 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.
+ */
+
+package org.altusmetrum.AltosDroid;
+
+import java.lang.ref.WeakReference;
+import java.util.concurrent.TimeoutException;
+import java.util.*;
+
+import android.app.*;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothAdapter;
+import android.graphics.Color;
+import android.hardware.usb.*;
+import android.content.Intent;
+import android.content.Context;
+import android.os.*;
+import android.widget.Toast;
+
+import org.altusmetrum.altoslib_13.*;
+
+public class TelemetryService extends Service implements AltosIdleMonitorListener {
+
+ static final int MSG_REGISTER_CLIENT = 1;
+ static final int MSG_UNREGISTER_CLIENT = 2;
+ static final int MSG_CONNECT = 3;
+ static final int MSG_OPEN_USB = 4;
+ static final int MSG_CONNECTED = 5;
+ static final int MSG_CONNECT_FAILED = 6;
+ static final int MSG_DISCONNECTED = 7;
+ static final int MSG_TELEMETRY = 8;
+ static final int MSG_SETFREQUENCY = 9;
+ static final int MSG_CRC_ERROR = 10;
+ static final int MSG_SETBAUD = 11;
+ static final int MSG_DISCONNECT = 12;
+ static final int MSG_DELETE_SERIAL = 13;
+ static final int MSG_BLUETOOTH_ENABLED = 14;
+ static final int MSG_MONITOR_IDLE_START= 15;
+ static final int MSG_MONITOR_IDLE_STOP = 16;
+ static final int MSG_REBOOT = 17;
+ static final int MSG_IGNITER_QUERY = 18;
+ static final int MSG_IGNITER_FIRE = 19;
+
+ // Unique Identification Number for the Notification.
+ // We use it on Notification start, and to cancel it.
+ private int NOTIFICATION = R.string.telemetry_service_label;
+ //private NotificationManager mNM;
+
+ ArrayList<Messenger> clients = new ArrayList<Messenger>(); // Keeps track of all current registered clients.
+ final Handler handler = new IncomingHandler(this);
+ final Messenger messenger = new Messenger(handler); // Target we publish for clients to send messages to IncomingHandler.
+
+ // Name of the connected device
+ DeviceAddress address;
+ private AltosDroidLink altos_link = null;
+ private TelemetryReader telemetry_reader = null;
+ private TelemetryLogger telemetry_logger = null;
+
+ // Local Bluetooth adapter
+ private BluetoothAdapter bluetooth_adapter = null;
+
+ // Last data seen; send to UI when it starts
+ private TelemetryState telemetry_state;
+
+ // Idle monitor if active
+ AltosIdleMonitor idle_monitor = null;
+
+ // Igniter bits
+ AltosIgnite ignite = null;
+ boolean ignite_running;
+
+ // Handler of incoming messages from clients.
+ static class IncomingHandler extends Handler {
+ private final WeakReference<TelemetryService> service;
+ IncomingHandler(TelemetryService s) { service = new WeakReference<TelemetryService>(s); }
+
+ @Override
+ public void handleMessage(Message msg) {
+ DeviceAddress address;
+
+ TelemetryService s = service.get();
+ AltosDroidLink bt = null;
+ if (s == null)
+ return;
+
+ switch (msg.what) {
+
+ /* Messages from application */
+ case MSG_REGISTER_CLIENT:
+ s.add_client(msg.replyTo);
+ break;
+ case MSG_UNREGISTER_CLIENT:
+ s.remove_client(msg.replyTo);
+ break;
+ case MSG_CONNECT:
+ AltosDebug.debug("Connect command received");
+ address = (DeviceAddress) msg.obj;
+ AltosDroidPreferences.set_active_device(address);
+ s.start_altos_bluetooth(address, false);
+ break;
+ case MSG_OPEN_USB:
+ AltosDebug.debug("Open USB command received");
+ UsbDevice device = (UsbDevice) msg.obj;
+ s.start_usb(device);
+ break;
+ case MSG_DISCONNECT:
+ AltosDebug.debug("Disconnect command received");
+ s.address = null;
+ if (!(Boolean) msg.obj)
+ AltosDroidPreferences.set_active_device(null);
+ s.disconnect(true);
+ break;
+ case MSG_DELETE_SERIAL:
+ AltosDebug.debug("Delete Serial command received");
+ s.delete_serial((Integer) msg.obj);
+ break;
+ case MSG_SETFREQUENCY:
+ AltosDebug.debug("MSG_SETFREQUENCY");
+ s.telemetry_state.frequency = (Double) msg.obj;
+ if (s.telemetry_state.connect == TelemetryState.CONNECT_CONNECTED) {
+ try {
+ s.altos_link.set_radio_frequency(s.telemetry_state.frequency);
+ s.altos_link.save_frequency();
+ } catch (InterruptedException e) {
+ } catch (TimeoutException e) {
+ }
+ }
+ s.send_to_clients();
+ break;
+ case MSG_SETBAUD:
+ AltosDebug.debug("MSG_SETBAUD");
+ s.telemetry_state.telemetry_rate = (Integer) msg.obj;
+ if (s.telemetry_state.connect == TelemetryState.CONNECT_CONNECTED) {
+ s.altos_link.set_telemetry_rate(s.telemetry_state.telemetry_rate);
+ s.altos_link.save_telemetry_rate();
+ }
+ s.send_to_clients();
+ break;
+
+ /*
+ *Messages from AltosBluetooth
+ */
+ case MSG_CONNECTED:
+ AltosDebug.debug("MSG_CONNECTED");
+ bt = (AltosDroidLink) msg.obj;
+
+ if (bt != s.altos_link) {
+ AltosDebug.debug("Stale message");
+ break;
+ }
+ AltosDebug.debug("Connected to device");
+ try {
+ s.connected();
+ } catch (InterruptedException ie) {
+ }
+ break;
+ case MSG_CONNECT_FAILED:
+ AltosDebug.debug("MSG_CONNECT_FAILED");
+ bt = (AltosDroidLink) msg.obj;
+
+ if (bt != s.altos_link) {
+ AltosDebug.debug("Stale message");
+ break;
+ }
+ if (s.address != null) {
+ AltosDebug.debug("Connection failed... retrying");
+ s.start_altos_bluetooth(s.address, true);
+ } else {
+ s.disconnect(true);
+ }
+ break;
+ case MSG_DISCONNECTED:
+
+ /* This can be sent by either AltosDroidLink or TelemetryReader */
+ AltosDebug.debug("MSG_DISCONNECTED");
+ bt = (AltosDroidLink) msg.obj;
+
+ if (bt != s.altos_link) {
+ AltosDebug.debug("Stale message");
+ break;
+ }
+ if (s.address != null) {
+ AltosDebug.debug("Connection lost... retrying");
+ s.start_altos_bluetooth(s.address, true);
+ } else {
+ s.disconnect(true);
+ }
+ break;
+
+ /*
+ * Messages from TelemetryReader
+ */
+ case MSG_TELEMETRY:
+ s.telemetry((AltosTelemetry) msg.obj);
+ break;
+ case MSG_CRC_ERROR:
+ // forward crc error messages
+ s.telemetry_state.crc_errors = (Integer) msg.obj;
+ s.send_to_clients();
+ break;
+ case MSG_BLUETOOTH_ENABLED:
+ AltosDebug.debug("TelemetryService notes that BT is now enabled");
+ address = AltosDroidPreferences.active_device();
+ if (address != null && !address.address.startsWith("USB"))
+ s.start_altos_bluetooth(address, false);
+ break;
+ case MSG_MONITOR_IDLE_START:
+ AltosDebug.debug("start monitor idle");
+ s.start_idle_monitor();
+ break;
+ case MSG_MONITOR_IDLE_STOP:
+ AltosDebug.debug("stop monitor idle");
+ s.stop_idle_monitor();
+ break;
+ case MSG_REBOOT:
+ AltosDebug.debug("reboot");
+ s.reboot_remote();
+ break;
+ case MSG_IGNITER_QUERY:
+ AltosDebug.debug("igniter query");
+ s.igniter_query(msg.replyTo);
+ break;
+ case MSG_IGNITER_FIRE:
+ AltosDebug.debug("igniter fire");
+ s.igniter_fire((String) msg.obj);
+ break;
+ default:
+ super.handleMessage(msg);
+ }
+ }
+ }
+
+ /* Handle telemetry packet
+ */
+ private void telemetry(AltosTelemetry telem) {
+ AltosState state;
+
+ if (telemetry_state.states.containsKey(telem.serial()))
+ state = telemetry_state.states.get(telem.serial());
+ else
+ state = new AltosState(new AltosCalData());
+ telem.provide_data(state);
+ telemetry_state.states.put(telem.serial(), state);
+ telemetry_state.quiet = false;
+ if (state != null) {
+ AltosPreferences.set_state(state,telem.serial());
+ }
+ send_to_clients();
+ }
+
+ /* Construct the message to deliver to clients
+ */
+ private Message message() {
+ if (telemetry_state == null)
+ AltosDebug.debug("telemetry_state null!");
+ if (telemetry_state.states == null)
+ AltosDebug.debug("telemetry_state.states null!");
+ return Message.obtain(null, AltosDroid.MSG_STATE, telemetry_state);
+ }
+
+ /* A new friend has connected
+ */
+ private void add_client(Messenger client) {
+
+ clients.add(client);
+ AltosDebug.debug("Client bound to service");
+
+ /* On connect, send the current state to the new client
+ */
+ send_to_client(client);
+ send_idle_mode_to_client(client);
+
+ /* If we've got an address from a previous session, then
+ * go ahead and try to reconnect to the device
+ */
+ if (address != null && telemetry_state.connect == TelemetryState.CONNECT_DISCONNECTED) {
+ AltosDebug.debug("Reconnecting now...");
+ start_altos_bluetooth(address, false);
+ }
+ }
+
+ /* A client has disconnected, clean up
+ */
+ private void remove_client(Messenger client) {
+ clients.remove(client);
+ AltosDebug.debug("Client unbound from service");
+
+ /* When the list of clients is empty, stop the service if
+ * we have no current telemetry source
+ */
+
+ if (clients.isEmpty() && telemetry_state.connect == TelemetryState.CONNECT_DISCONNECTED) {
+ AltosDebug.debug("No clients, no connection. Stopping\n");
+ stopSelf();
+ }
+ }
+
+ private void send_to_client(Messenger client) {
+ Message m = message();
+ try {
+ client.send(m);
+ } catch (RemoteException e) {
+ AltosDebug.error("Client %s disappeared", client.toString());
+ remove_client(client);
+ }
+ }
+
+ private void send_to_clients() {
+ for (Messenger client : clients)
+ send_to_client(client);
+ }
+
+ private void send_idle_mode_to_client(Messenger client) {
+ Message m = Message.obtain(null, AltosDroid.MSG_IDLE_MODE, idle_monitor != null);
+ try {
+ client.send(m);
+ } catch (RemoteException e) {
+ AltosDebug.error("Client %s disappeared", client.toString());
+ remove_client(client);
+ }
+ }
+
+ private void send_idle_mode_to_clients() {
+ for (Messenger client : clients)
+ send_idle_mode_to_client(client);
+ }
+
+ private void telemetry_start() {
+ if (telemetry_reader == null && idle_monitor == null && !ignite_running) {
+ telemetry_reader = new TelemetryReader(altos_link, handler);
+ telemetry_reader.start();
+ }
+ }
+
+ private void telemetry_stop() {
+ if (telemetry_reader != null) {
+ AltosDebug.debug("disconnect(): stopping TelemetryReader");
+ telemetry_reader.interrupt();
+ try {
+ telemetry_reader.join();
+ } catch (InterruptedException e) {
+ }
+ telemetry_reader = null;
+ }
+ }
+
+ private void disconnect(boolean notify) {
+ AltosDebug.debug("disconnect(): begin");
+
+ telemetry_state.connect = TelemetryState.CONNECT_DISCONNECTED;
+ telemetry_state.address = null;
+
+ if (idle_monitor != null)
+ stop_idle_monitor();
+
+ if (altos_link != null)
+ altos_link.closing();
+
+ stop_receiver_voltage_timer();
+
+ telemetry_stop();
+ if (telemetry_logger != null) {
+ AltosDebug.debug("disconnect(): stopping TelemetryLogger");
+ telemetry_logger.stop();
+ telemetry_logger = null;
+ }
+ if (altos_link != null) {
+ AltosDebug.debug("disconnect(): stopping AltosDroidLink");
+ altos_link.close();
+ altos_link = null;
+ ignite = null;
+ }
+ telemetry_state.config = null;
+ if (notify) {
+ AltosDebug.debug("disconnect(): send message to clients");
+ send_to_clients();
+ if (clients.isEmpty()) {
+ AltosDebug.debug("disconnect(): no clients, terminating");
+ stopSelf();
+ }
+ }
+ }
+
+ private void start_usb(UsbDevice device) {
+ AltosUsb d = new AltosUsb(this, device, handler);
+
+ if (d != null) {
+ disconnect(false);
+ altos_link = d;
+ try {
+ connected();
+ } catch (InterruptedException ie) {
+ }
+ }
+ }
+
+ private void delete_serial(int serial) {
+ telemetry_state.states.remove((Integer) serial);
+ AltosPreferences.remove_state(serial);
+ send_to_clients();
+ }
+
+ private void start_altos_bluetooth(DeviceAddress address, boolean pause) {
+ if (bluetooth_adapter == null || !bluetooth_adapter.isEnabled())
+ return;
+
+ disconnect(false);
+
+ // Get the BluetoothDevice object
+ BluetoothDevice device = bluetooth_adapter.getRemoteDevice(address.address);
+
+ this.address = address;
+ AltosDebug.debug("start_altos_bluetooth(): Connecting to %s (%s)", device.getName(), device.getAddress());
+ altos_link = new AltosBluetooth(device, handler, pause);
+ telemetry_state.connect = TelemetryState.CONNECT_CONNECTING;
+ telemetry_state.address = address;
+ send_to_clients();
+ }
+
+ private void start_idle_monitor() {
+ if (altos_link != null && idle_monitor == null) {
+ telemetry_stop();
+ idle_monitor = new AltosIdleMonitor(this, altos_link, true, false);
+ idle_monitor.set_callsign(AltosPreferences.callsign());
+ idle_monitor.start();
+ send_idle_mode_to_clients();
+ }
+ }
+
+ private void stop_idle_monitor() {
+ if (idle_monitor != null) {
+ try {
+ idle_monitor.abort();
+ } catch (InterruptedException ie) {
+ }
+ idle_monitor = null;
+ telemetry_start();
+ send_idle_mode_to_clients();
+ }
+ }
+
+ private void reboot_remote() {
+ if (altos_link != null) {
+ stop_idle_monitor();
+ try {
+ altos_link.start_remote();
+ altos_link.printf("r eboot\n");
+ altos_link.flush_output();
+ } catch (TimeoutException te) {
+ } catch (InterruptedException ie) {
+ } finally {
+ try {
+ altos_link.stop_remote();
+ } catch (InterruptedException ie) {
+ }
+ }
+ }
+ }
+
+ private void ensure_ignite() {
+ if (ignite == null)
+ ignite = new AltosIgnite(altos_link, true, false);
+ }
+
+ private synchronized void igniter_query(Messenger client) {
+ ensure_ignite();
+ HashMap<String,Integer> status_map = null;
+ ignite_running = true;
+ try {
+ stop_idle_monitor();
+ try {
+ status_map = ignite.status();
+ } catch (InterruptedException ie) {
+ AltosDebug.debug("ignite.status interrupted");
+ } catch (TimeoutException te) {
+ AltosDebug.debug("ignite.status timeout");
+ }
+ } finally {
+ ignite_running = false;
+ }
+ Message m = Message.obtain(null, AltosDroid.MSG_IGNITER_STATUS, status_map);
+ try {
+ client.send(m);
+ } catch (RemoteException e) {
+ }
+ }
+
+ private synchronized void igniter_fire(String igniter) {
+ ensure_ignite();
+ ignite_running = true;
+ stop_idle_monitor();
+ try {
+ ignite.fire(igniter);
+ } catch (InterruptedException ie) {
+ } finally {
+ ignite_running = false;
+ }
+ }
+
+ // Timer for receiver battery voltage monitoring
+ Timer receiver_voltage_timer;
+
+ private void update_receiver_voltage() {
+ if (altos_link != null && idle_monitor == null && !ignite_running) {
+ try {
+ double voltage = altos_link.monitor_battery();
+ telemetry_state.receiver_battery = voltage;
+ send_to_clients();
+ } catch (InterruptedException ie) {
+ }
+ }
+ }
+
+ private void stop_receiver_voltage_timer() {
+ if (receiver_voltage_timer != null) {
+ receiver_voltage_timer.cancel();
+ receiver_voltage_timer.purge();
+ receiver_voltage_timer = null;
+ }
+ }
+
+ private void start_receiver_voltage_timer() {
+ if (receiver_voltage_timer == null && altos_link.has_monitor_battery()) {
+ receiver_voltage_timer = new Timer();
+ receiver_voltage_timer.scheduleAtFixedRate(new TimerTask() { public void run() {update_receiver_voltage();}}, 1000L, 10000L);
+ }
+ }
+
+ private void connected() throws InterruptedException {
+ AltosDebug.debug("connected top");
+ AltosDebug.check_ui("connected\n");
+ try {
+ if (altos_link == null)
+ throw new InterruptedException("no bluetooth");
+ telemetry_state.config = altos_link.config_data();
+ altos_link.set_radio_frequency(telemetry_state.frequency);
+ altos_link.set_telemetry_rate(telemetry_state.telemetry_rate);
+ } catch (TimeoutException e) {
+ // If this timed out, then we really want to retry it, but
+ // probably safer to just retry the connection from scratch.
+ AltosDebug.debug("connected timeout");
+ if (address != null) {
+ AltosDebug.debug("connected timeout, retrying");
+ start_altos_bluetooth(address, true);
+ } else {
+ handler.obtainMessage(MSG_CONNECT_FAILED).sendToTarget();
+ disconnect(true);
+ }
+ return;
+ }
+
+ AltosDebug.debug("connected bluetooth configured");
+ telemetry_state.connect = TelemetryState.CONNECT_CONNECTED;
+ telemetry_state.address = address;
+
+ telemetry_start();
+
+ AltosDebug.debug("connected TelemetryReader started");
+
+ telemetry_logger = new TelemetryLogger(this, altos_link);
+
+ start_receiver_voltage_timer();
+
+ AltosDebug.debug("Notify UI of connection");
+
+ send_to_clients();
+ }
+
+
+ @Override
+ public void onCreate() {
+
+ AltosDebug.init(this);
+
+ // Initialise preferences
+ AltosDroidPreferences.init(this);
+
+ // Get local Bluetooth adapter
+ bluetooth_adapter = BluetoothAdapter.getDefaultAdapter();
+
+ telemetry_state = new TelemetryState();
+
+ // Create a reference to the NotificationManager so that we can update our notifcation text later
+ //mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
+
+ telemetry_state.connect = TelemetryState.CONNECT_DISCONNECTED;
+ telemetry_state.address = null;
+
+ /* Pull the saved state information out of the preferences database
+ */
+ ArrayList<Integer> serials = AltosPreferences.list_states();
+
+ telemetry_state.latest_serial = AltosPreferences.latest_state();
+
+ telemetry_state.quiet = true;
+
+ AltosDebug.debug("latest serial %d\n", telemetry_state.latest_serial);
+
+ for (int serial : serials) {
+ AltosState saved_state = AltosPreferences.state(serial);
+ if (saved_state != null) {
+ if (telemetry_state.latest_serial == 0)
+ telemetry_state.latest_serial = serial;
+
+ AltosDebug.debug("recovered old state serial %d flight %d",
+ serial,
+ saved_state.cal_data().flight);
+ if (saved_state.gps != null)
+ AltosDebug.debug("\tposition %f,%f",
+ saved_state.gps.lat,
+ saved_state.gps.lon);
+ telemetry_state.states.put(serial, saved_state);
+ } else {
+ AltosDebug.debug("Failed to recover state for %d", serial);
+ AltosPreferences.remove_state(serial);
+ }
+ }
+ }
+
+
+ private String createNotificationChannel(String channelId, String channelName) {
+ NotificationChannel chan = new NotificationChannel(
+ channelId, channelName, NotificationManager.IMPORTANCE_NONE);
+ chan.setLightColor(Color.BLUE);
+ chan.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
+ NotificationManager service = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
+ service.createNotificationChannel(chan);
+ return channelId;
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ AltosDebug.debug("Received start id %d: %s", startId, intent);
+
+ // The PendingIntent to launch our activity if the user selects this notification
+ PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
+ new Intent(this, AltosDroid.class), 0);
+
+ String channelId =
+ (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
+ ? createNotificationChannel("altosdroid_telemetry", "AltosDroid Telemetry Service")
+ : "";
+
+ // Create notification to be displayed while the service runs
+ Notification notification = new Notification.Builder(this, channelId)
+ .setContentTitle(getText(R.string.telemetry_service_label))
+ .setContentText(getText(R.string.telemetry_service_started))
+ .setContentIntent(contentIntent)
+ .setWhen(System.currentTimeMillis())
+ .setOngoing(true)
+ .setSmallIcon(R.drawable.am_status_c)
+// .setLargeIcon(R.drawable.am_status_c)
+ .build();
+
+ // Move us into the foreground.
+ startForeground(NOTIFICATION, notification);
+
+ /* Start bluetooth if we don't have a connection already */
+ if (intent != null &&
+ (telemetry_state.connect == TelemetryState.CONNECT_NONE ||
+ telemetry_state.connect == TelemetryState.CONNECT_DISCONNECTED))
+ {
+ String action = intent.getAction();
+
+ if (action.equals(AltosDroid.ACTION_BLUETOOTH)) {
+ DeviceAddress address = AltosDroidPreferences.active_device();
+ if (address != null && !address.address.startsWith("USB"))
+ start_altos_bluetooth(address, false);
+ }
+ }
+
+ // We want this service to continue running until it is explicitly
+ // stopped, so return sticky.
+ return START_STICKY;
+ }
+
+ @Override
+ public void onDestroy() {
+
+ // Stop the bluetooth Comms threads
+ disconnect(true);
+
+ // Demote us from the foreground, and cancel the persistent notification.
+ stopForeground(true);
+
+ // Tell the user we stopped.
+ Toast.makeText(this, R.string.telemetry_service_stopped, Toast.LENGTH_SHORT).show();
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return messenger.getBinder();
+ }
+
+ /* AltosIdleMonitorListener */
+ public void update(AltosState state, AltosListenerState listener_state) {
+ telemetry_state.states.put(state.cal_data().serial, state);
+ telemetry_state.receiver_battery = listener_state.battery;
+ send_to_clients();
+ }
+
+ public void failed() {
+ }
+
+ public void error(String reason) {
+ stop_idle_monitor();
+ }
+}
--- /dev/null
+/*
+ * 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; 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.
+ */
+
+package org.altusmetrum.AltosDroid;
+
+import java.util.*;
+import org.altusmetrum.altoslib_13.*;
+
+public class TelemetryState {
+ public static final int CONNECT_NONE = 0;
+ public static final int CONNECT_DISCONNECTED = 1;
+ public static final int CONNECT_CONNECTING = 2;
+ public static final int CONNECT_CONNECTED = 3;
+
+ int connect;
+ DeviceAddress address;
+ AltosConfigData config;
+ int crc_errors;
+ double receiver_battery;
+ double frequency;
+ int telemetry_rate;
+
+ boolean quiet;
+
+ HashMap<Integer,AltosState> states;
+
+ int latest_serial;
+
+ public TelemetryState() {
+ connect = CONNECT_NONE;
+ config = null;
+ states = new HashMap<Integer,AltosState>();
+ crc_errors = 0;
+ receiver_battery = AltosLib.MISSING;
+ frequency = AltosPreferences.frequency(0);
+ telemetry_rate = AltosPreferences.telemetry_rate(0);
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+ Copyright © 2012-2013 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; 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.
+
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="0"
+ android:orientation="vertical" >
+
+ <LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="0"
+ android:baselineAligned="true"
+ android:orientation="horizontal" >
+
+ <RelativeLayout
+ android:id="@+id/callsign_container"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" >
+
+ <TextView
+ android:id="@+id/callsign_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/callsign_label" />
+
+ <TextView
+ android:id="@+id/callsign_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@+id/callsign_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:id="@+id/serial_container"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" >
+
+ <TextView
+ android:id="@+id/serial_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/serial_label" />
+
+ <TextView
+ android:id="@+id/serial_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@+id/serial_label"
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:id="@+id/flight_container"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" >
+
+ <TextView
+ android:id="@+id/flight_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/flight_label" />
+
+ <TextView
+ android:id="@+id/flight_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@+id/flight_label"
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:id="@+id/state_container"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" >
+
+ <TextView
+ android:id="@+id/state_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/state_label" />
+
+ <TextView
+ android:id="@+id/state_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@+id/state_label"
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:id="@+id/rssi_container"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" >
+
+ <TextView
+ android:id="@+id/rssi_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/rssi_label" />
+
+ <TextView
+ android:id="@+id/rssi_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@+id/rssi_label"
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:id="@+id/age_container"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" >
+
+ <TextView
+ android:id="@+id/age_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/age_label" />
+
+ <TextView
+ android:id="@+id/age_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@+id/age_label"
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+ </LinearLayout>
+
+ <TabHost
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/tabhost"
+ android:layout_width="fill_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1" >
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical" >
+
+ <TabWidget
+ android:id="@android:id/tabs"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="0"
+ android:orientation="horizontal" />
+
+ <FrameLayout
+ android:id="@android:id/tabcontent"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_weight="0" />
+
+ <org.altusmetrum.AltosDroid.AltosViewPager
+ android:id="@+id/pager"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1" />
+ </LinearLayout>
+ </TabHost>
+
+ <TextView
+ android:id="@+id/version"
+ android:layout_width="fill_parent"
+ android:layout_height="10dip"
+ android:layout_weight="0"
+ android:gravity="bottom|right"
+ android:textSize="7sp"
+ android:typeface="monospace" />
+
+</LinearLayout>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ >
+ <TextView android:id="@+id/title_left_text"
+ android:layout_alignParentLeft="true"
+ android:ellipsize="end"
+ android:singleLine="true"
+ style="?android:attr/windowTitleStyle"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ />
+ <TextView android:id="@+id/title_right_text"
+ android:layout_alignParentRight="true"
+ android:ellipsize="end"
+ android:singleLine="true"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:textColor="#fff"
+ android:layout_weight="1"
+ />
+</RelativeLayout>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+ Copyright © 2016 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.
+
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ >
+ <Button android:id="@+id/button_scan"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/button_scan"
+ />
+ <TextView android:id="@+id/title_new_devices"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/title_other_devices"
+ android:visibility="gone"
+ android:background="#666"
+ android:textColor="#fff"
+ android:paddingLeft="5dp"
+ />
+ <ListView android:id="@+id/new_devices"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:fadeScrollbars="false"
+ android:scrollbars="vertical"
+ />
+ <TextView android:id="@+id/title_paired_devices"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/title_paired_devices"
+ android:visibility="gone"
+ android:background="#666"
+ android:textColor="#fff"
+ android:paddingLeft="5dp"
+ />
+ <ListView android:id="@+id/paired_devices"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:fadeScrollbars="false"
+ android:scrollbars="vertical"
+ />
+</LinearLayout>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textSize="18sp"
+ android:padding="5dp"
+/>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+ Copyright © 2016 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.
+
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="horizontal"
+ >
+ <TextView
+ android:id="@+id/frequency"
+ android:layout_width="wrap_content"
+ android:layout_height="fill_parent"
+ android:padding="10dp"
+ android:layout_weight="1"
+ />
+</LinearLayout>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+ Copyright © 2016 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.
+
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ >
+ <TextView android:id="@+id/set_callsign_label"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/set_callsign_label"
+ />
+ <EditText android:id="@+id/set_callsign"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:hint="@string/set_callsign_label"/>
+ <Button android:id="@+id/connect_idle"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/connect_idle"
+ />
+ <Button android:id="@+id/disconnect_idle"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/disconnect_idle"
+ />
+ <Button android:id="@+id/reboot_idle"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/reboot_idle"
+ />
+ <Button android:id="@+id/igniters_idle"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/igniters_idle"
+ />
+</LinearLayout>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+ Copyright © 2016 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.
+
+-->
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+ <TextView
+ android:id="@+id/igniter_status"
+ android:layout_width="wrap_content"
+ android:layout_height="fill_parent"
+ android:padding="10dp"
+ android:layout_alignParentRight="true"
+ />
+ <TextView
+ android:id="@+id/igniter_name"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:padding="10dp"
+ android:layout_alignParentLeft="@+id/igniter_status"
+ />
+</RelativeLayout>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+ Copyright © 2016 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.
+
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ >
+
+ <ListView android:id="@+id/igniters"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:fadeScrollbars="false"
+ android:scrollbars="vertical"
+ android:choiceMode="singleChoice"
+ />
+
+ <ToggleButton android:id="@+id/igniter_arm"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textOn="@string/igniter_armed"
+ android:textOff="@string/igniter_arm"
+ />
+
+ <Button android:id="@+id/igniter_fire"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/igniter_fire"
+ />
+
+</LinearLayout>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+ Copyright © 2016 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.
+
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ >
+
+ <LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/set_layout"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ >
+ <EditText
+ android:id="@+id/set_frequency"
+ android:layout_width="wrap_content"
+ android:layout_height="fill_parent"
+ android:padding="10dp"
+ android:layout_weight="1"
+ android:hint="@string/frequency"
+ android:inputType="number|numberDecimal"/>
+ />
+ <TextView
+ android:id="@+id/mhz"
+ android:layout_width="wrap_content"
+ android:layout_height="fill_parent"
+ android:padding="10dp"
+ android:layout_weight="0"
+ android:text="@string/mhz"
+ />
+ <EditText
+ android:id="@+id/set_description"
+ android:layout_width="wrap_content"
+ android:layout_height="fill_parent"
+ android:padding="10dp"
+ android:layout_weight="2"
+ android:hint="@string/description"
+ />
+ </LinearLayout>
+ <LinearLayout
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ >
+ <Button android:id="@+id/set"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/set"
+ android:layout_weight="1"
+ />
+
+ <Button android:id="@+id/remove"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/remove"
+ android:layout_weight="1"
+ />
+
+ <Button android:id="@+id/done"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/done"
+ android:layout_weight="1"
+ />
+ </LinearLayout>
+
+ <ListView android:id="@+id/frequencies"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:fadeScrollbars="false"
+ android:scrollbars="vertical"
+ android:choiceMode="singleChoice"
+ />
+
+
+</LinearLayout>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright © 2015 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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ >
+ <ScrollView android:layout_width="fill_parent"
+ android:layout_height="wrap_content">
+ <LinearLayout android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+ <TextView android:id="@+id/preload_site_label"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/preload_site_label"
+ />
+ <Spinner android:id="@+id/preload_site_list"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:prompt="@string/preload_site_label"
+ android:spinnerMode="dropdown"
+ />
+ <TextView android:id="@+id/preload_latitude_label"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/preload_latitude_label"
+ />
+ <EditText android:id="@+id/preload_latitude"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:hint="@string/preload_latitude_label"
+ android:inputType="number|numberSigned|numberDecimal"/>
+ <TextView android:id="@+id/preload_longitude_label"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/preload_longitude_label"
+ />
+ <EditText android:id="@+id/preload_longitude"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:hint="@string/preload_longitude_label"
+ android:inputType="number|numberSigned|numberDecimal"/>
+ <TextView android:id="@+id/preload_types"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/preload_types"
+ />
+<!--
+ <CheckBox android:id="@+id/preload_hybrid"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/preload_hybrid"
+ />
+ <CheckBox android:id="@+id/preload_satellite"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/preload_satellite"
+ />
+ <CheckBox android:id="@+id/preload_roadmap"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/preload_roadmap"
+ />
+ <CheckBox android:id="@+id/preload_terrain"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/preload_terrain"
+ />
+-->
+ <TextView android:id="@+id/preload_min_zoom_label"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/preload_min_zoom"
+ />
+ <Spinner android:id="@+id/preload_min_zoom"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:prompt="@string/preload_min_zoom"
+ android:spinnerMode="dropdown"
+ />
+ <TextView android:id="@+id/preload_max_zoom_label"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/preload_max_zoom"
+ />
+ <Spinner android:id="@+id/preload_max_zoom"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:prompt="@string/preload_max_zoom"
+ android:spinnerMode="dropdown"
+ />
+ <TextView android:id="@+id/preload_radius_label"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/preload_radius"
+ />
+ <Spinner android:id="@+id/preload_radius"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:prompt="@string/preload_radius"
+ android:spinnerMode="dropdown"
+ />
+ <Button android:id="@+id/preload_load"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/preload_load"
+ />
+ <ProgressBar android:id="@+id/preload_progress"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ style="@android:style/Widget.ProgressBar.Horizontal"
+ />
+ </LinearLayout>
+ </ScrollView>
+</LinearLayout>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright © 2015 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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ >
+ <Button android:id="@+id/map_type_hybrid"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/preload_hybrid"
+ android:onClick="selectType"
+ />
+ <Button android:id="@+id/map_type_satellite"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/preload_satellite"
+ android:onClick="selectType"
+ />
+ <Button android:id="@+id/map_type_roadmap"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/preload_roadmap"
+ android:onClick="selectType"
+ />
+ <Button android:id="@+id/map_type_terrain"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/preload_terrain"
+ android:onClick="selectType"
+ />
+</LinearLayout>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+ Copyright © 2016 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.
+
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ >
+ <TableLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:stretchColumns="2,3"
+ android:layout_weight="0"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content">
+
+ <TableRow
+ android:layout_gravity="center"
+ android:layout_weight="1"
+ android:padding="2dip"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+ <TextView
+ android:id="@+id/select_rate_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/telemetry_rate"
+ />
+ <Spinner android:id="@+id/select_rate"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:prompt="@string/telemetry_rate"
+ android:spinnerMode="dropdown"
+ />
+ </TableRow>
+ <TableRow
+ android:layout_gravity="center"
+ android:layout_weight="1"
+ android:padding="2dip"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+ <TextView
+ android:id="@+id/set_units_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/set_units"
+ />
+ <Spinner android:id="@+id/set_units"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:prompt="@string/set_units"
+ android:spinnerMode="dropdown"
+ />
+ </TableRow>
+ <TableRow
+ android:layout_gravity="center"
+ android:layout_weight="1"
+ android:padding="2dip"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+ <TextView
+ android:id="@+id/map_type_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/map_type"
+ />
+ <Spinner android:id="@+id/map_type"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:prompt="@string/map_type"
+ android:spinnerMode="dropdown"
+ />
+ </TableRow>
+ <TableRow
+ android:layout_gravity="center"
+ android:layout_weight="1"
+ android:padding="2dip"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+ <TextView
+ android:id="@+id/map_source_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/map_source"
+ />
+ <Spinner android:id="@+id/map_source"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:prompt="@string/map_source"
+ android:spinnerMode="dropdown"
+ />
+ </TableRow>
+ </TableLayout>
+ <Button android:id="@+id/preload_maps"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/preload_maps"
+ />
+ <Button android:id="@+id/manage_frequencies"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/manage_frequencies"
+ />
+ <Button android:id="@+id/done"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/done"
+ />
+</LinearLayout>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright © 2013 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; 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.
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+
+ <LinearLayout
+ android:layout_weight="0"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+
+ <LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="0"
+ android:baselineAligned="true"
+ android:orientation="horizontal" >
+
+ <RelativeLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" >
+
+ <TextView
+ android:id="@+id/speed_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/speed_label" />
+
+ <TextView
+ android:id="@+id/speed_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@id/speed_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" >
+
+ <TextView
+ android:id="@+id/height_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/height_label" />
+
+ <TextView
+ android:id="@+id/height_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@id/height_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ </LinearLayout>
+
+ <LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="0"
+ android:baselineAligned="true"
+ android:orientation="horizontal" >
+
+ <RelativeLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" >
+
+ <TextView
+ android:id="@+id/max_speed_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/max_speed_label" />
+
+ <TextView
+ android:id="@+id/max_speed_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@id/max_speed_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" >
+
+ <TextView
+ android:id="@+id/max_height_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/max_height_label" />
+
+ <TextView
+ android:id="@+id/max_height_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@id/max_height_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ </LinearLayout>
+
+ <LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="0"
+ android:baselineAligned="true"
+ android:orientation="horizontal"
+ android:paddingTop="5dp" >
+
+ <RelativeLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" >
+
+ <TextView
+ android:id="@+id/elevation_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/elevation_label" />
+
+ <TextView
+ android:id="@+id/elevation_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@id/elevation_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" >
+
+ <TextView
+ android:id="@+id/range_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/range_label" />
+
+ <TextView
+ android:id="@+id/range_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@id/range_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ </LinearLayout>
+
+ <LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="0"
+ android:baselineAligned="true"
+ android:orientation="horizontal"
+ android:paddingTop="5dp" >
+
+ <RelativeLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" >
+
+ <TextView
+ android:id="@+id/bearing_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/bearing_label" />
+
+ <TextView
+ android:id="@+id/bearing_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@id/bearing_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" >
+
+ <TextView
+ android:id="@+id/compass_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="" />
+
+ <TextView
+ android:id="@+id/compass_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@id/compass_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ </LinearLayout>
+
+ <LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="0"
+ android:baselineAligned="true"
+ android:orientation="horizontal"
+ android:paddingTop="5dp" >
+
+ <RelativeLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" >
+
+ <TextView
+ android:id="@+id/distance_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/gnd_distance_label" />
+
+ <TextView
+ android:id="@+id/distance_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@id/distance_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <TextView
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" >
+ </TextView>
+
+ </LinearLayout>
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="5dp" >
+
+ <TextView
+ android:id="@+id/lat_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/latitude_label" />
+
+ <TextView
+ android:id="@+id/lat_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@id/lat_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="5dp" >
+
+ <TextView
+ android:id="@+id/lon_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/longitude_label" />
+
+ <TextView
+ android:id="@+id/lon_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@id/lon_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:id="@+id/apogee_view"
+ android:visibility="gone"
+ android:layout_gravity="fill"
+ android:layout_weight="1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="5dp" >
+
+ <ImageView
+ android:id="@+id/apogee_redled"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@string/apogee_voltage_label"
+ android:src="@drawable/grayled" />
+
+ <ImageView
+ android:id="@+id/apogee_greenled"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/apogee_redled"
+ android:contentDescription="@string/apogee_voltage_label"
+ android:paddingRight="5dp"
+ android:src="@drawable/grayled" />
+
+ <TextView
+ android:id="@+id/apogee_voltage_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/apogee_greenled"
+ android:text="@string/apogee_voltage_label" />
+
+ <TextView
+ android:id="@+id/apogee_voltage_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:id="@+id/main_view"
+ android:visibility="gone"
+ android:layout_gravity="fill"
+ android:layout_weight="1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="5dp" >
+
+ <ImageView
+ android:id="@+id/main_redled"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@string/main_voltage_label"
+ android:src="@drawable/grayled" />
+
+ <ImageView
+ android:id="@+id/main_greenled"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/main_redled"
+ android:contentDescription="@string/main_voltage_label"
+ android:paddingRight="5dp"
+ android:src="@drawable/grayled" />
+
+ <TextView
+ android:id="@+id/main_voltage_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/main_greenled"
+ android:text="@string/main_voltage_label" />
+
+ <TextView
+ android:id="@+id/main_voltage_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+ </LinearLayout>
+</LinearLayout>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/customTabLayout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <TextView
+ android:id="@+id/tabLabel"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:textSize="13dp"
+ android:textColor="#ffffff"
+ android:gravity="center_horizontal"
+ android:background="#808080"
+ android:layout_centerVertical="true"
+ android:layout_centerHorizontal="true" />
+</RelativeLayout>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright © 2013 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; 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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical" >
+
+ <FrameLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:baselineAligned="true"
+ android:orientation="horizontal"
+ android:layout_weight="1">
+
+ <LinearLayout
+ android:id="@+id/map_online"
+ android:orientation="horizontal"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:layout_weight="1">
+ </LinearLayout>
+
+ <org.altusmetrum.AltosDroid.AltosMapOffline
+ android:id="@+id/map_offline"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"/>
+ </FrameLayout>
+
+ <LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:baselineAligned="true"
+ android:orientation="horizontal" >
+
+ <RelativeLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:paddingTop="5dp" >
+
+ <TextView
+ android:id="@+id/distance_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingRight="4dp"
+ android:text="@string/distance_label" />
+
+ <TextView
+ android:id="@+id/distance_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/distance_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:paddingTop="5dp" >
+
+ <TextView
+ android:id="@+id/bearing_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingRight="4dp"
+ android:text="@string/bearing_label" />
+
+ <TextView
+ android:id="@+id/bearing_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/bearing_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ </LinearLayout>
+
+ <LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:baselineAligned="true"
+ android:orientation="horizontal" >
+
+ <RelativeLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:paddingTop="5dp" >
+
+ <TextView
+ android:id="@+id/target_lat_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingRight="4dp"
+ android:text="@string/target_latitude_label" />
+
+ <TextView
+ android:id="@+id/target_lat_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/target_lat_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:paddingTop="5dp" >
+
+ <TextView
+ android:id="@+id/target_lon_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingRight="4dp"
+ android:text="@string/target_longitude_label" />
+
+ <TextView
+ android:id="@+id/target_lon_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/target_lon_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+ </LinearLayout>
+
+ <LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:baselineAligned="true"
+ android:orientation="horizontal" >
+
+ <RelativeLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:paddingTop="5dp" >
+
+ <TextView
+ android:id="@+id/receiver_lat_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingRight="4dp"
+ android:text="@string/receiver_latitude_label" />
+
+ <TextView
+ android:id="@+id/receiver_lat_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/receiver_lat_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:paddingTop="5dp" >
+
+ <TextView
+ android:id="@+id/receiver_lon_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingRight="4dp"
+ android:text="@string/receiver_longitude_label" />
+
+ <TextView
+ android:id="@+id/receiver_lon_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/receiver_lon_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+ </LinearLayout>
+</LinearLayout>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright © 2013 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; 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.
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <TableLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:stretchColumns="2,3"
+ android:layout_weight="0"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <TableRow
+ android:layout_gravity="center"
+ android:layout_weight="1"
+ android:padding="2dip"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <ImageView
+ android:id="@+id/battery_redled"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@string/battery_voltage_label"
+ android:src="@drawable/grayled"
+ />
+
+ <ImageView
+ android:id="@+id/battery_greenled"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@string/battery_voltage_label"
+ android:src="@drawable/grayled" />
+
+ <TextView
+ android:id="@+id/battery_voltage_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/battery_voltage_label" />
+
+ <TextView
+ android:id="@+id/battery_voltage_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ />
+ </TableRow>
+
+ <TableRow
+ android:id="@+id/receiver_row"
+ android:visibility="gone"
+ android:layout_gravity="center"
+ android:layout_weight="1"
+ android:padding="2dip"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <ImageView
+ android:id="@+id/receiver_redled"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@string/receiver_voltage_label"
+ android:src="@drawable/grayled" />
+
+ <ImageView
+ android:id="@+id/receiver_greenled"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@string/receiver_voltage_label"
+ android:src="@drawable/grayled" />
+
+ <TextView
+ android:id="@+id/receiver_voltage_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/receiver_voltage_label" />
+
+ <TextView
+ android:id="@+id/receiver_voltage_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </TableRow>
+
+ <TableRow
+ android:layout_gravity="center"
+ android:layout_weight="1"
+ android:padding="2dip"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" >
+
+ <ImageView
+ android:id="@+id/logging_redled"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@string/logging_label"
+ android:src="@drawable/grayled" />
+
+ <ImageView
+ android:id="@+id/logging_greenled"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@string/logging_label"
+ android:src="@drawable/grayled" />
+
+ <TextView
+ android:id="@+id/logging_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/logging_label" />
+
+ <TextView
+ android:id="@+id/logging_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/logging_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </TableRow>
+
+ <TableRow
+ android:layout_gravity="center"
+ android:layout_weight="1"
+ android:padding="2dip"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" >
+
+ <ImageView
+ android:id="@+id/gps_locked_redled"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@string/gps_locked_label"
+ android:src="@drawable/grayled" />
+
+ <ImageView
+ android:id="@+id/gps_locked_greenled"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@string/gps_locked_label"
+ android:src="@drawable/grayled" />
+
+ <TextView
+ android:id="@+id/gps_locked_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/gps_locked_label" />
+
+ <TextView
+ android:id="@+id/gps_locked_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/gps_locked_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </TableRow>
+
+ <TableRow
+ android:layout_gravity="center"
+ android:layout_weight="1"
+ android:padding="2dip"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" >
+
+ <ImageView
+ android:id="@+id/gps_ready_redled"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@string/gps_ready_label"
+ android:src="@drawable/grayled" />
+
+ <ImageView
+ android:id="@+id/gps_ready_greenled"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@string/gps_ready_label"
+ android:src="@drawable/grayled" />
+
+ <TextView
+ android:id="@+id/gps_ready_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/gps_ready_label" />
+
+ <TextView
+ android:id="@+id/gps_ready_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/gps_ready_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </TableRow>
+
+ <TableRow
+ android:id="@+id/apogee_row"
+ android:visibility="gone"
+ android:layout_gravity="center"
+ android:layout_weight="1"
+ android:padding="2dip"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <ImageView
+ android:id="@+id/apogee_redled"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@string/apogee_voltage_label"
+ android:src="@drawable/grayled" />
+
+ <ImageView
+ android:id="@+id/apogee_greenled"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@string/apogee_voltage_label"
+ android:src="@drawable/grayled" />
+
+ <TextView
+ android:id="@+id/apogee_voltage_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/apogee_voltage_label" />
+
+ <TextView
+ android:id="@+id/apogee_voltage_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </TableRow>
+
+ <TableRow
+ android:id="@+id/main_row"
+ android:visibility="gone"
+ android:layout_gravity="center"
+ android:layout_weight="1"
+ android:padding="2dip"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" >
+
+ <ImageView
+ android:id="@+id/main_redled"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@string/main_voltage_label"
+ android:src="@drawable/grayled" />
+
+ <ImageView
+ android:id="@+id/main_greenled"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@string/main_voltage_label"
+ android:src="@drawable/grayled" />
+
+ <TextView
+ android:id="@+id/main_voltage_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/main_voltage_label" />
+
+ <TextView
+ android:id="@+id/main_voltage_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </TableRow>
+
+ <TableRow
+ android:id="@+id/ignite_a_row"
+ android:visibility="gone"
+ android:layout_gravity="center"
+ android:layout_weight="1"
+ android:padding="2dip"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" >
+
+ <ImageView
+ android:id="@+id/ignite_a_redled"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@string/ignite_a_voltage_label"
+ android:src="@drawable/grayled" />
+
+ <ImageView
+ android:id="@+id/ignite_a_greenled"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@string/ignite_a_voltage_label"
+ android:src="@drawable/grayled" />
+
+ <TextView
+ android:id="@+id/ignite_a_voltage_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/ignite_a_voltage_label" />
+
+ <TextView
+ android:id="@+id/ignite_a_voltage_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </TableRow>
+
+ <TableRow
+ android:id="@+id/ignite_b_row"
+ android:visibility="gone"
+ android:layout_gravity="center"
+ android:layout_weight="1"
+ android:padding="2dip"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" >
+
+ <ImageView
+ android:id="@+id/ignite_b_redled"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@string/ignite_b_voltage_label"
+ android:src="@drawable/grayled" />
+
+ <ImageView
+ android:id="@+id/ignite_b_greenled"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@string/ignite_b_voltage_label"
+ android:src="@drawable/grayled" />
+
+ <TextView
+ android:id="@+id/ignite_b_voltage_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/ignite_b_voltage_label" />
+
+ <TextView
+ android:id="@+id/ignite_b_voltage_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </TableRow>
+
+ <TableRow
+ android:id="@+id/ignite_c_row"
+ android:visibility="gone"
+ android:layout_gravity="center"
+ android:layout_weight="1"
+ android:padding="2dip"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" >
+
+ <ImageView
+ android:id="@+id/ignite_c_redled"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@string/ignite_c_voltage_label"
+ android:src="@drawable/grayled" />
+
+ <ImageView
+ android:id="@+id/ignite_c_greenled"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@string/ignite_c_voltage_label"
+ android:src="@drawable/grayled" />
+
+ <TextView
+ android:id="@+id/ignite_c_voltage_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/ignite_c_voltage_label" />
+
+ <TextView
+ android:id="@+id/ignite_c_voltage_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </TableRow>
+
+ <TableRow
+ android:id="@+id/ignite_d_row"
+ android:visibility="gone"
+ android:layout_gravity="center"
+ android:layout_weight="1"
+ android:padding="2dip"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" >
+
+ <ImageView
+ android:id="@+id/ignite_d_redled"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@string/ignite_d_voltage_label"
+ android:src="@drawable/grayled" />
+
+ <ImageView
+ android:id="@+id/ignite_d_greenled"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@string/ignite_d_voltage_label"
+ android:src="@drawable/grayled" />
+
+ <TextView
+ android:id="@+id/ignite_d_voltage_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/ignite_d_voltage_label" />
+
+ <TextView
+ android:id="@+id/ignite_d_voltage_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </TableRow>
+
+ <TableRow
+ android:padding="2dip"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <TextView
+ android:id="@+id/receiver_lat_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_column="2"
+ android:text="@string/receiver_latitude_label" />
+
+ <TextView
+ android:id="@+id/receiver_lat_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </TableRow>
+
+ <TableRow
+ android:padding="2dip"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <TextView
+ android:id="@+id/receiver_lon_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_column="2"
+ android:text="@string/receiver_longitude_label" />
+
+ <TextView
+ android:id="@+id/receiver_lon_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </TableRow>
+
+ <TableRow
+ android:padding="2dip"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <TextView
+ android:id="@+id/receiver_alt_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_column="2"
+ android:text="@string/receiver_altitude_label" />
+
+ <TextView
+ android:id="@+id/receiver_alt_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </TableRow>
+ </TableLayout>
+</LinearLayout>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright © 2013 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; 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.
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+
+ <LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_weight="0"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+
+ <RelativeLayout
+ android:layout_gravity="fill"
+ android:layout_weight="1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" >
+
+ <TextView
+ android:id="@+id/bearing_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/bearing_label" />
+
+ <TextView
+ android:id="@+id/bearing_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@+id/bearing_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_gravity="fill"
+ android:layout_weight="1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" >
+
+ <TextView
+ android:id="@+id/direction_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/direction_label" />
+
+ <TextView
+ android:id="@+id/direction_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@+id/direction_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_gravity="fill"
+ android:layout_weight="1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <TextView
+ android:id="@+id/distance_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/distance_label" />
+
+ <TextView
+ android:id="@+id/distance_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@+id/distance_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_gravity="fill"
+ android:layout_weight="1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <TextView
+ android:id="@+id/target_lat_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/target_latitude_label" />
+
+ <TextView
+ android:id="@+id/target_lat_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@id/target_lat_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_gravity="fill"
+ android:layout_weight="1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <TextView
+ android:id="@+id/target_lon_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/target_longitude_label" />
+
+ <TextView
+ android:id="@+id/target_lon_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@id/target_lon_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_gravity="fill"
+ android:layout_weight="1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <TextView
+ android:id="@+id/receiver_lat_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/receiver_latitude_label" />
+
+ <TextView
+ android:id="@+id/receiver_lat_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@id/receiver_lat_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_gravity="fill"
+ android:layout_weight="1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <TextView
+ android:id="@+id/receiver_lon_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/receiver_longitude_label" />
+
+ <TextView
+ android:id="@+id/receiver_lon_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@id/receiver_lon_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_gravity="fill"
+ android:layout_weight="1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <TextView
+ android:id="@+id/max_height_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/max_height_label" />
+
+ <TextView
+ android:id="@+id/max_height_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@id/max_height_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_gravity="fill"
+ android:layout_weight="1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <TextView
+ android:id="@+id/max_speed_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/max_speed_label" />
+
+ <TextView
+ android:id="@+id/max_speed_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@id/max_speed_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_gravity="fill"
+ android:layout_weight="1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <TextView
+ android:id="@+id/max_accel_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/max_accel_label" />
+
+ <TextView
+ android:id="@+id/max_accel_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@id/max_accel_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+ </LinearLayout>
+</LinearLayout>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright © 2015 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.
+-->
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@+id/connect_scan"
+ android:icon="@android:drawable/ic_menu_search"
+ android:title="@string/connect_device" />
+ <item android:id="@+id/disconnect"
+ android:icon="@android:drawable/ic_notification_clear_all"
+ android:title="@string/disconnect_device" />
+ <item android:id="@+id/select_freq"
+ android:icon="@android:drawable/ic_menu_preferences"
+ android:title="@string/select_freq" />
+
+ <item android:id="@+id/select_tracker"
+ android:icon="@android:drawable/ic_menu_view"
+ android:title="@string/select_tracker"/>
+ <item android:id="@+id/delete_track"
+ android:icon="@android:drawable/ic_notification_clear_all"
+ android:title="@string/delete_track"/>
+
+ <item android:id="@+id/setup"
+ android:icon="@android:drawable/ic_menu_preferences"
+ android:title="@string/setup" />
+ <item android:id="@+id/idle_mode"
+ android:icon="@android:drawable/ic_menu_preferences"
+ android:title="@string/idle_mode" />
+
+ <item android:id="@+id/quit"
+ android:icon="@android:drawable/ic_menu_close_clear_cancel"
+ android:title="@string/quit" />
+</menu>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright © 2015 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.
+-->
+<resources>
+ <color name="old_color">#ffff4040</color>
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+
+<resources>
+ <style name="CustomTheme" parent="android:Theme.Material.Light">
+ </style>
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright © 2012-2013 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; 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.
+-->
+<resources>
+
+ <string name="app_name">AltosDroid</string>
+
+ <!-- AltosDroid -->
+ <string name="bt_not_enabled">Bluetooth was not enabled.</string>
+ <string name="title_connecting">connecting…</string>
+ <string name="title_connected_to">connected</string>
+ <string name="title_not_connected">not connected</string>
+
+ <!-- Options Menu -->
+ <string name="connect_device">Connect a device</string>
+ <string name="disconnect_device">Disconnect device</string>
+ <string name="quit">Quit</string>
+ <string name="setup">Setup</string>
+ <string name="select_freq">Select radio frequency</string>
+ <string name="select_rate">Select data rate</string>
+ <string name="change_units">Change units</string>
+ <string name="preload_maps">Load Maps</string>
+ <string name="select_tracker">Select Tracker</string>
+ <string name="delete_track">Delete Track</string>
+ <string name="map_type">Map Type</string>
+ <string name="map_source">Toggle Online/Offline maps</string>
+
+ <!-- MapTypeActivity -->
+ <!-- <string name="map_type">Map Type</string> -->
+
+ <!-- DeviceListActivity -->
+ <string name="scanning">scanning for devices…</string>
+ <string name="select_device">select a device to connect</string>
+ <string name="none_paired">No devices have been paired</string>
+ <string name="none_found">No devices found</string>
+ <string name="title_paired_devices">Paired Devices</string>
+ <string name="title_other_devices">Other Available Devices</string>
+ <string name="button_scan">Scan for devices</string>
+
+ <!-- Service -->
+ <string name="telemetry_service_label">AltosDroid Telemetry Service</string>
+ <string name="telemetry_service_started">Telemetry Service Started</string>
+ <string name="telemetry_service_stopped">Telemetry Service Stopped</string>
+
+ <!-- UI fields -->
+ <!-- Header -->
+ <string name="callsign_label">Callsign</string>
+ <string name="serial_label">Serial</string>
+ <string name="flight_label">Flight</string>
+ <string name="state_label">State</string>
+ <string name="rssi_label">RSSI</string>
+ <string name="age_label">Age</string>
+
+ <!-- Tab fields -->
+ <string name="height_label">Height</string>
+ <string name="speed_label">Speed</string>
+ <string name="accel_label">Acceleration</string>
+ <string name="bearing_label">Bearing</string>
+ <string name="direction_label">Direction</string>
+ <string name="elevation_label">Elevation</string>
+ <string name="range_label">Range</string>
+ <string name="distance_label">Distance</string>
+ <string name="gnd_distance_label">Ground Distance</string>
+ <string name="max_height_label">Max Height</string>
+ <string name="max_speed_label">Max Speed</string>
+ <string name="max_accel_label">Max Accel</string>
+ <string name="battery_voltage_label">Battery</string>
+ <string name="receiver_voltage_label">Receiver Battery</string>
+ <string name="apogee_voltage_label">Apogee Igniter</string>
+ <string name="main_voltage_label">Main Igniter</string>
+ <string name="ignite_a_voltage_label">Igniter A</string>
+ <string name="ignite_b_voltage_label">Igniter B</string>
+ <string name="ignite_c_voltage_label">Igniter C</string>
+ <string name="ignite_d_voltage_label">Igniter D</string>
+ <string name="logging_label">Data Logging</string>
+ <string name="gps_locked_label">GPS Locked</string>
+ <string name="gps_ready_label">GPS Ready</string>
+ <string name="latitude_label">Latitude</string>
+ <string name="longitude_label">Longitude</string>
+ <string name="target_latitude_label">Tar Lat</string>
+ <string name="target_longitude_label">Tar Lon</string>
+ <string name="receiver_latitude_label">My Lat</string>
+ <string name="receiver_longitude_label">My Lon</string>
+ <string name="receiver_altitude_label">My Alt</string>
+
+ <!-- Map preload -->
+ <string name="preload_site_label">Known Launch Sites</string>
+ <string name="preload_latitude_label">Latitude</string>
+ <string name="preload_longitude_label">Longitude</string>
+
+ <string name="preload_types">Map Types</string>
+ <string name="preload_hybrid">Hybrid</string>
+ <string name="preload_satellite">Satellite</string>
+ <string name="preload_roadmap">Roadmap</string>
+ <string name="preload_terrain">Terrain</string>
+ <string name="preload_min_zoom">Minimum Zoom</string>
+ <string name="preload_max_zoom">Maximum Zoom</string>
+ <string name="preload_radius">Radius</string>
+
+ <string name="preload_load">Load Map</string>
+
+ <!-- Idle mode -->
+ <string name="idle_mode">Idle Mode</string>
+ <string name="set_callsign_label">Callsign</string>
+ <string name="connect_idle">Monitor</string>
+ <string name="disconnect_idle">Disconnect</string>
+ <string name="reboot_idle">Reboot</string>
+ <string name="igniters_idle">Fire Igniters</string>
+
+ <!-- igniters -->
+ <string name="igniters">Igniters</string>
+ <string name="igniter_arm">Arm</string>
+ <string name="igniter_armed">Armed</string>
+ <string name="igniter_fire">Fire</string>
+
+ <!-- setup -->
+ <string name="telemetry_rate">Telemetry Rate</string>
+ <string name="set_units">Units</string>
+ <!-- <string name="map_type">Map Type</string> -->
+ <!-- <string name="map_source">Map Source</string> -->
+ <!-- <string name="preload_maps">Preload Maps</string> -->
+ <string name="manage_frequencies">Manage Frequencies</string>
+ <string name="done">OK</string>
+
+ <!-- manage frequencies -->
+ <string name="set">Set</string>
+ <string name="mhz">MHz</string>
+ <string name="remove">Remove</string>
+ <!-- <string name="done">OK</string> -->
+ <string name="frequency">Frequency</string>
+ <string name="description">Description</string>
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+
+<resources>
+ <usb-device vendor-id="65534" />
+ <usb-device vendor-id="1027" />
+</resources>
--- /dev/null
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+ repositories {
+ google()
+ jcenter()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:3.4.2'
+ // NOTE: Do not place your application dependencies here; they belong
+ // in the individual module build.gradle files
+ }
+}
+
+allprojects {
+ repositories {
+ google()
+ jcenter()
+ }
+ tasks.withType(JavaCompile) {
+ options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation"
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<project name="AltosDroid" default="help">
-
- <!-- The local.properties file is created and updated by the 'android' tool.
- It contains the path to the SDK. It should *NOT* be checked into
- Version Control Systems. -->
- <property file="local.properties" />
-
- <!-- The ant.properties file can be created by you. It is only edited by the
- 'android' tool to add properties to it.
- This is the place to change some Ant specific build properties.
- Here are some properties you may want to change/update:
-
- source.dir
- The name of the source directory. Default is 'src'.
- out.dir
- The name of the output directory. Default is 'bin'.
-
- For other overridable properties, look at the beginning of the rules
- files in the SDK, at tools/ant/build.xml
-
- Properties related to the SDK location or the project target should
- be updated using the 'android' tool with the 'update' action.
-
- This file is an integral part of the build system for your
- application and should be checked into Version Control Systems.
-
- -->
- <property file="ant.properties" />
-
- <!-- The project.properties file is created and updated by the 'android'
- tool, as well as ADT.
-
- This contains project specific properties such as project target, and library
- dependencies. Lower level build properties are stored in ant.properties
- (or in .classpath for Eclipse projects).
-
- This file is an integral part of the build system for your
- application and should be checked into Version Control Systems. -->
- <loadproperties srcFile="project.properties" />
-
- <!-- quick check on sdk.dir -->
- <fail
- message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through an env var"
- unless="sdk.dir"
- />
-
-
-<!-- extension targets. Uncomment the ones where you want to do custom work
- in between standard targets -->
-<!--
- <target name="-pre-build">
- </target>
- <target name="-pre-compile">
- </target>
-
- /* This is typically used for code obfuscation.
- Compiled code location: ${out.classes.absolute.dir}
- If this is not done in place, override ${out.dex.input.absolute.dir} */
- <target name="-post-compile">
- </target>
--->
-
- <!-- Import the actual build file.
-
- To customize existing targets, there are two options:
- - Customize only one target:
- - copy/paste the target into this file, *before* the
- <import> task.
- - customize it to your needs.
- - Customize the whole content of build.xml
- - copy/paste the content of the rules files (minus the top node)
- into this file, replacing the <import> task.
- - customize to your needs.
-
- ***********************
- ****** IMPORTANT ******
- ***********************
- In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
- in order to avoid having your file be overridden by tools such as "android update project"
- -->
- <!-- version-tag: 1 -->
- <import file="${sdk.dir}/tools/ant/build.xml" />
-
-</project>
# version and build information, primarily).
#
-infile=src/org/altusmetrum/AltosDroid/BuildInfo.java.in
-outfile=src/org/altusmetrum/AltosDroid/BuildInfo.java
+srcdir=app/src/main/java/org/altusmetrum/AltosDroid
+infile=${srcdir}/BuildInfo.java.in
+outfile=${srcdir}/BuildInfo.java
-. ../src/Version
+. ../src/Makedefs
version=$VERSION
branch=''
commitnum=''
+++ /dev/null
-# This file is automatically generated by Android Tools.
-# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
-#
-# This file must be checked in Version Control Systems.
-#
-# To customize properties used by the Ant build system use,
-# "build.properties", and override values to adapt the script to your
-# project structure.
-
-# Project target.
-target=android-12
--- /dev/null
+# Project-wide Gradle settings.
+
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+android.enableJetifier=true
+android.useAndroidX=true
+org.gradle.jvmargs=-Xmx1536m
+
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
--- /dev/null
+#Thu Aug 29 13:53:38 NZST 2019
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip
--- /dev/null
+#!/usr/bin/env sh
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
--- /dev/null
+@if "%DEBUG%" == "" @echo off\r
+@rem ##########################################################################\r
+@rem\r
+@rem Gradle startup script for Windows\r
+@rem\r
+@rem ##########################################################################\r
+\r
+@rem Set local scope for the variables with windows NT shell\r
+if "%OS%"=="Windows_NT" setlocal\r
+\r
+set DIRNAME=%~dp0\r
+if "%DIRNAME%" == "" set DIRNAME=.\r
+set APP_BASE_NAME=%~n0\r
+set APP_HOME=%DIRNAME%\r
+\r
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r
+set DEFAULT_JVM_OPTS="-Xmx64m"\r
+\r
+@rem Find java.exe\r
+if defined JAVA_HOME goto findJavaFromJavaHome\r
+\r
+set JAVA_EXE=java.exe\r
+%JAVA_EXE% -version >NUL 2>&1\r
+if "%ERRORLEVEL%" == "0" goto init\r
+\r
+echo.\r
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\r
+echo.\r
+echo Please set the JAVA_HOME variable in your environment to match the\r
+echo location of your Java installation.\r
+\r
+goto fail\r
+\r
+:findJavaFromJavaHome\r
+set JAVA_HOME=%JAVA_HOME:"=%\r
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe\r
+\r
+if exist "%JAVA_EXE%" goto init\r
+\r
+echo.\r
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\r
+echo.\r
+echo Please set the JAVA_HOME variable in your environment to match the\r
+echo location of your Java installation.\r
+\r
+goto fail\r
+\r
+:init\r
+@rem Get command-line arguments, handling Windows variants\r
+\r
+if not "%OS%" == "Windows_NT" goto win9xME_args\r
+\r
+:win9xME_args\r
+@rem Slurp the command line arguments.\r
+set CMD_LINE_ARGS=\r
+set _SKIP=2\r
+\r
+:win9xME_args_slurp\r
+if "x%~1" == "x" goto execute\r
+\r
+set CMD_LINE_ARGS=%*\r
+\r
+:execute\r
+@rem Setup the command line\r
+\r
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar\r
+\r
+@rem Execute Gradle\r
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\r
+\r
+:end\r
+@rem End local scope for the variables with windows NT shell\r
+if "%ERRORLEVEL%"=="0" goto mainEnd\r
+\r
+:fail\r
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r
+rem the _cmd.exe /c_ return code!\r
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1\r
+exit /b 1\r
+\r
+:mainEnd\r
+if "%OS%"=="Windows_NT" endlocal\r
+\r
+:omega\r
+++ /dev/null
-# This file is automatically generated by Android Tools.
-# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
-#
-# This file must be checked in Version Control Systems.
-#
-# To customize properties used by the Ant build system use,
-# "ant.properties", and override values to adapt the script to your
-# project structure.
-
-# Project target.
-target=android-12
-android.library.reference.1=google-play-services_lib/
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-
- Copyright © 2012-2013 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; 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.
-
--->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_weight="0"
- android:orientation="vertical" >
-
- <LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_weight="0"
- android:baselineAligned="true"
- android:orientation="horizontal" >
-
- <RelativeLayout
- android:id="@+id/callsign_container"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1" >
-
- <TextView
- android:id="@+id/callsign_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/callsign_label" />
-
- <TextView
- android:id="@+id/callsign_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@+id/callsign_label"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </RelativeLayout>
-
- <RelativeLayout
- android:id="@+id/serial_container"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1" >
-
- <TextView
- android:id="@+id/serial_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/serial_label" />
-
- <TextView
- android:id="@+id/serial_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@+id/serial_label"
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </RelativeLayout>
-
- <RelativeLayout
- android:id="@+id/flight_container"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1" >
-
- <TextView
- android:id="@+id/flight_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/flight_label" />
-
- <TextView
- android:id="@+id/flight_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@+id/flight_label"
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </RelativeLayout>
-
- <RelativeLayout
- android:id="@+id/state_container"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1" >
-
- <TextView
- android:id="@+id/state_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/state_label" />
-
- <TextView
- android:id="@+id/state_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@+id/state_label"
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </RelativeLayout>
-
- <RelativeLayout
- android:id="@+id/rssi_container"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1" >
-
- <TextView
- android:id="@+id/rssi_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/rssi_label" />
-
- <TextView
- android:id="@+id/rssi_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@+id/rssi_label"
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </RelativeLayout>
-
- <RelativeLayout
- android:id="@+id/age_container"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1" >
-
- <TextView
- android:id="@+id/age_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/age_label" />
-
- <TextView
- android:id="@+id/age_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@+id/age_label"
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </RelativeLayout>
- </LinearLayout>
-
- <TabHost
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@android:id/tabhost"
- android:layout_width="fill_parent"
- android:layout_height="0dp"
- android:layout_weight="1" >
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical" >
-
- <TabWidget
- android:id="@android:id/tabs"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_weight="0"
- android:orientation="horizontal" />
-
- <FrameLayout
- android:id="@android:id/tabcontent"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:layout_weight="0" />
-
- <org.altusmetrum.AltosDroid.AltosViewPager
- android:id="@+id/pager"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1" />
- </LinearLayout>
- </TabHost>
-
- <TextView
- android:id="@+id/version"
- android:layout_width="fill_parent"
- android:layout_height="10dip"
- android:layout_weight="0"
- android:gravity="bottom|right"
- android:textSize="7sp"
- android:typeface="monospace" />
-
-</LinearLayout>
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:gravity="center_vertical"
- >
- <TextView android:id="@+id/title_left_text"
- android:layout_alignParentLeft="true"
- android:ellipsize="end"
- android:singleLine="true"
- style="?android:attr/windowTitleStyle"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_weight="1"
- />
- <TextView android:id="@+id/title_right_text"
- android:layout_alignParentRight="true"
- android:ellipsize="end"
- android:singleLine="true"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:textColor="#fff"
- android:layout_weight="1"
- />
-</RelativeLayout>
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-
- Copyright © 2016 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.
-
--->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- >
- <Button android:id="@+id/button_scan"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/button_scan"
- />
- <TextView android:id="@+id/title_new_devices"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/title_other_devices"
- android:visibility="gone"
- android:background="#666"
- android:textColor="#fff"
- android:paddingLeft="5dp"
- />
- <ListView android:id="@+id/new_devices"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:fadeScrollbars="false"
- android:scrollbars="vertical"
- />
- <TextView android:id="@+id/title_paired_devices"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/title_paired_devices"
- android:visibility="gone"
- android:background="#666"
- android:textColor="#fff"
- android:paddingLeft="5dp"
- />
- <ListView android:id="@+id/paired_devices"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:fadeScrollbars="false"
- android:scrollbars="vertical"
- />
-</LinearLayout>
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:textSize="18sp"
- android:padding="5dp"
-/>
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-
- Copyright © 2016 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.
-
--->
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:orientation="horizontal"
- >
- <TextView
- android:id="@+id/frequency"
- android:layout_width="wrap_content"
- android:layout_height="fill_parent"
- android:padding="10dp"
- android:layout_weight="1"
- />
-</LinearLayout>
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-
- Copyright © 2016 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.
-
--->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- >
- <TextView android:id="@+id/set_callsign_label"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:text="@string/set_callsign_label"
- />
- <EditText android:id="@+id/set_callsign"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:hint="@string/set_callsign_label"/>
- <Button android:id="@+id/connect_idle"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/connect_idle"
- />
- <Button android:id="@+id/disconnect_idle"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/disconnect_idle"
- />
- <Button android:id="@+id/reboot_idle"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/reboot_idle"
- />
- <Button android:id="@+id/igniters_idle"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/igniters_idle"
- />
-</LinearLayout>
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-
- Copyright © 2016 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.
-
--->
-<RelativeLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent">
- <TextView
- android:id="@+id/igniter_status"
- android:layout_width="wrap_content"
- android:layout_height="fill_parent"
- android:padding="10dp"
- android:layout_alignParentRight="true"
- />
- <TextView
- android:id="@+id/igniter_name"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:padding="10dp"
- android:layout_alignParentLeft="@+id/igniter_status"
- />
-</RelativeLayout>
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-
- Copyright © 2016 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.
-
--->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- >
-
- <ListView android:id="@+id/igniters"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:fadeScrollbars="false"
- android:scrollbars="vertical"
- android:choiceMode="singleChoice"
- />
-
- <ToggleButton android:id="@+id/igniter_arm"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:textOn="@string/igniter_armed"
- android:textOff="@string/igniter_arm"
- />
-
- <Button android:id="@+id/igniter_fire"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/igniter_fire"
- />
-
-</LinearLayout>
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-
- Copyright © 2016 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.
-
--->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- >
-
- <LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/set_layout"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- >
- <EditText
- android:id="@+id/set_frequency"
- android:layout_width="wrap_content"
- android:layout_height="fill_parent"
- android:padding="10dp"
- android:layout_weight="1"
- android:hint="@string/frequency"
- android:inputType="number|numberDecimal"/>
- />
- <TextView
- android:id="@+id/mhz"
- android:layout_width="wrap_content"
- android:layout_height="fill_parent"
- android:padding="10dp"
- android:layout_weight="0"
- android:text="@string/mhz"
- />
- <EditText
- android:id="@+id/set_description"
- android:layout_width="wrap_content"
- android:layout_height="fill_parent"
- android:padding="10dp"
- android:layout_weight="2"
- android:hint="@string/description"
- />
- </LinearLayout>
- <LinearLayout
- android:orientation="horizontal"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- >
- <Button android:id="@+id/set"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/set"
- android:layout_weight="1"
- />
-
- <Button android:id="@+id/remove"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/remove"
- android:layout_weight="1"
- />
-
- <Button android:id="@+id/done"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/done"
- android:layout_weight="1"
- />
- </LinearLayout>
-
- <ListView android:id="@+id/frequencies"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:fadeScrollbars="false"
- android:scrollbars="vertical"
- android:choiceMode="singleChoice"
- />
-
-
-</LinearLayout>
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright © 2015 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.
--->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- >
- <ScrollView android:layout_width="fill_parent"
- android:layout_height="wrap_content">
- <LinearLayout android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="vertical">
- <TextView android:id="@+id/preload_site_label"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:text="@string/preload_site_label"
- />
- <Spinner android:id="@+id/preload_site_list"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:prompt="@string/preload_site_label"
- android:spinnerMode="dropdown"
- />
- <TextView android:id="@+id/preload_latitude_label"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:text="@string/preload_latitude_label"
- />
- <EditText android:id="@+id/preload_latitude"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:hint="@string/preload_latitude_label"
- android:inputType="number|numberSigned|numberDecimal"/>
- <TextView android:id="@+id/preload_longitude_label"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:text="@string/preload_longitude_label"
- />
- <EditText android:id="@+id/preload_longitude"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:hint="@string/preload_longitude_label"
- android:inputType="number|numberSigned|numberDecimal"/>
- <TextView android:id="@+id/preload_types"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:text="@string/preload_types"
- />
-<!--
- <CheckBox android:id="@+id/preload_hybrid"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:text="@string/preload_hybrid"
- />
- <CheckBox android:id="@+id/preload_satellite"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:text="@string/preload_satellite"
- />
- <CheckBox android:id="@+id/preload_roadmap"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:text="@string/preload_roadmap"
- />
- <CheckBox android:id="@+id/preload_terrain"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:text="@string/preload_terrain"
- />
--->
- <TextView android:id="@+id/preload_min_zoom_label"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:text="@string/preload_min_zoom"
- />
- <Spinner android:id="@+id/preload_min_zoom"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:prompt="@string/preload_min_zoom"
- android:spinnerMode="dropdown"
- />
- <TextView android:id="@+id/preload_max_zoom_label"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:text="@string/preload_max_zoom"
- />
- <Spinner android:id="@+id/preload_max_zoom"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:prompt="@string/preload_max_zoom"
- android:spinnerMode="dropdown"
- />
- <TextView android:id="@+id/preload_radius_label"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:text="@string/preload_radius"
- />
- <Spinner android:id="@+id/preload_radius"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:prompt="@string/preload_radius"
- android:spinnerMode="dropdown"
- />
- <Button android:id="@+id/preload_load"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/preload_load"
- />
- <ProgressBar android:id="@+id/preload_progress"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- style="@android:style/Widget.ProgressBar.Horizontal"
- />
- </LinearLayout>
- </ScrollView>
-</LinearLayout>
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright © 2015 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.
--->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- >
- <Button android:id="@+id/map_type_hybrid"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:text="@string/preload_hybrid"
- android:onClick="selectType"
- />
- <Button android:id="@+id/map_type_satellite"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:text="@string/preload_satellite"
- android:onClick="selectType"
- />
- <Button android:id="@+id/map_type_roadmap"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:text="@string/preload_roadmap"
- android:onClick="selectType"
- />
- <Button android:id="@+id/map_type_terrain"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:text="@string/preload_terrain"
- android:onClick="selectType"
- />
-</LinearLayout>
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-
- Copyright © 2016 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.
-
--->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- >
- <TableLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:stretchColumns="2,3"
- android:layout_weight="0"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content">
-
- <TableRow
- android:layout_gravity="center"
- android:layout_weight="1"
- android:padding="2dip"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content">
- <TextView
- android:id="@+id/select_rate_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/telemetry_rate"
- />
- <Spinner android:id="@+id/select_rate"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:prompt="@string/telemetry_rate"
- android:spinnerMode="dropdown"
- />
- </TableRow>
- <TableRow
- android:layout_gravity="center"
- android:layout_weight="1"
- android:padding="2dip"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content">
- <TextView
- android:id="@+id/set_units_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/set_units"
- />
- <Spinner android:id="@+id/set_units"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:prompt="@string/set_units"
- android:spinnerMode="dropdown"
- />
- </TableRow>
- <TableRow
- android:layout_gravity="center"
- android:layout_weight="1"
- android:padding="2dip"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content">
- <TextView
- android:id="@+id/map_type_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/map_type"
- />
- <Spinner android:id="@+id/map_type"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:prompt="@string/map_type"
- android:spinnerMode="dropdown"
- />
- </TableRow>
- <TableRow
- android:layout_gravity="center"
- android:layout_weight="1"
- android:padding="2dip"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content">
- <TextView
- android:id="@+id/map_source_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/map_source"
- />
- <Spinner android:id="@+id/map_source"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:prompt="@string/map_source"
- android:spinnerMode="dropdown"
- />
- </TableRow>
- </TableLayout>
- <Button android:id="@+id/preload_maps"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/preload_maps"
- />
- <Button android:id="@+id/manage_frequencies"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/manage_frequencies"
- />
- <Button android:id="@+id/done"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/done"
- />
-</LinearLayout>
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright © 2013 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; 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.
--->
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical" >
-
- <LinearLayout
- android:layout_weight="0"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical" >
-
- <LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_weight="0"
- android:baselineAligned="true"
- android:orientation="horizontal" >
-
- <RelativeLayout
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1" >
-
- <TextView
- android:id="@+id/speed_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/speed_label" />
-
- <TextView
- android:id="@+id/speed_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_below="@id/speed_label"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </RelativeLayout>
-
- <RelativeLayout
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1" >
-
- <TextView
- android:id="@+id/height_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/height_label" />
-
- <TextView
- android:id="@+id/height_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_below="@id/height_label"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </RelativeLayout>
-
- </LinearLayout>
-
- <LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_weight="0"
- android:baselineAligned="true"
- android:orientation="horizontal" >
-
- <RelativeLayout
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1" >
-
- <TextView
- android:id="@+id/max_speed_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/max_speed_label" />
-
- <TextView
- android:id="@+id/max_speed_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_below="@id/max_speed_label"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </RelativeLayout>
-
- <RelativeLayout
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1" >
-
- <TextView
- android:id="@+id/max_height_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/max_height_label" />
-
- <TextView
- android:id="@+id/max_height_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_below="@id/max_height_label"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </RelativeLayout>
-
- </LinearLayout>
-
- <LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_weight="0"
- android:baselineAligned="true"
- android:orientation="horizontal"
- android:paddingTop="5dp" >
-
- <RelativeLayout
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1" >
-
- <TextView
- android:id="@+id/elevation_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/elevation_label" />
-
- <TextView
- android:id="@+id/elevation_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_below="@id/elevation_label"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </RelativeLayout>
-
- <RelativeLayout
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1" >
-
- <TextView
- android:id="@+id/range_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/range_label" />
-
- <TextView
- android:id="@+id/range_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_below="@id/range_label"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </RelativeLayout>
-
- </LinearLayout>
-
- <LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_weight="0"
- android:baselineAligned="true"
- android:orientation="horizontal"
- android:paddingTop="5dp" >
-
- <RelativeLayout
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1" >
-
- <TextView
- android:id="@+id/bearing_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/bearing_label" />
-
- <TextView
- android:id="@+id/bearing_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_below="@id/bearing_label"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </RelativeLayout>
-
- <RelativeLayout
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1" >
-
- <TextView
- android:id="@+id/compass_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="" />
-
- <TextView
- android:id="@+id/compass_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_below="@id/compass_label"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </RelativeLayout>
-
- </LinearLayout>
-
- <LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_weight="0"
- android:baselineAligned="true"
- android:orientation="horizontal"
- android:paddingTop="5dp" >
-
- <RelativeLayout
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1" >
-
- <TextView
- android:id="@+id/distance_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/gnd_distance_label" />
-
- <TextView
- android:id="@+id/distance_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_below="@id/distance_label"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </RelativeLayout>
-
- <TextView
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1" >
- </TextView>
-
- </LinearLayout>
-
- <RelativeLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingTop="5dp" >
-
- <TextView
- android:id="@+id/lat_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/latitude_label" />
-
- <TextView
- android:id="@+id/lat_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_below="@id/lat_label"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </RelativeLayout>
-
- <RelativeLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingTop="5dp" >
-
- <TextView
- android:id="@+id/lon_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/longitude_label" />
-
- <TextView
- android:id="@+id/lon_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_below="@id/lon_label"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </RelativeLayout>
-
- <RelativeLayout
- android:id="@+id/apogee_view"
- android:visibility="gone"
- android:layout_gravity="fill"
- android:layout_weight="1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingTop="5dp" >
-
- <ImageView
- android:id="@+id/apogee_redled"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:contentDescription="@string/apogee_voltage_label"
- android:src="@drawable/grayled" />
-
- <ImageView
- android:id="@+id/apogee_greenled"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_toRightOf="@id/apogee_redled"
- android:contentDescription="@string/apogee_voltage_label"
- android:paddingRight="5dp"
- android:src="@drawable/grayled" />
-
- <TextView
- android:id="@+id/apogee_voltage_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_toRightOf="@id/apogee_greenled"
- android:text="@string/apogee_voltage_label" />
-
- <TextView
- android:id="@+id/apogee_voltage_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </RelativeLayout>
-
- <RelativeLayout
- android:id="@+id/main_view"
- android:visibility="gone"
- android:layout_gravity="fill"
- android:layout_weight="1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingTop="5dp" >
-
- <ImageView
- android:id="@+id/main_redled"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:contentDescription="@string/main_voltage_label"
- android:src="@drawable/grayled" />
-
- <ImageView
- android:id="@+id/main_greenled"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_toRightOf="@id/main_redled"
- android:contentDescription="@string/main_voltage_label"
- android:paddingRight="5dp"
- android:src="@drawable/grayled" />
-
- <TextView
- android:id="@+id/main_voltage_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_toRightOf="@id/main_greenled"
- android:text="@string/main_voltage_label" />
-
- <TextView
- android:id="@+id/main_voltage_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </RelativeLayout>
- </LinearLayout>
-</LinearLayout>
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/customTabLayout"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
- <TextView
- android:id="@+id/tabLabel"
- android:layout_height="wrap_content"
- android:layout_width="match_parent"
- android:textSize="13dp"
- android:textColor="#ffffff"
- android:gravity="center_horizontal"
- android:background="#808080"
- android:layout_centerVertical="true"
- android:layout_centerHorizontal="true" />
-</RelativeLayout>
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright © 2013 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; 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.
--->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical" >
-
- <FrameLayout
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:baselineAligned="true"
- android:orientation="horizontal"
- android:layout_weight="1">
-
- <LinearLayout
- android:id="@+id/map_online"
- android:orientation="horizontal"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:layout_weight="1">
- </LinearLayout>
-
- <org.altusmetrum.AltosDroid.AltosMapOffline
- android:id="@+id/map_offline"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_weight="1"/>
- </FrameLayout>
-
- <LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:baselineAligned="true"
- android:orientation="horizontal" >
-
- <RelativeLayout
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:paddingTop="5dp" >
-
- <TextView
- android:id="@+id/distance_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingRight="4dp"
- android:text="@string/distance_label" />
-
- <TextView
- android:id="@+id/distance_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_toRightOf="@id/distance_label"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </RelativeLayout>
-
- <RelativeLayout
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:paddingTop="5dp" >
-
- <TextView
- android:id="@+id/bearing_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingRight="4dp"
- android:text="@string/bearing_label" />
-
- <TextView
- android:id="@+id/bearing_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_toRightOf="@id/bearing_label"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </RelativeLayout>
-
- </LinearLayout>
-
- <LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:baselineAligned="true"
- android:orientation="horizontal" >
-
- <RelativeLayout
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:paddingTop="5dp" >
-
- <TextView
- android:id="@+id/target_lat_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingRight="4dp"
- android:text="@string/target_latitude_label" />
-
- <TextView
- android:id="@+id/target_lat_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_toRightOf="@id/target_lat_label"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </RelativeLayout>
-
- <RelativeLayout
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:paddingTop="5dp" >
-
- <TextView
- android:id="@+id/target_lon_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingRight="4dp"
- android:text="@string/target_longitude_label" />
-
- <TextView
- android:id="@+id/target_lon_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_toRightOf="@id/target_lon_label"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </RelativeLayout>
- </LinearLayout>
-
- <LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:baselineAligned="true"
- android:orientation="horizontal" >
-
- <RelativeLayout
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:paddingTop="5dp" >
-
- <TextView
- android:id="@+id/receiver_lat_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingRight="4dp"
- android:text="@string/receiver_latitude_label" />
-
- <TextView
- android:id="@+id/receiver_lat_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_toRightOf="@id/receiver_lat_label"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </RelativeLayout>
-
- <RelativeLayout
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:paddingTop="5dp" >
-
- <TextView
- android:id="@+id/receiver_lon_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingRight="4dp"
- android:text="@string/receiver_longitude_label" />
-
- <TextView
- android:id="@+id/receiver_lon_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_toRightOf="@id/receiver_lon_label"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </RelativeLayout>
- </LinearLayout>
-</LinearLayout>
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright © 2013 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; 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.
--->
-
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content">
-
- <TableLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:stretchColumns="2,3"
- android:layout_weight="0"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content">
-
- <TableRow
- android:layout_gravity="center"
- android:layout_weight="1"
- android:padding="2dip"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content">
-
- <ImageView
- android:id="@+id/battery_redled"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:contentDescription="@string/battery_voltage_label"
- android:src="@drawable/grayled"
- />
-
- <ImageView
- android:id="@+id/battery_greenled"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:contentDescription="@string/battery_voltage_label"
- android:src="@drawable/grayled" />
-
- <TextView
- android:id="@+id/battery_voltage_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/battery_voltage_label" />
-
- <TextView
- android:id="@+id/battery_voltage_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceSmall"
- />
- </TableRow>
-
- <TableRow
- android:id="@+id/receiver_row"
- android:visibility="gone"
- android:layout_gravity="center"
- android:layout_weight="1"
- android:padding="2dip"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content">
-
- <ImageView
- android:id="@+id/receiver_redled"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:contentDescription="@string/receiver_voltage_label"
- android:src="@drawable/grayled" />
-
- <ImageView
- android:id="@+id/receiver_greenled"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:contentDescription="@string/receiver_voltage_label"
- android:src="@drawable/grayled" />
-
- <TextView
- android:id="@+id/receiver_voltage_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/receiver_voltage_label" />
-
- <TextView
- android:id="@+id/receiver_voltage_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </TableRow>
-
- <TableRow
- android:layout_gravity="center"
- android:layout_weight="1"
- android:padding="2dip"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" >
-
- <ImageView
- android:id="@+id/logging_redled"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:contentDescription="@string/logging_label"
- android:src="@drawable/grayled" />
-
- <ImageView
- android:id="@+id/logging_greenled"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:contentDescription="@string/logging_label"
- android:src="@drawable/grayled" />
-
- <TextView
- android:id="@+id/logging_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/logging_label" />
-
- <TextView
- android:id="@+id/logging_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@id/logging_label"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </TableRow>
-
- <TableRow
- android:layout_gravity="center"
- android:layout_weight="1"
- android:padding="2dip"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" >
-
- <ImageView
- android:id="@+id/gps_locked_redled"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:contentDescription="@string/gps_locked_label"
- android:src="@drawable/grayled" />
-
- <ImageView
- android:id="@+id/gps_locked_greenled"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:contentDescription="@string/gps_locked_label"
- android:src="@drawable/grayled" />
-
- <TextView
- android:id="@+id/gps_locked_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/gps_locked_label" />
-
- <TextView
- android:id="@+id/gps_locked_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@id/gps_locked_label"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </TableRow>
-
- <TableRow
- android:layout_gravity="center"
- android:layout_weight="1"
- android:padding="2dip"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" >
-
- <ImageView
- android:id="@+id/gps_ready_redled"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:contentDescription="@string/gps_ready_label"
- android:src="@drawable/grayled" />
-
- <ImageView
- android:id="@+id/gps_ready_greenled"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:contentDescription="@string/gps_ready_label"
- android:src="@drawable/grayled" />
-
- <TextView
- android:id="@+id/gps_ready_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/gps_ready_label" />
-
- <TextView
- android:id="@+id/gps_ready_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@id/gps_ready_label"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </TableRow>
-
- <TableRow
- android:id="@+id/apogee_row"
- android:visibility="gone"
- android:layout_gravity="center"
- android:layout_weight="1"
- android:padding="2dip"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content">
-
- <ImageView
- android:id="@+id/apogee_redled"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:contentDescription="@string/apogee_voltage_label"
- android:src="@drawable/grayled" />
-
- <ImageView
- android:id="@+id/apogee_greenled"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:contentDescription="@string/apogee_voltage_label"
- android:src="@drawable/grayled" />
-
- <TextView
- android:id="@+id/apogee_voltage_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/apogee_voltage_label" />
-
- <TextView
- android:id="@+id/apogee_voltage_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </TableRow>
-
- <TableRow
- android:id="@+id/main_row"
- android:visibility="gone"
- android:layout_gravity="center"
- android:layout_weight="1"
- android:padding="2dip"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" >
-
- <ImageView
- android:id="@+id/main_redled"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:contentDescription="@string/main_voltage_label"
- android:src="@drawable/grayled" />
-
- <ImageView
- android:id="@+id/main_greenled"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:contentDescription="@string/main_voltage_label"
- android:src="@drawable/grayled" />
-
- <TextView
- android:id="@+id/main_voltage_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/main_voltage_label" />
-
- <TextView
- android:id="@+id/main_voltage_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </TableRow>
-
- <TableRow
- android:id="@+id/ignite_a_row"
- android:visibility="gone"
- android:layout_gravity="center"
- android:layout_weight="1"
- android:padding="2dip"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" >
-
- <ImageView
- android:id="@+id/ignite_a_redled"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:contentDescription="@string/ignite_a_voltage_label"
- android:src="@drawable/grayled" />
-
- <ImageView
- android:id="@+id/ignite_a_greenled"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:contentDescription="@string/ignite_a_voltage_label"
- android:src="@drawable/grayled" />
-
- <TextView
- android:id="@+id/ignite_a_voltage_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/ignite_a_voltage_label" />
-
- <TextView
- android:id="@+id/ignite_a_voltage_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </TableRow>
-
- <TableRow
- android:id="@+id/ignite_b_row"
- android:visibility="gone"
- android:layout_gravity="center"
- android:layout_weight="1"
- android:padding="2dip"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" >
-
- <ImageView
- android:id="@+id/ignite_b_redled"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:contentDescription="@string/ignite_b_voltage_label"
- android:src="@drawable/grayled" />
-
- <ImageView
- android:id="@+id/ignite_b_greenled"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:contentDescription="@string/ignite_b_voltage_label"
- android:src="@drawable/grayled" />
-
- <TextView
- android:id="@+id/ignite_b_voltage_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/ignite_b_voltage_label" />
-
- <TextView
- android:id="@+id/ignite_b_voltage_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </TableRow>
-
- <TableRow
- android:id="@+id/ignite_c_row"
- android:visibility="gone"
- android:layout_gravity="center"
- android:layout_weight="1"
- android:padding="2dip"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" >
-
- <ImageView
- android:id="@+id/ignite_c_redled"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:contentDescription="@string/ignite_c_voltage_label"
- android:src="@drawable/grayled" />
-
- <ImageView
- android:id="@+id/ignite_c_greenled"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:contentDescription="@string/ignite_c_voltage_label"
- android:src="@drawable/grayled" />
-
- <TextView
- android:id="@+id/ignite_c_voltage_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/ignite_c_voltage_label" />
-
- <TextView
- android:id="@+id/ignite_c_voltage_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </TableRow>
-
- <TableRow
- android:id="@+id/ignite_d_row"
- android:visibility="gone"
- android:layout_gravity="center"
- android:layout_weight="1"
- android:padding="2dip"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" >
-
- <ImageView
- android:id="@+id/ignite_d_redled"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:contentDescription="@string/ignite_d_voltage_label"
- android:src="@drawable/grayled" />
-
- <ImageView
- android:id="@+id/ignite_d_greenled"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:contentDescription="@string/ignite_d_voltage_label"
- android:src="@drawable/grayled" />
-
- <TextView
- android:id="@+id/ignite_d_voltage_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/ignite_d_voltage_label" />
-
- <TextView
- android:id="@+id/ignite_d_voltage_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </TableRow>
-
- <TableRow
- android:padding="2dip"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content">
-
- <TextView
- android:id="@+id/receiver_lat_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_column="2"
- android:text="@string/receiver_latitude_label" />
-
- <TextView
- android:id="@+id/receiver_lat_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </TableRow>
-
- <TableRow
- android:padding="2dip"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content">
-
- <TextView
- android:id="@+id/receiver_lon_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_column="2"
- android:text="@string/receiver_longitude_label" />
-
- <TextView
- android:id="@+id/receiver_lon_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </TableRow>
-
- <TableRow
- android:padding="2dip"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content">
-
- <TextView
- android:id="@+id/receiver_alt_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_column="2"
- android:text="@string/receiver_altitude_label" />
-
- <TextView
- android:id="@+id/receiver_alt_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </TableRow>
- </TableLayout>
-</LinearLayout>
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright © 2013 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; 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.
--->
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical" >
-
- <LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_weight="0"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical" >
-
- <RelativeLayout
- android:layout_gravity="fill"
- android:layout_weight="1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" >
-
- <TextView
- android:id="@+id/bearing_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/bearing_label" />
-
- <TextView
- android:id="@+id/bearing_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_below="@+id/bearing_label"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </RelativeLayout>
-
- <RelativeLayout
- android:layout_gravity="fill"
- android:layout_weight="1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" >
-
- <TextView
- android:id="@+id/direction_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/direction_label" />
-
- <TextView
- android:id="@+id/direction_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_below="@+id/direction_label"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </RelativeLayout>
-
- <RelativeLayout
- android:layout_gravity="fill"
- android:layout_weight="1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content">
-
- <TextView
- android:id="@+id/distance_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/distance_label" />
-
- <TextView
- android:id="@+id/distance_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_below="@+id/distance_label"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </RelativeLayout>
-
- <RelativeLayout
- android:layout_gravity="fill"
- android:layout_weight="1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content">
-
- <TextView
- android:id="@+id/target_lat_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/target_latitude_label" />
-
- <TextView
- android:id="@+id/target_lat_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_below="@id/target_lat_label"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </RelativeLayout>
-
- <RelativeLayout
- android:layout_gravity="fill"
- android:layout_weight="1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content">
-
- <TextView
- android:id="@+id/target_lon_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/target_longitude_label" />
-
- <TextView
- android:id="@+id/target_lon_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_below="@id/target_lon_label"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </RelativeLayout>
-
- <RelativeLayout
- android:layout_gravity="fill"
- android:layout_weight="1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content">
-
- <TextView
- android:id="@+id/receiver_lat_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/receiver_latitude_label" />
-
- <TextView
- android:id="@+id/receiver_lat_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_below="@id/receiver_lat_label"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </RelativeLayout>
-
- <RelativeLayout
- android:layout_gravity="fill"
- android:layout_weight="1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content">
-
- <TextView
- android:id="@+id/receiver_lon_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/receiver_longitude_label" />
-
- <TextView
- android:id="@+id/receiver_lon_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_below="@id/receiver_lon_label"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </RelativeLayout>
-
- <RelativeLayout
- android:layout_gravity="fill"
- android:layout_weight="1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content">
-
- <TextView
- android:id="@+id/max_height_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/max_height_label" />
-
- <TextView
- android:id="@+id/max_height_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_below="@id/max_height_label"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </RelativeLayout>
-
- <RelativeLayout
- android:layout_gravity="fill"
- android:layout_weight="1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content">
-
- <TextView
- android:id="@+id/max_speed_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/max_speed_label" />
-
- <TextView
- android:id="@+id/max_speed_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_below="@id/max_speed_label"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </RelativeLayout>
-
- <RelativeLayout
- android:layout_gravity="fill"
- android:layout_weight="1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content">
-
- <TextView
- android:id="@+id/max_accel_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/max_accel_label" />
-
- <TextView
- android:id="@+id/max_accel_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_below="@id/max_accel_label"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </RelativeLayout>
- </LinearLayout>
-</LinearLayout>
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright © 2015 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.
--->
-<menu xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:id="@+id/connect_scan"
- android:icon="@android:drawable/ic_menu_search"
- android:title="@string/connect_device" />
- <item android:id="@+id/disconnect"
- android:icon="@android:drawable/ic_notification_clear_all"
- android:title="@string/disconnect_device" />
- <item android:id="@+id/select_freq"
- android:icon="@android:drawable/ic_menu_preferences"
- android:title="@string/select_freq" />
-
- <item android:id="@+id/select_tracker"
- android:icon="@android:drawable/ic_menu_view"
- android:title="@string/select_tracker"/>
- <item android:id="@+id/delete_track"
- android:icon="@android:drawable/ic_notification_clear_all"
- android:title="@string/delete_track"/>
-
- <item android:id="@+id/setup"
- android:icon="@android:drawable/ic_menu_preferences"
- android:title="@string/setup" />
- <item android:id="@+id/idle_mode"
- android:icon="@android:drawable/ic_menu_preferences"
- android:title="@string/idle_mode" />
-
- <item android:id="@+id/quit"
- android:icon="@android:drawable/ic_menu_close_clear_cancel"
- android:title="@string/quit" />
-</menu>
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright © 2015 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.
--->
-<resources>
- <color name="old_color">#ffff4040</color>
-</resources>
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-
-<resources>
- <style name="CustomTheme" parent="android:Theme.Holo">
- </style>
-</resources>
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright © 2012-2013 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; 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.
--->
-<resources>
-
- <string name="app_name">AltosDroid</string>
-
- <!-- AltosDroid -->
- <string name="bt_not_enabled">Bluetooth was not enabled.</string>
- <string name="title_connecting">connecting…</string>
- <string name="title_connected_to">connected</string>
- <string name="title_not_connected">not connected</string>
-
- <!-- Options Menu -->
- <string name="connect_device">Connect a device</string>
- <string name="disconnect_device">Disconnect device</string>
- <string name="quit">Quit</string>
- <string name="setup">Setup</string>
- <string name="select_freq">Select radio frequency</string>
- <string name="select_rate">Select data rate</string>
- <string name="change_units">Change units</string>
- <string name="preload_maps">Load Maps</string>
- <string name="select_tracker">Select Tracker</string>
- <string name="delete_track">Delete Track</string>
- <string name="map_type">Map Type</string>
- <string name="map_source">Toggle Online/Offline maps</string>
-
- <!-- MapTypeActivity -->
- <string name="map_type">Map Type</string>
-
- <!-- DeviceListActivity -->
- <string name="scanning">scanning for devices…</string>
- <string name="select_device">select a device to connect</string>
- <string name="none_paired">No devices have been paired</string>
- <string name="none_found">No devices found</string>
- <string name="title_paired_devices">Paired Devices</string>
- <string name="title_other_devices">Other Available Devices</string>
- <string name="button_scan">Scan for devices</string>
-
- <!-- Service -->
- <string name="telemetry_service_label">AltosDroid Telemetry Service</string>
- <string name="telemetry_service_started">Telemetry Service Started</string>
- <string name="telemetry_service_stopped">Telemetry Service Stopped</string>
-
- <!-- UI fields -->
- <!-- Header -->
- <string name="callsign_label">Callsign</string>
- <string name="serial_label">Serial</string>
- <string name="flight_label">Flight</string>
- <string name="state_label">State</string>
- <string name="rssi_label">RSSI</string>
- <string name="age_label">Age</string>
-
- <!-- Tab fields -->
- <string name="height_label">Height</string>
- <string name="speed_label">Speed</string>
- <string name="accel_label">Acceleration</string>
- <string name="bearing_label">Bearing</string>
- <string name="direction_label">Direction</string>
- <string name="elevation_label">Elevation</string>
- <string name="range_label">Range</string>
- <string name="distance_label">Distance</string>
- <string name="gnd_distance_label">Ground Distance</string>
- <string name="max_height_label">Max Height</string>
- <string name="max_speed_label">Max Speed</string>
- <string name="max_accel_label">Max Accel</string>
- <string name="battery_voltage_label">Battery</string>
- <string name="receiver_voltage_label">Receiver Battery</string>
- <string name="apogee_voltage_label">Apogee Igniter</string>
- <string name="main_voltage_label">Main Igniter</string>
- <string name="ignite_a_voltage_label">Igniter A</string>
- <string name="ignite_b_voltage_label">Igniter B</string>
- <string name="ignite_c_voltage_label">Igniter C</string>
- <string name="ignite_d_voltage_label">Igniter D</string>
- <string name="logging_label">Data Logging</string>
- <string name="gps_locked_label">GPS Locked</string>
- <string name="gps_ready_label">GPS Ready</string>
- <string name="latitude_label">Latitude</string>
- <string name="longitude_label">Longitude</string>
- <string name="target_latitude_label">Tar Lat</string>
- <string name="target_longitude_label">Tar Lon</string>
- <string name="receiver_latitude_label">My Lat</string>
- <string name="receiver_longitude_label">My Lon</string>
- <string name="receiver_altitude_label">My Alt</string>
-
- <!-- Map preload -->
- <string name="preload_site_label">Known Launch Sites</string>
- <string name="preload_latitude_label">Latitude</string>
- <string name="preload_longitude_label">Longitude</string>
-
- <string name="preload_types">Map Types</string>
- <string name="preload_hybrid">Hybrid</string>
- <string name="preload_satellite">Satellite</string>
- <string name="preload_roadmap">Roadmap</string>
- <string name="preload_terrain">Terrain</string>
- <string name="preload_min_zoom">Minimum Zoom</string>
- <string name="preload_max_zoom">Maximum Zoom</string>
- <string name="preload_radius">Radius</string>
-
- <string name="preload_load">Load Map</string>
-
- <!-- Idle mode -->
- <string name="idle_mode">Idle Mode</string>
- <string name="set_callsign_label">Callsign</string>
- <string name="connect_idle">Monitor</string>
- <string name="disconnect_idle">Disconnect</string>
- <string name="reboot_idle">Reboot</string>
- <string name="igniters_idle">Fire Igniters</string>
-
- <!-- igniters -->
- <string name="igniters">Igniters</string>
- <string name="igniter_arm">Arm</string>
- <string name="igniter_armed">Armed</string>
- <string name="igniter_fire">Fire</string>
-
- <!-- setup -->
- <string name="telemetry_rate">Telemetry Rate</string>
- <string name="set_units">Units</string>
- <string name="map_type">Map Type</string>
- <string name="map_source">Map Source</string>
- <string name="preload_maps">Preload Maps</string>
- <string name="manage_frequencies">Manage Frequencies</string>
- <string name="done">OK</string>
-
- <!-- manage frequencies -->
- <string name="set">Set</string>
- <string name="mhz">MHz</string>
- <string name="remove">Remove</string>
- <string name="done">OK</string>
- <string name="frequency">Frequency</string>
- <string name="description">Description</string>
-</resources>
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-
-<resources>
- <usb-device vendor-id="65534" />
- <usb-device vendor-id="1027" />
-</resources>
--- /dev/null
+include ':app'
+++ /dev/null
-/*
- * 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; 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.
- */
-
-package org.altusmetrum.AltosDroid;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.UUID;
-
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothSocket;
-//import android.os.Bundle;
-import android.os.Handler;
-//import android.os.Message;
-
-import org.altusmetrum.altoslib_13.*;
-
-public class AltosBluetooth extends AltosDroidLink {
-
- private ConnectThread connect_thread = null;
-
- private BluetoothDevice device;
- private BluetoothSocket socket;
- private InputStream input;
- private OutputStream output;
- private boolean pause;
-
- // Constructor
- public AltosBluetooth(BluetoothDevice device, Handler handler, boolean pause) {
- super(handler);
- this.device = device;
- this.handler = handler;
- this.pause = pause;
-
- connect_thread = new ConnectThread();
- connect_thread.start();
- }
-
- void connected() {
- if (closed()) {
- AltosDebug.debug("connected after closed");
- return;
- }
-
- AltosDebug.check_ui("connected\n");
- try {
- synchronized(this) {
- if (socket != null) {
- input = socket.getInputStream();
- output = socket.getOutputStream();
- super.connected();
- }
- }
- } catch (InterruptedException ie) {
- connect_failed();
- } catch (IOException io) {
- connect_failed();
- }
- }
-
- private void connect_failed() {
- if (closed()) {
- AltosDebug.debug("connect_failed after closed");
- return;
- }
-
- close_device();
- input = null;
- output = null;
- handler.obtainMessage(TelemetryService.MSG_CONNECT_FAILED, this).sendToTarget();
- AltosDebug.error("ConnectThread: Failed to establish connection");
- }
-
- void close_device() {
- BluetoothSocket tmp_socket;
-
- synchronized(this) {
- tmp_socket = socket;
- socket = null;
- }
-
- if (tmp_socket != null) {
- try {
- tmp_socket.close();
- } catch (IOException e) {
- AltosDebug.error("close_socket failed");
- }
- }
- }
-
- public void close() {
- super.close();
- input = null;
- output = null;
- }
-
- private final UUID SPP_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
-
- private void create_socket(BluetoothDevice device) {
-
- BluetoothSocket tmp_socket = null;
-
- AltosDebug.check_ui("create_socket\n");
- try {
- tmp_socket = device.createInsecureRfcommSocketToServiceRecord(SPP_UUID);
- } catch (IOException e) {
- e.printStackTrace();
- }
- if (socket != null) {
- AltosDebug.debug("Socket already allocated %s", socket.toString());
- close_device();
- }
- synchronized (this) {
- socket = tmp_socket;
- }
- }
-
- private class ConnectThread extends Thread {
-
- public void run() {
- AltosDebug.debug("ConnectThread: BEGIN (pause %b)", pause);
- setName("ConnectThread");
-
- if (pause) {
- try {
- Thread.sleep(4000);
- } catch (InterruptedException e) {
- }
- }
-
- create_socket(device);
- // Always cancel discovery because it will slow down a connection
- try {
- BluetoothAdapter.getDefaultAdapter().cancelDiscovery();
- } catch (Exception e) {
- AltosDebug.debug("cancelDiscovery exception %s", e.toString());
- }
-
- BluetoothSocket local_socket = null;
-
- synchronized (AltosBluetooth.this) {
- if (!closed())
- local_socket = socket;
- }
-
- if (local_socket != null) {
- try {
- // Make a connection to the BluetoothSocket
- // This is a blocking call and will only return on a
- // successful connection or an exception
- local_socket.connect();
- } catch (Exception e) {
- AltosDebug.debug("Connect exception %s", e.toString());
- try {
- local_socket.close();
- } catch (Exception ce) {
- AltosDebug.debug("Close exception %s", ce.toString());
- }
- local_socket = null;
- }
- }
-
- if (local_socket != null) {
- connected();
- } else {
- connect_failed();
- }
-
- AltosDebug.debug("ConnectThread: completed");
- }
- }
-
- private synchronized void wait_connected() throws InterruptedException, IOException {
- AltosDebug.check_ui("wait_connected\n");
- if (input == null && socket != null) {
- AltosDebug.debug("wait_connected...");
- wait();
- AltosDebug.debug("wait_connected done");
- }
- if (socket == null)
- throw new IOException();
- }
-
- int write(byte[] buffer, int len) {
- if (output == null)
- return -1;
- try {
- output.write(buffer, 0, len);
- } catch (IOException ie) {
- return -1;
- }
- return len;
- }
-
- int read(byte[] buffer, int len) {
- if (input == null)
- return -1;
- try {
- return input.read(buffer, 0, len);
- } catch (IOException ie) {
- return -1;
- }
- }
-
- // Stubs of required methods when extending AltosLink
- public boolean can_cancel_reply() { return false; }
- public boolean show_reply_timeout() { return true; }
- public void hide_reply_timeout() { }
-
-}
+++ /dev/null
-/*
- * Copyright © 2015 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.
- */
-package org.altusmetrum.AltosDroid;
-
-import java.util.Arrays;
-import java.io.*;
-import java.lang.*;
-
-import org.altusmetrum.altoslib_13.*;
-
-import android.app.Activity;
-import android.graphics.*;
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentTransaction;
-import android.view.*;
-import android.widget.*;
-import android.location.Location;
-import android.content.*;
-import android.util.Log;
-import android.os.*;
-import android.content.pm.*;
-
-public class AltosDebug {
- // Debugging
- static final String TAG = "AltosDroid";
-
- static boolean D = true;
-
- static void init(Context context) {
- ApplicationInfo app_info = context.getApplicationInfo();
-
- if ((app_info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
- Log.d(TAG, "Enable debugging\n");
- D = true;
- } else {
- Log.d(TAG, "Disable debugging\n");
- D = false;
- }
- }
-
-
- static void info(String format, Object ... arguments) {
- Log.i(TAG, String.format(format, arguments));
- }
-
- static void debug(String format, Object ... arguments) {
- if (D)
- Log.d(TAG, String.format(format, arguments));
- }
-
- static void error(String format, Object ... arguments) {
- Log.e(TAG, String.format(format, arguments));
- }
-
- static void check_ui(String format, Object ... arguments) {
- if (Looper.myLooper() == Looper.getMainLooper()) {
- Log.e(TAG, String.format("ON UI THREAD " + format, arguments));
- for (StackTraceElement el : Thread.currentThread().getStackTrace())
- Log.e(TAG, "\t" + el.toString() + "\n");
- }
- }
-}
+++ /dev/null
-/*
- * Copyright © 2012-2013 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; 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.
- */
-
-package org.altusmetrum.AltosDroid;
-
-import java.lang.ref.WeakReference;
-import java.text.*;
-import java.util.*;
-import java.io.*;
-
-import android.app.Activity;
-import android.app.PendingIntent;
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
-import android.content.Intent;
-import android.content.Context;
-import android.content.ComponentName;
-import android.content.ServiceConnection;
-import android.content.DialogInterface;
-import android.os.IBinder;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.os.Messenger;
-import android.os.RemoteException;
-import android.content.res.Resources;
-import android.support.v4.app.FragmentActivity;
-import android.support.v4.app.FragmentManager;
-import android.util.DisplayMetrics;
-import android.view.*;
-import android.widget.*;
-import android.app.AlertDialog;
-import android.location.Location;
-import android.location.LocationManager;
-import android.location.LocationListener;
-import android.hardware.usb.*;
-import android.graphics.*;
-import android.graphics.drawable.*;
-
-import org.altusmetrum.altoslib_13.*;
-
-class SavedState {
- long received_time;
- int state;
- boolean locked;
- String callsign;
- int serial;
- int flight;
- int rssi;
-
- SavedState(AltosState state) {
- received_time = state.received_time;
- this.state = state.state();
- if (state.gps != null)
- locked = state.gps.locked;
- else
- locked = false;
- callsign = state.cal_data().callsign;
- serial = state.cal_data().serial;
- flight = state.cal_data().flight;
- rssi = state.rssi;
- }
-}
-
-class Tracker implements CharSequence, Comparable {
- int serial;
- String call;
- double frequency;
-
- String display;
-
- public Tracker(int serial, String call, double frequency) {
- if (call == null)
- call = "none";
-
- this.serial = serial;
- this.call = call;
- this.frequency = frequency;
- if (frequency == 0.0)
- display = "Auto";
- else if (frequency == AltosLib.MISSING) {
- display = String.format("%-8.8s %6d", call, serial);
- } else {
- display = String.format("%-8.8s %7.3f %6d", call, frequency, serial);
- }
- }
-
- public Tracker(AltosState s) {
- this(s == null ? 0 : s.cal_data().serial,
- s == null ? null : s.cal_data().callsign,
- s == null ? 0.0 : s.frequency);
- }
-
- /* CharSequence */
- public char charAt(int index) {
- return display.charAt(index);
- }
-
- public int length() {
- return display.length();
- }
-
- public CharSequence subSequence(int start, int end) throws IndexOutOfBoundsException {
- return display.subSequence(start, end);
- }
-
- public String toString() {
- return display.toString();
- }
-
- /* Comparable */
- public int compareTo (Object other) {
- Tracker o = (Tracker) other;
- if (frequency == 0.0) {
- if (o.frequency == 0.0)
- return 0;
- return -1;
- }
- if (o.frequency == 0.0)
- return 1;
-
- int a = serial - o.serial;
- int b = call.compareTo(o.call);
- int c = (int) Math.signum(frequency - o.frequency);
-
- if (b != 0)
- return b;
- if (c != 0)
- return c;
- return a;
- }
-}
-
-public class AltosDroid extends FragmentActivity implements AltosUnitsListener, LocationListener {
-
- // Actions sent to the telemetry server at startup time
-
- public static final String ACTION_BLUETOOTH = "org.altusmetrum.AltosDroid.BLUETOOTH";
- public static final String ACTION_USB = "org.altusmetrum.AltosDroid.USB";
-
- // Message types received by our Handler
-
- public static final int MSG_STATE = 1;
- public static final int MSG_UPDATE_AGE = 2;
- public static final int MSG_IDLE_MODE = 3;
- public static final int MSG_IGNITER_STATUS = 4;
-
- // Intent request codes
- public static final int REQUEST_CONNECT_DEVICE = 1;
- public static final int REQUEST_ENABLE_BT = 2;
- public static final int REQUEST_PRELOAD_MAPS = 3;
- public static final int REQUEST_IDLE_MODE = 5;
- public static final int REQUEST_IGNITERS = 6;
- public static final int REQUEST_SETUP = 7;
-
- public static final String EXTRA_IDLE_MODE = "idle_mode";
- public static final String EXTRA_IDLE_RESULT = "idle_result";
- public static final String EXTRA_TELEMETRY_SERVICE = "telemetry_service";
-
- // Setup result bits
- public static final int SETUP_BAUD = 1;
- public static final int SETUP_UNITS = 2;
- public static final int SETUP_MAP_SOURCE = 4;
- public static final int SETUP_MAP_TYPE = 8;
-
- public static FragmentManager fm;
-
- private BluetoothAdapter mBluetoothAdapter = null;
-
- // Flight state values
- private TextView mCallsignView;
- private TextView mRSSIView;
- private TextView mSerialView;
- private TextView mFlightView;
- private RelativeLayout mStateLayout;
- private TextView mStateView;
- private TextView mAgeView;
- private boolean mAgeViewOld;
- private int mAgeNewColor;
- private int mAgeOldColor;
-
- public static final String tab_pad_name = "pad";
- public static final String tab_flight_name = "flight";
- public static final String tab_recover_name = "recover";
- public static final String tab_map_name = "map";
-
- // field to display the version at the bottom of the screen
- private TextView mVersion;
-
- private boolean idle_mode = false;
-
- public Location location = null;
-
- private AltosState state;
- private SavedState saved_state;
-
- // Tabs
- TabHost mTabHost;
- AltosViewPager mViewPager;
- TabsAdapter mTabsAdapter;
- ArrayList<AltosDroidTab> mTabs = new ArrayList<AltosDroidTab>();
- int tabHeight;
-
- // Timer and Saved flight state for Age calculation
- private Timer timer;
-
- TelemetryState telemetry_state;
- Tracker[] trackers;
-
-
- UsbDevice pending_usb_device;
- boolean start_with_usb;
-
- // Service
- private boolean mIsBound = false;
- private Messenger mService = null;
- final Messenger mMessenger = new Messenger(new IncomingHandler(this));
-
- // Text to Speech
- private AltosVoice mAltosVoice = null;
-
- // The Handler that gets information back from the Telemetry Service
- static class IncomingHandler extends Handler {
- private final WeakReference<AltosDroid> mAltosDroid;
- IncomingHandler(AltosDroid ad) { mAltosDroid = new WeakReference<AltosDroid>(ad); }
-
- @Override
- public void handleMessage(Message msg) {
- AltosDroid ad = mAltosDroid.get();
-
- switch (msg.what) {
- case MSG_STATE:
- if (msg.obj == null) {
- AltosDebug.debug("telemetry_state null!");
- return;
- }
- ad.update_state((TelemetryState) msg.obj);
- break;
- case MSG_UPDATE_AGE:
- ad.update_age();
- break;
- case MSG_IDLE_MODE:
- ad.idle_mode = (Boolean) msg.obj;
- ad.update_state(null);
- break;
- }
- }
- };
-
-
- private ServiceConnection mConnection = new ServiceConnection() {
- public void onServiceConnected(ComponentName className, IBinder service) {
- mService = new Messenger(service);
- try {
- Message msg = Message.obtain(null, TelemetryService.MSG_REGISTER_CLIENT);
- msg.replyTo = mMessenger;
- mService.send(msg);
- } catch (RemoteException e) {
- // In this case the service has crashed before we could even do anything with it
- }
- if (pending_usb_device != null) {
- try {
- mService.send(Message.obtain(null, TelemetryService.MSG_OPEN_USB, pending_usb_device));
- pending_usb_device = null;
- } catch (RemoteException e) {
- }
- }
- }
-
- public void onServiceDisconnected(ComponentName className) {
- // This is called when the connection with the service has been unexpectedly disconnected - process crashed.
- mService = null;
- }
- };
-
- void doBindService() {
- bindService(new Intent(this, TelemetryService.class), mConnection, Context.BIND_AUTO_CREATE);
- mIsBound = true;
- }
-
- void doUnbindService() {
- if (mIsBound) {
- // If we have received the service, and hence registered with it, then now is the time to unregister.
- if (mService != null) {
- try {
- Message msg = Message.obtain(null, TelemetryService.MSG_UNREGISTER_CLIENT);
- msg.replyTo = mMessenger;
- mService.send(msg);
- } catch (RemoteException e) {
- // There is nothing special we need to do if the service has crashed.
- }
- }
- // Detach our existing connection.
- unbindService(mConnection);
- mIsBound = false;
- }
- }
-
- public void registerTab(AltosDroidTab mTab) {
- mTabs.add(mTab);
- }
-
- public void unregisterTab(AltosDroidTab mTab) {
- mTabs.remove(mTab);
- }
-
- public void units_changed(boolean imperial_units) {
- for (AltosDroidTab mTab : mTabs)
- mTab.units_changed(imperial_units);
- }
-
- void update_title(TelemetryState telemetry_state) {
- switch (telemetry_state.connect) {
- case TelemetryState.CONNECT_CONNECTED:
- if (telemetry_state.config != null) {
- String str = String.format("S/N %d %6.3f MHz%s", telemetry_state.config.serial,
- telemetry_state.frequency, idle_mode ? " (idle)" : "");
- if (telemetry_state.telemetry_rate != AltosLib.ao_telemetry_rate_38400)
- str = str.concat(String.format(" %d bps",
- AltosLib.ao_telemetry_rate_values[telemetry_state.telemetry_rate]));
- setTitle(str);
- } else {
- setTitle(R.string.title_connected_to);
- }
- break;
- case TelemetryState.CONNECT_CONNECTING:
- if (telemetry_state.address != null)
- setTitle(String.format("Connecting to %s...", telemetry_state.address.name));
- else
- setTitle("Connecting to something...");
- break;
- case TelemetryState.CONNECT_DISCONNECTED:
- case TelemetryState.CONNECT_NONE:
- setTitle(R.string.title_not_connected);
- break;
- }
- }
-
- void start_timer() {
- if (timer == null) {
- timer = new Timer();
- timer.scheduleAtFixedRate(new TimerTask(){ public void run() {onTimerTick();}}, 1000L, 1000L);
- }
- }
-
- void stop_timer() {
- if (timer != null) {
- timer.cancel();
- timer.purge();
- timer = null;
- }
- }
-
- int selected_serial = 0;
- int current_serial;
- long switch_time;
-
- void set_switch_time() {
- switch_time = System.currentTimeMillis();
- selected_serial = 0;
- }
-
- boolean registered_units_listener;
-
- void update_state(TelemetryState new_telemetry_state) {
-
- if (new_telemetry_state != null)
- telemetry_state = new_telemetry_state;
-
- if (selected_serial != 0)
- current_serial = selected_serial;
-
- if (current_serial == 0)
- current_serial = telemetry_state.latest_serial;
-
- if (!registered_units_listener) {
- registered_units_listener = true;
- AltosPreferences.register_units_listener(this);
- }
-
- int num_trackers = 0;
- for (AltosState s : telemetry_state.states.values()) {
- num_trackers++;
- }
-
- trackers = new Tracker[num_trackers + 1];
-
- int n = 0;
- trackers[n++] = new Tracker(0, "auto", 0.0);
-
- for (AltosState s : telemetry_state.states.values())
- trackers[n++] = new Tracker(s);
-
- Arrays.sort(trackers);
-
- update_title(telemetry_state);
-
- AltosState state = null;
- boolean aged = true;
-
- if (telemetry_state.states.containsKey(current_serial)) {
- state = telemetry_state.states.get(current_serial);
- int age = state_age(state.received_time);
- if (age < 20)
- aged = false;
- if (current_serial == selected_serial)
- aged = false;
- else if (switch_time != 0 && (switch_time - state.received_time) > 0)
- aged = true;
- }
-
- if (aged) {
- AltosState newest_state = null;
- int newest_age = 0;
-
- for (int serial : telemetry_state.states.keySet()) {
- AltosState existing = telemetry_state.states.get(serial);
- int existing_age = state_age(existing.received_time);
-
- if (newest_state == null || existing_age < newest_age) {
- newest_state = existing;
- newest_age = existing_age;
- }
- }
-
- if (newest_state != null)
- state = newest_state;
- }
-
- update_ui(telemetry_state, state, telemetry_state.quiet);
-
- start_timer();
- }
-
- boolean same_string(String a, String b) {
- if (a == null) {
- if (b == null)
- return true;
- return false;
- } else {
- if (b == null)
- return false;
- return a.equals(b);
- }
- }
-
-
- private int blend_component(int a, int b, double r, int shift, int mask) {
- return ((int) (((a >> shift) & mask) * r + ((b >> shift) & mask) * (1 - r)) & mask) << shift;
- }
- private int blend_color(int a, int b, double r) {
- return (blend_component(a, b, r, 0, 0xff) |
- blend_component(a, b, r, 8, 0xff) |
- blend_component(a, b, r, 16, 0xff) |
- blend_component(a, b, r, 24, 0xff));
- }
-
- int state_age(long received_time) {
- return (int) ((System.currentTimeMillis() - received_time + 500) / 1000);
- }
-
- void set_screen_on(int age) {
- if (age < 60)
- getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- else
- getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- }
-
- void update_age() {
- if (saved_state != null) {
- int age = state_age(saved_state.received_time);
-
- double age_scale = age / 100.0;
-
- if (age_scale > 1.0)
- age_scale = 1.0;
-
- mAgeView.setTextColor(blend_color(mAgeOldColor, mAgeNewColor, age_scale));
-
- set_screen_on(age);
-
- String text;
- if (age < 60)
- text = String.format("%ds", age);
- else if (age < 60 * 60)
- text = String.format("%dm", age / 60);
- else if (age < 60 * 60 * 24)
- text = String.format("%dh", age / (60 * 60));
- else
- text = String.format("%dd", age / (24 * 60 * 60));
- mAgeView.setText(text);
- }
- }
-
- void update_ui(TelemetryState telem_state, AltosState state, boolean quiet) {
-
- this.state = state;
-
- int prev_state = AltosLib.ao_flight_invalid;
-
- AltosGreatCircle from_receiver = null;
-
- if (saved_state != null)
- prev_state = saved_state.state;
-
- if (state != null) {
- set_screen_on(state_age(state.received_time));
-
- if (state.state() == AltosLib.ao_flight_stateless) {
- boolean prev_locked = false;
- boolean locked = false;
-
- if(state.gps != null)
- locked = state.gps.locked;
- if (saved_state != null)
- prev_locked = saved_state.locked;
- if (prev_locked != locked) {
- String currentTab = mTabHost.getCurrentTabTag();
- if (locked) {
- if (currentTab.equals(tab_pad_name)) mTabHost.setCurrentTabByTag(tab_flight_name);
- } else {
- if (currentTab.equals(tab_flight_name)) mTabHost.setCurrentTabByTag(tab_pad_name);
- }
- }
- } else {
- if (prev_state != state.state()) {
- String currentTab = mTabHost.getCurrentTabTag();
- switch (state.state()) {
- case AltosLib.ao_flight_boost:
- if (currentTab.equals(tab_pad_name)) mTabHost.setCurrentTabByTag(tab_flight_name);
- break;
- case AltosLib.ao_flight_landed:
- if (currentTab.equals(tab_flight_name)) mTabHost.setCurrentTabByTag(tab_recover_name);
- break;
- case AltosLib.ao_flight_stateless:
- if (currentTab.equals(tab_pad_name)) mTabHost.setCurrentTabByTag(tab_flight_name);
- break;
- }
- }
- }
-
- if (location != null && state.gps != null && state.gps.locked) {
- double altitude = 0;
- if (location.hasAltitude())
- altitude = location.getAltitude();
- from_receiver = new AltosGreatCircle(location.getLatitude(),
- location.getLongitude(),
- altitude,
- state.gps.lat,
- state.gps.lon,
- state.gps.alt);
- }
-
- if (saved_state == null || !same_string(saved_state.callsign, state.cal_data().callsign)) {
- mCallsignView.setText(state.cal_data().callsign);
- }
- if (saved_state == null || state.cal_data().serial != saved_state.serial) {
- if (state.cal_data().serial == AltosLib.MISSING)
- mSerialView.setText("");
- else
- mSerialView.setText(String.format("%d", state.cal_data().serial));
- }
- if (saved_state == null || state.cal_data().flight != saved_state.flight) {
- if (state.cal_data().flight == AltosLib.MISSING)
- mFlightView.setText("");
- else
- mFlightView.setText(String.format("%d", state.cal_data().flight));
- }
- if (saved_state == null || state.state() != saved_state.state) {
- if (state.state() == AltosLib.ao_flight_stateless) {
- mStateLayout.setVisibility(View.GONE);
- } else {
- mStateView.setText(state.state_name());
- mStateLayout.setVisibility(View.VISIBLE);
- }
- }
- if (saved_state == null || state.rssi != saved_state.rssi) {
- if (state.rssi == AltosLib.MISSING)
- mRSSIView.setText("");
- else
- mRSSIView.setText(String.format("%d", state.rssi));
- }
- saved_state = new SavedState(state);
- }
-
- for (AltosDroidTab mTab : mTabs)
- mTab.update_ui(telem_state, state, from_receiver, location, mTab == mTabsAdapter.currentItem());
-
- AltosDebug.debug("quiet %b\n", quiet);
- if (mAltosVoice != null)
- mAltosVoice.tell(telem_state, state, from_receiver, location, (AltosDroidTab) mTabsAdapter.currentItem(), quiet);
-
- }
-
- private void onTimerTick() {
- try {
- mMessenger.send(Message.obtain(null, MSG_UPDATE_AGE));
- } catch (RemoteException e) {
- }
- }
-
- static String pos(double p, String pos, String neg) {
- String h = pos;
- if (p == AltosLib.MISSING)
- return "";
- if (p < 0) {
- h = neg;
- p = -p;
- }
- int deg = (int) Math.floor(p);
- double min = (p - Math.floor(p)) * 60.0;
- return String.format("%d°%9.4f\" %s", deg, min, h);
- }
-
- static String number(String format, double value) {
- if (value == AltosLib.MISSING)
- return "";
- return String.format(format, value);
- }
-
- static String integer(String format, int value) {
- if (value == AltosLib.MISSING)
- return "";
- return String.format(format, value);
- }
-
- private View create_tab_view(String label) {
- LayoutInflater inflater = (LayoutInflater) this.getLayoutInflater();
- View tab_view = inflater.inflate(R.layout.tab_layout, null);
- TextView text_view = (TextView) tab_view.findViewById (R.id.tabLabel);
- text_view.setText(label);
- return tab_view;
- }
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- AltosDebug.init(this);
- AltosDebug.debug("+++ ON CREATE +++");
-
- // Initialise preferences
- AltosDroidPreferences.init(this);
-
- fm = getSupportFragmentManager();
-
- // Set up the window layout
- setContentView(R.layout.altosdroid);
-
- // Create the Tabs and ViewPager
- mTabHost = (TabHost)findViewById(android.R.id.tabhost);
- mTabHost.setup();
-
- mViewPager = (AltosViewPager)findViewById(R.id.pager);
- mViewPager.setOffscreenPageLimit(4);
-
- mTabsAdapter = new TabsAdapter(this, mTabHost, mViewPager);
-
- mTabsAdapter.addTab(mTabHost.newTabSpec(tab_pad_name).setIndicator(create_tab_view("Pad")), TabPad.class, null);
- mTabsAdapter.addTab(mTabHost.newTabSpec(tab_flight_name).setIndicator(create_tab_view("Flight")), TabFlight.class, null);
- mTabsAdapter.addTab(mTabHost.newTabSpec(tab_recover_name).setIndicator(create_tab_view("Recover")), TabRecover.class, null);
- mTabsAdapter.addTab(mTabHost.newTabSpec(tab_map_name).setIndicator(create_tab_view("Map")), TabMap.class, null);
-
- // Display the Version
- mVersion = (TextView) findViewById(R.id.version);
- mVersion.setText("Version: " + BuildInfo.version +
- " Built: " + BuildInfo.builddate + " " + BuildInfo.buildtime + " " + BuildInfo.buildtz +
- " (" + BuildInfo.branch + "-" + BuildInfo.commitnum + "-" + BuildInfo.commithash + ")");
-
- mCallsignView = (TextView) findViewById(R.id.callsign_value);
- mRSSIView = (TextView) findViewById(R.id.rssi_value);
- mSerialView = (TextView) findViewById(R.id.serial_value);
- mFlightView = (TextView) findViewById(R.id.flight_value);
- mStateLayout = (RelativeLayout) findViewById(R.id.state_container);
- mStateView = (TextView) findViewById(R.id.state_value);
- mAgeView = (TextView) findViewById(R.id.age_value);
- mAgeNewColor = mAgeView.getTextColors().getDefaultColor();
- mAgeOldColor = getResources().getColor(R.color.old_color);
- }
-
- private void ensureBluetooth() {
- // Get local Bluetooth adapter
- mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
-
- /* if there is a BT adapter and it isn't turned on, then turn it on */
- if (mBluetoothAdapter != null && !mBluetoothAdapter.isEnabled()) {
- Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
- startActivityForResult(enableIntent, AltosDroid.REQUEST_ENABLE_BT);
- }
- }
-
- private boolean check_usb() {
- UsbDevice device = AltosUsb.find_device(this, AltosLib.product_basestation);
-
- if (device != null) {
- Intent i = new Intent(this, AltosDroid.class);
- PendingIntent pi = PendingIntent.getActivity(this, 0, new Intent("hello world", null, this, AltosDroid.class), 0);
-
- if (AltosUsb.request_permission(this, device, pi)) {
- connectUsb(device);
- }
- start_with_usb = true;
- return true;
- }
-
- start_with_usb = false;
-
- return false;
- }
-
- private void noticeIntent(Intent intent) {
-
- /* Ok, this is pretty convenient.
- *
- * When a USB device is plugged in, and our 'hotplug'
- * intent registration fires, we get an Intent with
- * EXTRA_DEVICE set.
- *
- * When we start up and see a usb device and request
- * permission to access it, that queues a
- * PendingIntent, which has the EXTRA_DEVICE added in,
- * along with the EXTRA_PERMISSION_GRANTED field as
- * well.
- *
- * So, in both cases, we get the device name using the
- * same call. We check to see if access was granted,
- * in which case we ignore the device field and do our
- * usual startup thing.
- */
-
- UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
- boolean granted = intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, true);
-
- AltosDebug.debug("intent %s device %s granted %s", intent, device, granted);
-
- if (!granted)
- device = null;
-
- if (device != null) {
- AltosDebug.debug("intent has usb device " + device.toString());
- connectUsb(device);
- } else {
-
- /* 'granted' is only false if this intent came
- * from the request_permission call and
- * permission was denied. In which case, we
- * don't want to loop forever...
- */
- if (granted) {
- AltosDebug.debug("check for a USB device at startup");
- if (check_usb())
- return;
- }
- AltosDebug.debug("Starting by looking for bluetooth devices");
- ensureBluetooth();
- }
- }
-
- @Override
- public void onStart() {
- super.onStart();
- AltosDebug.debug("++ ON START ++");
-
- set_switch_time();
-
- noticeIntent(getIntent());
-
- // Start Telemetry Service
- String action = start_with_usb ? ACTION_USB : ACTION_BLUETOOTH;
-
- startService(new Intent(action, null, AltosDroid.this, TelemetryService.class));
-
- doBindService();
-
- if (mAltosVoice == null)
- mAltosVoice = new AltosVoice(this);
-
- }
-
- @Override
- public void onNewIntent(Intent intent) {
- super.onNewIntent(intent);
- AltosDebug.debug("onNewIntent");
- noticeIntent(intent);
- }
-
- @Override
- public void onResume() {
- super.onResume();
- AltosDebug.debug("+ ON RESUME +");
-
- // Listen for GPS and Network position updates
- LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
- locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 1, this);
-
- location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
-
- if (location != null)
- AltosDebug.debug("Resume, location is %f,%f\n",
- location.getLatitude(),
- location.getLongitude());
-
- update_ui(telemetry_state, state, true);
- }
-
- @Override
- public void onPause() {
- super.onPause();
- AltosDebug.debug("- ON PAUSE -");
- // Stop listening for location updates
- ((LocationManager) getSystemService(Context.LOCATION_SERVICE)).removeUpdates(this);
- }
-
- @Override
- public void onStop() {
- super.onStop();
- AltosDebug.debug("-- ON STOP --");
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- AltosDebug.debug("--- ON DESTROY ---");
-
- doUnbindService();
- if (mAltosVoice != null) {
- mAltosVoice.stop();
- mAltosVoice = null;
- }
- stop_timer();
- }
-
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- AltosDebug.debug("onActivityResult " + resultCode);
- switch (requestCode) {
- case REQUEST_CONNECT_DEVICE:
- // When DeviceListActivity returns with a device to connect to
- if (resultCode == Activity.RESULT_OK) {
- connectDevice(data);
- }
- break;
- case REQUEST_ENABLE_BT:
- // When the request to enable Bluetooth returns
- if (resultCode == Activity.RESULT_OK) {
- // Bluetooth is now enabled, so set up a chat session
- //setupChat();
- AltosDebug.debug("BT enabled");
- bluetoothEnabled(data);
- } else {
- // User did not enable Bluetooth or an error occured
- AltosDebug.debug("BT not enabled");
- }
- break;
- case REQUEST_IDLE_MODE:
- if (resultCode == Activity.RESULT_OK)
- idle_mode(data);
- break;
- case REQUEST_IGNITERS:
- break;
- case REQUEST_SETUP:
- if (resultCode == Activity.RESULT_OK)
- note_setup_changes(data);
- break;
- }
- }
-
- private void note_setup_changes(Intent data) {
- int changes = data.getIntExtra(SetupActivity.EXTRA_SETUP_CHANGES, 0);
-
- if ((changes & SETUP_BAUD) != 0) {
- try {
- mService.send(Message.obtain(null, TelemetryService.MSG_SETBAUD,
- AltosPreferences.telemetry_rate(1)));
- } catch (RemoteException re) {
- }
- }
- if ((changes & SETUP_UNITS) != 0) {
- /* nothing to do here */
- }
- if ((changes & SETUP_MAP_SOURCE) != 0) {
- /* nothing to do here */
- }
- if ((changes & SETUP_MAP_TYPE) != 0) {
- /* nothing to do here */
- }
- set_switch_time();
- }
-
- private void connectUsb(UsbDevice device) {
- if (mService == null)
- pending_usb_device = device;
- else {
- // Attempt to connect to the device
- try {
- mService.send(Message.obtain(null, TelemetryService.MSG_OPEN_USB, device));
- AltosDebug.debug("Sent OPEN_USB message");
- } catch (RemoteException e) {
- AltosDebug.debug("connect device message failed");
- }
- }
- }
-
- private void bluetoothEnabled(Intent data) {
- try {
- mService.send(Message.obtain(null, TelemetryService.MSG_BLUETOOTH_ENABLED, null));
- } catch (RemoteException e) {
- AltosDebug.debug("send BT enabled message failed");
- }
- }
-
- private void connectDevice(Intent data) {
- // Attempt to connect to the device
- try {
- String address = data.getExtras().getString(DeviceListActivity.EXTRA_DEVICE_ADDRESS);
- String name = data.getExtras().getString(DeviceListActivity.EXTRA_DEVICE_NAME);
-
- AltosDebug.debug("Connecting to " + address + " " + name);
- DeviceAddress a = new DeviceAddress(address, name);
- mService.send(Message.obtain(null, TelemetryService.MSG_CONNECT, a));
- AltosDebug.debug("Sent connecting message");
- } catch (RemoteException e) {
- AltosDebug.debug("connect device message failed");
- }
- }
-
- private void disconnectDevice(boolean remember) {
- try {
- mService.send(Message.obtain(null, TelemetryService.MSG_DISCONNECT, (Boolean) remember));
- } catch (RemoteException e) {
- }
- }
-
- private void idle_mode(Intent data) {
- int type = data.getIntExtra(IdleModeActivity.EXTRA_IDLE_RESULT, -1);
- Message msg;
-
- AltosDebug.debug("intent idle_mode %d", type);
- switch (type) {
- case IdleModeActivity.IDLE_MODE_CONNECT:
- msg = Message.obtain(null, TelemetryService.MSG_MONITOR_IDLE_START);
- try {
- mService.send(msg);
- } catch (RemoteException re) {
- }
- break;
- case IdleModeActivity.IDLE_MODE_DISCONNECT:
- msg = Message.obtain(null, TelemetryService.MSG_MONITOR_IDLE_STOP);
- try {
- mService.send(msg);
- } catch (RemoteException re) {
- }
- break;
- case IdleModeActivity.IDLE_MODE_REBOOT:
- msg = Message.obtain(null, TelemetryService.MSG_REBOOT);
- try {
- mService.send(msg);
- } catch (RemoteException re) {
- }
- break;
- case IdleModeActivity.IDLE_MODE_IGNITERS:
- Intent serverIntent = new Intent(this, IgniterActivity.class);
- startActivityForResult(serverIntent, REQUEST_IGNITERS);
- break;
- }
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.option_menu, menu);
- return true;
- }
-
- void setFrequency(double freq) {
- try {
- mService.send(Message.obtain(null, TelemetryService.MSG_SETFREQUENCY, freq));
- set_switch_time();
- } catch (RemoteException e) {
- }
- }
-
- void setFrequency(AltosFrequency frequency) {
- setFrequency (frequency.frequency);
- }
-
- void setBaud(int baud) {
- try {
- mService.send(Message.obtain(null, TelemetryService.MSG_SETBAUD, baud));
- set_switch_time();
- } catch (RemoteException e) {
- }
- }
-
- void setBaud(String baud) {
- try {
- int value = Integer.parseInt(baud);
- int rate = AltosLib.ao_telemetry_rate_38400;
- switch (value) {
- case 2400:
- rate = AltosLib.ao_telemetry_rate_2400;
- break;
- case 9600:
- rate = AltosLib.ao_telemetry_rate_9600;
- break;
- case 38400:
- rate = AltosLib.ao_telemetry_rate_38400;
- break;
- }
- setBaud(rate);
- } catch (NumberFormatException e) {
- }
- }
-
- void select_tracker(int serial) {
- int i;
-
- AltosDebug.debug("select tracker %d\n", serial);
-
- if (serial == selected_serial) {
- AltosDebug.debug("%d already selected\n", serial);
- return;
- }
-
- if (serial != 0) {
- for (i = 0; i < trackers.length; i++)
- if (trackers[i].serial == serial)
- break;
-
- if (i == trackers.length) {
- AltosDebug.debug("attempt to select unknown tracker %d\n", serial);
- return;
- }
- }
-
- current_serial = selected_serial = serial;
- update_state(null);
- }
-
- void touch_trackers(Integer[] serials) {
- AlertDialog.Builder builder_tracker = new AlertDialog.Builder(this);
- builder_tracker.setTitle("Select Tracker");
-
- final Tracker[] my_trackers = new Tracker[serials.length + 1];
-
- my_trackers[0] = new Tracker(null);
-
- for (int i = 0; i < serials.length; i++) {
- AltosState s = telemetry_state.states.get(serials[i]);
- my_trackers[i+1] = new Tracker(s);
- }
- builder_tracker.setItems(my_trackers,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int item) {
- if (item == 0)
- select_tracker(0);
- else
- select_tracker(my_trackers[item].serial);
- }
- });
- AlertDialog alert_tracker = builder_tracker.create();
- alert_tracker.show();
- }
-
- void delete_track(int serial) {
- try {
- mService.send(Message.obtain(null, TelemetryService.MSG_DELETE_SERIAL, (Integer) serial));
- } catch (Exception ex) {
- }
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- Intent serverIntent = null;
- switch (item.getItemId()) {
- case R.id.connect_scan:
- ensureBluetooth();
- // Launch the DeviceListActivity to see devices and do scan
- serverIntent = new Intent(this, DeviceListActivity.class);
- startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE);
- return true;
- case R.id.disconnect:
- /* Disconnect the device
- */
- disconnectDevice(false);
- return true;
- case R.id.quit:
- AltosDebug.debug("R.id.quit");
- disconnectDevice(true);
- finish();
- return true;
- case R.id.setup:
- serverIntent = new Intent(this, SetupActivity.class);
- startActivityForResult(serverIntent, REQUEST_SETUP);
- return true;
- case R.id.select_freq:
- // Set the TBT radio frequency
-
- final AltosFrequency[] frequencies = AltosPreferences.common_frequencies();
- String[] frequency_strings = new String[frequencies.length];
- for (int i = 0; i < frequencies.length; i++)
- frequency_strings[i] = frequencies[i].toString();
-
- AlertDialog.Builder builder_freq = new AlertDialog.Builder(this);
- builder_freq.setTitle("Pick a frequency");
- builder_freq.setItems(frequency_strings,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int item) {
- setFrequency(frequencies[item]);
- }
- });
- AlertDialog alert_freq = builder_freq.create();
- alert_freq.show();
- return true;
- case R.id.select_tracker:
- if (trackers != null) {
- AlertDialog.Builder builder_serial = new AlertDialog.Builder(this);
- builder_serial.setTitle("Select a tracker");
- builder_serial.setItems(trackers,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int item) {
- System.out.printf("select item %d %s\n", item, trackers[item].display);
- if (item == 0)
- select_tracker(0);
- else
- select_tracker(trackers[item].serial);
- }
- });
- AlertDialog alert_serial = builder_serial.create();
- alert_serial.show();
-
- }
- return true;
- case R.id.delete_track:
- if (trackers != null) {
- AlertDialog.Builder builder_serial = new AlertDialog.Builder(this);
- builder_serial.setTitle("Delete a track");
- final Tracker[] my_trackers = new Tracker[trackers.length - 1];
- for (int i = 0; i < trackers.length - 1; i++)
- my_trackers[i] = trackers[i+1];
- builder_serial.setItems(my_trackers,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int item) {
- delete_track(my_trackers[item].serial);
- }
- });
- AlertDialog alert_serial = builder_serial.create();
- alert_serial.show();
-
- }
- return true;
- case R.id.idle_mode:
- serverIntent = new Intent(this, IdleModeActivity.class);
- serverIntent.putExtra(EXTRA_IDLE_MODE, idle_mode);
- startActivityForResult(serverIntent, REQUEST_IDLE_MODE);
- return true;
- }
- return false;
- }
-
- static String direction(AltosGreatCircle from_receiver,
- Location receiver) {
- if (from_receiver == null)
- return null;
-
- if (receiver == null)
- return null;
-
- if (!receiver.hasBearing())
- return null;
-
- float bearing = receiver.getBearing();
- float heading = (float) from_receiver.bearing - bearing;
-
- while (heading <= -180.0f)
- heading += 360.0f;
- while (heading > 180.0f)
- heading -= 360.0f;
-
- int iheading = (int) (heading + 0.5f);
-
- if (-1 < iheading && iheading < 1)
- return "ahead";
- else if (iheading < -179 || 179 < iheading)
- return "backwards";
- else if (iheading < 0)
- return String.format("left %d°", -iheading);
- else
- return String.format("right %d°", iheading);
- }
-
- public void onLocationChanged(Location location) {
- this.location = location;
- AltosDebug.debug("Location changed to %f,%f",
- location.getLatitude(),
- location.getLongitude());
- update_ui(telemetry_state, state, false);
- }
-
- public void onStatusChanged(String provider, int status, Bundle extras) {
- AltosDebug.debug("Location status now %d\n", status);
- }
-
- public void onProviderEnabled(String provider) {
- AltosDebug.debug("Location provider enabled %s\n", provider);
- }
-
- public void onProviderDisabled(String provider) {
- AltosDebug.debug("Location provider disabled %s\n", provider);
- }
-}
+++ /dev/null
-/*
- * Copyright © 2015 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.
- */
-
-package org.altusmetrum.AltosDroid;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.UUID;
-
-import android.os.Handler;
-
-import org.altusmetrum.altoslib_13.*;
-
-public abstract class AltosDroidLink extends AltosLink {
-
- Handler handler;
-
- Thread input_thread = null;
-
- public double frequency() {
- return frequency;
- }
-
- public int telemetry_rate() {
- return telemetry_rate;
- }
-
- public void save_frequency() {
- AltosPreferences.set_frequency(0, frequency);
- }
-
- public void save_telemetry_rate() {
- AltosPreferences.set_telemetry_rate(0, telemetry_rate);
- }
-
- Object closed_lock = new Object();
- boolean closing = false;
- boolean closed = false;
-
- public boolean closed() {
- synchronized(closed_lock) {
- return closing;
- }
- }
-
- void connected() throws InterruptedException {
- input_thread = new Thread(this);
- input_thread.start();
-
- // Configure the newly connected device for telemetry
- print("~\nE 0\n");
- set_monitor(false);
- AltosDebug.debug("ConnectThread: connected");
-
- /* Let TelemetryService know we're connected
- */
- handler.obtainMessage(TelemetryService.MSG_CONNECTED, this).sendToTarget();
-
- /* Notify other waiting threads that we're connected now
- */
- notifyAll();
- }
-
- public void closing() {
- synchronized(closed_lock) {
- AltosDebug.debug("Marked closing true");
- closing = true;
- }
- }
-
- private boolean actually_closed() {
- synchronized(closed_lock) {
- return closed;
- }
- }
-
- abstract void close_device();
-
- public void close() {
- AltosDebug.debug("close(): begin");
-
- closing();
-
- flush_output();
-
- synchronized (closed_lock) {
- AltosDebug.debug("Marked closed true");
- closed = true;
- }
-
- close_device();
-
- synchronized(this) {
-
- if (input_thread != null) {
- AltosDebug.debug("close(): stopping input_thread");
- try {
- AltosDebug.debug("close(): input_thread.interrupt().....");
- input_thread.interrupt();
- AltosDebug.debug("close(): input_thread.join().....");
- input_thread.join();
- } catch (Exception e) {}
- input_thread = null;
- }
- notifyAll();
- }
- }
-
- abstract int write(byte[] buffer, int len);
-
- abstract int read(byte[] buffer, int len);
-
- private static final int buffer_size = 64;
-
- private byte[] in_buffer = new byte[buffer_size];
- private byte[] out_buffer = new byte[buffer_size];
- private int buffer_len = 0;
- private int buffer_off = 0;
- private int out_buffer_off = 0;
-
- private byte[] debug_chars = new byte[buffer_size];
- private int debug_off;
-
- private void debug_input(byte b) {
- if (b == '\n') {
- AltosDebug.debug(" " + new String(debug_chars, 0, debug_off));
- debug_off = 0;
- } else {
- if (debug_off < buffer_size)
- debug_chars[debug_off++] = b;
- }
- }
-
- private void disconnected() {
- if (closed()) {
- AltosDebug.debug("disconnected after closed");
- return;
- }
-
- AltosDebug.debug("Sending disconnected message");
- handler.obtainMessage(TelemetryService.MSG_DISCONNECTED, this).sendToTarget();
- }
-
- public int getchar() {
-
- if (actually_closed())
- return ERROR;
-
- while (buffer_off == buffer_len) {
- buffer_len = read(in_buffer, buffer_size);
- if (buffer_len < 0) {
- AltosDebug.debug("ERROR returned from getchar()");
- disconnected();
- return ERROR;
- }
- buffer_off = 0;
- }
-// if (AltosDebug.D)
-// debug_input(in_buffer[buffer_off]);
- return in_buffer[buffer_off++];
- }
-
- public void flush_output() {
- super.flush_output();
-
- if (actually_closed()) {
- out_buffer_off = 0;
- return;
- }
-
- while (out_buffer_off != 0) {
- int sent = write(out_buffer, out_buffer_off);
-
- if (sent <= 0) {
- AltosDebug.debug("flush_output() failed");
- out_buffer_off = 0;
- break;
- }
-
- if (sent < out_buffer_off)
- System.arraycopy(out_buffer, 0, out_buffer, sent, out_buffer_off - sent);
-
- out_buffer_off -= sent;
- }
- }
-
- public void putchar(byte c) {
- out_buffer[out_buffer_off++] = c;
- if (out_buffer_off == buffer_size)
- flush_output();
- }
-
- public void print(String data) {
- byte[] bytes = data.getBytes();
-// AltosDebug.debug(data.replace('\n', '\\'));
- for (byte b : bytes)
- putchar(b);
- }
-
- public AltosDroidLink(Handler handler) {
- this.handler = handler;
- }
-}
+++ /dev/null
-/*
- * Copyright © 2015 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.
- */
-
-package org.altusmetrum.AltosDroid;
-
-import java.util.*;
-import java.io.*;
-import android.location.Location;
-import org.altusmetrum.altoslib_13.*;
-
-public interface AltosDroidMapInterface {
- public void onCreateView(AltosDroid altos_droid);
-
- public void onDestroyView();
-
- public void set_visible(boolean visible);
-
- public void center(double lat, double lon, double accuracy);
-
- public void show(TelemetryState telem_state, AltosState state, AltosGreatCircle from_receiver, Location receiver);
-}
+++ /dev/null
-/*
- * Copyright © 2016 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.
- */
-
-package org.altusmetrum.AltosDroid;
-
-public interface AltosDroidMapSourceListener {
- public void map_source_changed(int map_source);
-}
+++ /dev/null
-/*
- * Copyright © 2014 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.
- */
-package org.altusmetrum.AltosDroid;
-
-import java.io.*;
-import java.util.*;
-import java.text.*;
-
-import android.content.Context;
-import org.altusmetrum.altoslib_13.*;
-
-public class AltosDroidPreferences extends AltosPreferences {
-
- /* Active device preference name */
- final static String activeDeviceAddressPreference = "ACTIVE-DEVICE-ADDRESS";
- final static String activeDeviceNamePreference = "ACTIVE-DEVICE-NAME";
-
- static DeviceAddress active_device_address;
-
- /* Map source preference name */
- final static String mapSourcePreference = "MAP-SOURCE";
-
- static final int MAP_SOURCE_OFFLINE = 0;
- static final int MAP_SOURCE_ONLINE = 1;
-
- static int map_source;
-
- public static void init(Context context) {
- if (backend != null)
- return;
-
- AltosPreferences.init(new AltosDroidPreferencesBackend(context));
-
- String address = backend.getString(activeDeviceAddressPreference, null);
- String name = backend.getString(activeDeviceNamePreference, null);
-
- if (address != null && name != null)
- active_device_address = new DeviceAddress (address, name);
-
- map_source = backend.getInt(mapSourcePreference, MAP_SOURCE_ONLINE);
- }
-
- public static void set_active_device(DeviceAddress address) {
- synchronized(backend) {
- active_device_address = address;
- if (active_device_address != null) {
- backend.putString(activeDeviceAddressPreference, active_device_address.address);
- backend.putString(activeDeviceNamePreference, active_device_address.name);
- } else {
- backend.remove(activeDeviceAddressPreference);
- backend.remove(activeDeviceNamePreference);
- }
- flush_preferences();
- }
- }
-
- public static DeviceAddress active_device() {
- synchronized(backend) {
- return active_device_address;
- }
- }
-
- static LinkedList<AltosDroidMapSourceListener> map_source_listeners;
-
- public static void set_map_source(int map_source) {
- synchronized(backend) {
- AltosDroidPreferences.map_source = map_source;
- backend.putInt(mapSourcePreference, map_source);
- flush_preferences();
- }
- if (map_source_listeners != null) {
- for (AltosDroidMapSourceListener l : map_source_listeners) {
- l.map_source_changed(map_source);
- }
- }
- }
-
- public static int map_source() {
- synchronized(backend) {
- return map_source;
- }
- }
-
- public static void register_map_source_listener(AltosDroidMapSourceListener l) {
- synchronized(backend) {
- if (map_source_listeners == null)
- map_source_listeners = new LinkedList<AltosDroidMapSourceListener>();
- map_source_listeners.add(l);
- }
- }
-
- public static void unregister_map_source_listener(AltosDroidMapSourceListener l) {
- synchronized(backend) {
- map_source_listeners.remove(l);
- }
- }
-}
+++ /dev/null
-/*
- * 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; 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.
- */
-
-package org.altusmetrum.AltosDroid;
-
-import java.io.File;
-import java.util.Map;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.os.Environment;
-import android.util.*;
-
-import org.altusmetrum.altoslib_13.*;
-
-public class AltosDroidPreferencesBackend extends AltosPreferencesBackend {
- public final static String NAME = "org.altusmetrum.AltosDroid";
- private Context context = null;
- private SharedPreferences prefs = null;
- private SharedPreferences.Editor editor = null;
-
- public AltosDroidPreferencesBackend(Context in_context) {
- this(in_context, NAME);
- }
-
- public AltosDroidPreferencesBackend(Context in_context, String in_prefs) {
- context = in_context;
- prefs = context.getSharedPreferences(in_prefs, 0);
- editor = prefs.edit();
- }
-
- public String[] keys() {
- Map<String, ?> all = prefs.getAll();
- Object[] ao = all.keySet().toArray();
-
- String[] as = new String[ao.length];
- for (int i = 0; i < ao.length; i++)
- as[i] = (String) ao[i];
- return as;
- }
-
- public AltosPreferencesBackend node(String key) {
- if (!nodeExists(key))
- putBoolean(key, true);
- return new AltosDroidPreferencesBackend(context, key);
- }
-
- public boolean nodeExists(String key) {
- return prefs.contains(key);
- }
-
- public boolean getBoolean(String key, boolean def) {
- return prefs.getBoolean(key, def);
- }
-
- public double getDouble(String key, double def) {
- Float f = Float.valueOf(prefs.getFloat(key, (float)def));
- return f.doubleValue();
- }
-
- public int getInt(String key, int def) {
- return prefs.getInt(key, def);
- }
-
- public String getString(String key, String def) {
- String ret;
- ret = prefs.getString(key, def);
-// AltosDebug.debug("AltosDroidPreferencesBackend get string %s:\n", key);
-// if (ret == null)
-// AltosDebug.debug(" (null)\n");
-// else {
-// String[] lines = ret.split("\n");
-// for (String l : lines)
-// AltosDebug.debug(" %s\n", l);
-// }
- return ret;
- }
-
- public byte[] getBytes(String key, byte[] def) {
- String save = prefs.getString(key, null);
-
- if (save == null)
- return def;
-
- byte[] bytes = Base64.decode(save, Base64.DEFAULT);
- return bytes;
- }
-
- public void putBoolean(String key, boolean value) {
- editor.putBoolean(key, value);
- }
-
- public void putDouble(String key, double value) {
- editor.putFloat(key, (float)value);
- }
-
- public void putInt(String key, int value) {
- editor.putInt(key, value);
- }
-
- public void putString(String key, String value) {
-// AltosDebug.debug("AltosDroidPreferencesBackend put string %s:\n", key);
-// String[] lines = value.split("\n");
-// for (String l : lines)
-// AltosDebug.debug(" %s\n", l);
- editor.putString(key, value);
- }
-
- public void putBytes(String key, byte[] bytes) {
- String save = Base64.encodeToString(bytes, Base64.DEFAULT);
- editor.putString(key, save);
- }
-
- public void remove(String key) {
- AltosDebug.debug("remove preference %s\n", key);
- editor.remove(key);
- }
-
- public void flush() {
- editor.apply();
- }
-
- public File homeDirectory() {
- return Environment.getExternalStorageDirectory();
- }
-
- public void debug(String format, Object ... arguments) {
- AltosDebug.debug(format, arguments);
- }
-}
+++ /dev/null
-/*
- * Copyright © 2013 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; 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.
- */
-
-package org.altusmetrum.AltosDroid;
-
-import org.altusmetrum.altoslib_13.*;
-import android.location.Location;
-import android.app.Activity;
-import android.graphics.Color;
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentTransaction;
-import android.support.v4.app.FragmentManager;
-import android.location.Location;
-import android.widget.TextView;
-
-public abstract class AltosDroidTab extends Fragment implements AltosUnitsListener {
- TelemetryState last_telem_state;
- AltosState last_state;
- AltosGreatCircle last_from_receiver;
- Location last_receiver;
- AltosDroid altos_droid;
-
- public abstract void show(TelemetryState telem_state, AltosState state, AltosGreatCircle from_receiver, Location receiver);
-
- public abstract String tab_name();
-
- public void units_changed(boolean imperial_units) {
- if (!isHidden())
- show(last_telem_state, last_state, last_from_receiver, last_receiver);
- }
-
- public void set_value(TextView text_view,
- AltosUnits units,
- int width,
- double value) {
- if (value == AltosLib.MISSING)
- text_view.setText("");
- else
- text_view.setText(units.show(width, value));
- }
-
- public void set_visible(boolean visible) {
- FragmentTransaction ft = AltosDroid.fm.beginTransaction();
- AltosDebug.debug("set visible %b %s\n", visible, tab_name());
- if (visible) {
- ft.show(this);
- show(last_telem_state, last_state, last_from_receiver, last_receiver);
- } else
- ft.hide(this);
- try {
- ft.commitAllowingStateLoss();
- } catch (IllegalStateException ie) {
- }
- }
-
- @Override
- public void onAttach(Activity activity) {
- super.onAttach(activity);
- altos_droid = (AltosDroid) activity;
- altos_droid.registerTab(this);
- }
-
- @Override
- public void onDetach() {
- super.onDetach();
- altos_droid.unregisterTab(this);
- altos_droid = null;
- }
-
- @Override
- public void onResume() {
- super.onResume();
- AltosDebug.debug("onResume tab %s\n", tab_name());
- set_visible(true);
- }
-
- public void update_ui(TelemetryState telem_state, AltosState state,
- AltosGreatCircle from_receiver, Location receiver, boolean is_current)
- {
- last_telem_state = telem_state;
- last_state = state;
- last_from_receiver = from_receiver;
- last_receiver = receiver;
- if (is_current)
- show(telem_state, state, from_receiver, receiver);
- else
- return;
- }
-}
+++ /dev/null
-/*
- * Copyright © 2015 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.
- */
-
-package org.altusmetrum.AltosDroid;
-
-import java.util.*;
-import java.io.*;
-
-import org.altusmetrum.altoslib_13.*;
-
-import android.app.Activity;
-import android.graphics.*;
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentTransaction;
-import android.view.*;
-import android.widget.*;
-import android.location.Location;
-import android.content.*;
-import android.util.*;
-
-class Rocket implements Comparable {
- AltosLatLon position;
- String name;
- int serial;
- long last_packet;
- boolean active;
- AltosMapOffline map_offline;
-
- void paint() {
- map_offline.draw_bitmap(position, map_offline.rocket_bitmap, map_offline.rocket_off_x, map_offline.rocket_off_y);
- map_offline.draw_text(position, name, 0, 3*map_offline.rocket_bitmap.getHeight()/4);
- }
-
- void set_position(AltosLatLon position, long last_packet) {
- this.position = position;
- this.last_packet = last_packet;
- }
-
- void set_active(boolean active) {
- this.active = active;
- }
-
- public int compareTo(Object o) {
- Rocket other = (Rocket) o;
-
- if (active && !other.active)
- return 1;
- if (other.active && !active)
- return -1;
-
- long diff = last_packet - other.last_packet;
-
- if (diff > 0)
- return 1;
- if (diff < 0)
- return -1;
- return 0;
- }
-
- Rocket(int serial, AltosMapOffline map_offline) {
- this.serial = serial;
- this.name = String.format("%d", serial);
- this.map_offline = map_offline;
- }
-}
-
-public class AltosMapOffline extends View implements ScaleGestureDetector.OnScaleGestureListener, AltosMapInterface, AltosDroidMapInterface, AltosMapTypeListener {
- ScaleGestureDetector scale_detector;
- boolean scaling;
- AltosMap map;
- AltosDroid altos_droid;
-
- static int scale = 1;
-
- AltosLatLon here;
- AltosLatLon there;
- AltosLatLon pad;
-
- Canvas canvas;
- Paint paint;
-
- Bitmap pad_bitmap;
- int pad_off_x, pad_off_y;
- Bitmap rocket_bitmap;
- int rocket_off_x, rocket_off_y;
- Bitmap here_bitmap;
- int here_off_x, here_off_y;
-
- static final int WHITE = 0xffffffff;
- static final int RED = 0xffff0000;
- static final int PINK = 0xffff8080;
- static final int YELLOW= 0xffffff00;
- static final int CYAN = 0xff00ffff;
- static final int BLUE = 0xff0000ff;
- static final int BLACK = 0xff000000;
-
- public static final int stateColors[] = {
- WHITE, // startup
- WHITE, // idle
- WHITE, // pad
- RED, // boost
- PINK, // fast
- YELLOW, // coast
- CYAN, // drogue
- BLUE, // main
- BLACK, // landed
- BLACK, // invalid
- CYAN, // stateless
- };
-
- /* AltosMapInterface */
- public void debug(String format, Object ... arguments) {
- AltosDebug.debug(format, arguments);
- }
-
- class MapTile extends AltosMapTile {
- public void paint(AltosMapTransform t) {
- AltosPointInt pt = new AltosPointInt(t.screen(upper_left));
-
- if (canvas.quickReject(pt.x, pt.y, pt.x + px_size, pt.y + px_size, Canvas.EdgeType.AA))
- return;
-
- AltosImage altos_image = this.get_image();
-
- MapImage map_image = (MapImage) altos_image;
-
- Bitmap bitmap = null;
-
- if (map_image != null)
- bitmap = map_image.bitmap;
-
- if (bitmap != null) {
- canvas.drawBitmap(bitmap, pt.x, pt.y, paint);
- } else {
- paint.setColor(0xff808080);
- canvas.drawRect(pt.x, pt.y, pt.x + px_size, pt.y + px_size, paint);
- if (t.has_location()) {
- String message = null;
- switch (status) {
- case AltosMapTile.fetching:
- message = "Fetching...";
- break;
- case AltosMapTile.bad_request:
- message = "Internal error";
- break;
- case AltosMapTile.failed:
- message = "Network error";
- break;
- case AltosMapTile.forbidden:
- message = "Outside of known launch areas";
- break;
- }
- if (message != null) {
- Rect bounds = new Rect();
- paint.getTextBounds(message, 0, message.length(), bounds);
-
- int width = bounds.right - bounds.left;
- int height = bounds.bottom - bounds.top;
-
- float x = pt.x + px_size / 2.0f;
- float y = pt.y + px_size / 2.0f;
- x = x - width / 2.0f;
- y = y + height / 2.0f;
- paint.setColor(0xff000000);
- canvas.drawText(message, 0, message.length(), x, y, paint);
- }
- }
- }
- }
-
- public MapTile(AltosMapCache cache, AltosLatLon upper_left, AltosLatLon center, int zoom, int maptype, int px_size, int scale) {
- super(cache, upper_left, center, zoom, maptype, px_size, scale);
- }
-
- }
-
- public AltosMapTile new_tile(AltosMapCache cache, AltosLatLon upper_left, AltosLatLon center, int zoom, int maptype, int px_size, int scale) {
- return new MapTile(cache, upper_left, center, zoom, maptype, px_size, scale);
- }
-
- public AltosMapPath new_path() {
- return null;
- }
-
- public AltosMapLine new_line() {
- return null;
- }
-
- class MapImage implements AltosImage {
- public Bitmap bitmap;
-
- public void flush() {
- if (bitmap != null) {
- bitmap.recycle();
- bitmap = null;
- }
- }
-
- public MapImage(File file) {
- bitmap = BitmapFactory.decodeFile(file.getPath());
- }
- }
-
- public AltosImage load_image(File file) throws Exception {
- return new MapImage(file);
- }
-
- class MapMark extends AltosMapMark {
- public void paint(AltosMapTransform t) {
- }
-
- MapMark(double lat, double lon, int state) {
- super(lat, lon, state);
- }
- }
-
- public AltosMapMark new_mark(double lat, double lon, int state) {
- return new MapMark(lat, lon, state);
- }
-
- public int width() {
- return getWidth();
- }
-
- public int height() {
- return getHeight();
- }
-
- public void repaint() {
- postInvalidate();
- }
-
- public void repaint(AltosRectangle damage) {
- postInvalidate(damage.x, damage.y, damage.x + damage.width, damage.y + damage.height);
- }
-
- public void set_zoom_label(String label) {
- }
-
- public void select_object(AltosLatLon latlon) {
- if (map.transform == null)
- return;
- ArrayList<Integer> near = new ArrayList<Integer>();
-
- for (Rocket rocket : sorted_rockets()) {
- if (rocket.position == null) {
- debug("rocket %d has no position\n", rocket.serial);
- continue;
- }
- double distance = map.transform.hypot(latlon, rocket.position);
- debug("check select %d distance %g width %d\n", rocket.serial, distance, rocket_bitmap.getWidth());
- if (distance < rocket_bitmap.getWidth() * 2.0) {
- debug("selecting %d\n", rocket.serial);
- near.add(rocket.serial);
- }
- }
- if (near.size() != 0)
- altos_droid.touch_trackers(near.toArray(new Integer[0]));
- }
-
- class Line {
- AltosLatLon a, b;
-
- void paint() {
- if (a != null && b != null) {
- AltosPointDouble a_screen = map.transform.screen(a);
- AltosPointDouble b_screen = map.transform.screen(b);
- paint.setColor(0xff8080ff);
- canvas.drawLine((float) a_screen.x, (float) a_screen.y,
- (float) b_screen.x, (float) b_screen.y,
- paint);
- }
- }
-
- void set_a(AltosLatLon a) {
- this.a = a;
- }
-
- void set_b(AltosLatLon b) {
- this.b = b;
- }
-
- Line() {
- }
- }
-
- Line line = new Line();
-
- int stroke_width = 20;
-
- void draw_text(AltosLatLon lat_lon, String text, int off_x, int off_y) {
- if (lat_lon != null && map != null && map.transform != null) {
- AltosPointInt pt = new AltosPointInt(map.transform.screen(lat_lon));
-
- Rect bounds = new Rect();
- paint.getTextBounds(text, 0, text.length(), bounds);
-
- int width = bounds.right - bounds.left;
- int height = bounds.bottom - bounds.top;
-
- float x = pt.x;
- float y = pt.y;
- x = x - width / 2.0f - off_x;
- y = y + height / 2.0f - off_y;
- paint.setColor(0xff000000);
- canvas.drawText(text, 0, text.length(), x, y, paint);
- }
- }
-
- HashMap<Integer,Rocket> rockets = new HashMap<Integer,Rocket>();
-
- void draw_bitmap(AltosLatLon lat_lon, Bitmap bitmap, int off_x, int off_y) {
- if (lat_lon != null && map != null && map.transform != null) {
- AltosPointInt pt = new AltosPointInt(map.transform.screen(lat_lon));
-
- canvas.drawBitmap(bitmap, pt.x - off_x, pt.y - off_y, paint);
- }
- }
-
- private Rocket[] sorted_rockets() {
- Rocket[] rocket_array = rockets.values().toArray(new Rocket[0]);
-
- Arrays.sort(rocket_array);
- return rocket_array;
- }
-
- private void draw_positions() {
- line.set_a(there);
- line.set_b(here);
- line.paint();
- draw_bitmap(pad, pad_bitmap, pad_off_x, pad_off_y);
-
- for (Rocket rocket : sorted_rockets())
- rocket.paint();
- draw_bitmap(here, here_bitmap, here_off_x, here_off_y);
- }
-
- @Override public void invalidate() {
- Rect r = new Rect();
- getDrawingRect(r);
- super.invalidate();
- }
-
- @Override public void invalidate(int l, int t, int r, int b) {
- Rect rect = new Rect();
- getDrawingRect(rect);
- super.invalidate();
- }
-
- @Override
- protected void onDraw(Canvas view_canvas) {
- if (map == null) {
- debug("MapView draw without map\n");
- return;
- }
- canvas = view_canvas;
- paint = new Paint(Paint.ANTI_ALIAS_FLAG);
- paint.setStrokeWidth(stroke_width);
- paint.setStrokeCap(Paint.Cap.ROUND);
- paint.setStrokeJoin(Paint.Join.ROUND);
- paint.setTextSize(40);
- map.paint();
- draw_positions();
- canvas = null;
- }
-
- public boolean onScale(ScaleGestureDetector detector) {
- float f = detector.getScaleFactor();
-
- if (f <= 0.8) {
- map.set_zoom_centre(map.get_zoom() - 1, new AltosPointInt((int) detector.getFocusX(), (int) detector.getFocusY()));
- return true;
- }
- if (f >= 1.2) {
- map.set_zoom_centre(map.get_zoom() + 1, new AltosPointInt((int) detector.getFocusX(), (int) detector.getFocusY()));
- return true;
- }
- return false;
- }
-
- public boolean onScaleBegin(ScaleGestureDetector detector) {
- return true;
- }
-
- public void onScaleEnd(ScaleGestureDetector detector) {
- }
-
- @Override
- public boolean dispatchTouchEvent(MotionEvent event) {
- scale_detector.onTouchEvent(event);
-
- if (scale_detector.isInProgress()) {
- scaling = true;
- }
-
- if (scaling) {
- if (event.getAction() == MotionEvent.ACTION_UP) {
- scaling = false;
- }
- return true;
- }
-
- if (event.getAction() == MotionEvent.ACTION_DOWN) {
- map.touch_start((int) event.getX(), (int) event.getY(), true);
- } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
- map.touch_continue((int) event.getX(), (int) event.getY(), true);
- } else if (event.getAction() == MotionEvent.ACTION_UP) {
- map.touch_stop((int) event.getX(), (int) event.getY(), true);
- }
- return true;
- }
-
- double mapAccuracy;
-
- public void center(double lat, double lon, double accuracy) {
- if (mapAccuracy <= 0 || accuracy < mapAccuracy/10 || (map != null && !map.has_centre())) {
- if (map != null)
- map.maybe_centre(lat, lon);
- mapAccuracy = accuracy;
- }
- }
-
- public void set_visible(boolean visible) {
- if (visible)
- setVisibility(VISIBLE);
- else
- setVisibility(GONE);
- }
-
- public void show(TelemetryState telem_state, AltosState state, AltosGreatCircle from_receiver, Location receiver) {
- boolean changed = false;
-
- if (state != null) {
- map.show(state, null);
- if (state.pad_lat != AltosLib.MISSING && pad == null)
- pad = new AltosLatLon(state.pad_lat, state.pad_lon);
- }
-
- if (telem_state != null) {
- Integer[] old_serial = rockets.keySet().toArray(new Integer[0]);
- Integer[] new_serial = telem_state.states.keySet().toArray(new Integer[0]);
-
- /* remove deleted keys */
- for (int serial : old_serial) {
- if (!telem_state.states.containsKey(serial))
- rockets.remove(serial);
- }
-
- /* set remaining keys */
-
- for (int serial : new_serial) {
- Rocket rocket;
- AltosState t_state = telem_state.states.get(serial);
- if (rockets.containsKey(serial))
- rocket = rockets.get(serial);
- else {
- rocket = new Rocket(serial, this);
- rockets.put(serial, rocket);
- }
- if (t_state.gps != null) {
- AltosLatLon latlon = new AltosLatLon(t_state.gps.lat, t_state.gps.lon);
- rocket.set_position(latlon, t_state.received_time);
- if (state.cal_data().serial == serial)
- there = latlon;
- }
- if (state != null)
- rocket.set_active(state.cal_data().serial == serial);
- }
- }
- if (receiver != null) {
- AltosLatLon new_here = new AltosLatLon(receiver.getLatitude(), receiver.getLongitude());
- if (!new_here.equals(here)) {
- here = new_here;
- AltosDebug.debug("Location changed, redraw");
- repaint();
- }
- }
- }
-
- public void onCreateView(AltosDroid altos_droid) {
- this.altos_droid = altos_droid;
- map = new AltosMap(this, scale);
- AltosPreferences.register_map_type_listener(this);
- map.set_maptype(AltosPreferences.map_type());
-
- pad_bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.pad);
- /* arrow at the bottom of the launchpad image */
- pad_off_x = pad_bitmap.getWidth() / 2;
- pad_off_y = pad_bitmap.getHeight();
-
- rocket_bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.rocket);
- /* arrow at the bottom of the rocket image */
- rocket_off_x = rocket_bitmap.getWidth() / 2;
- rocket_off_y = rocket_bitmap.getHeight();
-
- here_bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_maps_indicator_current_position);
- /* Center of the dot */
- here_off_x = here_bitmap.getWidth() / 2;
- here_off_y = here_bitmap.getHeight() / 2;
- }
-
- public void onDestroyView() {
- AltosPreferences.unregister_map_type_listener(this);
- }
-
- public void map_type_changed(int map_type) {
- if (map != null)
- map.set_maptype(map_type);
- }
-
- public AltosMapOffline(Context context, AttributeSet attrs) {
- super(context, attrs);
- this.altos_droid = altos_droid;
- scale_detector = new ScaleGestureDetector(context, this);
- }
-}
+++ /dev/null
-/*
- * Copyright © 2013 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; 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.
- */
-
-package org.altusmetrum.AltosDroid;
-
-import java.util.*;
-
-import org.altusmetrum.altoslib_13.*;
-
-import com.google.android.gms.maps.*;
-import com.google.android.gms.maps.model.*;
-
-import android.app.Activity;
-import android.graphics.Color;
-import android.graphics.*;
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-//import android.support.v4.app.FragmentTransaction;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.TextView;
-import android.location.Location;
-import android.content.*;
-
-class RocketOnline implements Comparable {
- Marker marker;
- int serial;
- long last_packet;
- int size;
-
- void set_position(AltosLatLon position, long last_packet) {
- marker.setPosition(new LatLng(position.lat, position.lon));
- this.last_packet = last_packet;
- }
-
- private Bitmap rocket_bitmap(Context context, String text) {
-
- /* From: http://mapicons.nicolasmollet.com/markers/industry/military/missile-2/
- */
- Bitmap orig_bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.rocket);
- Bitmap bitmap = orig_bitmap.copy(Bitmap.Config.ARGB_8888, true);
-
- Canvas canvas = new Canvas(bitmap);
- Paint paint = new Paint();
- paint.setTextSize(40);
- paint.setColor(0xff000000);
-
- Rect bounds = new Rect();
- paint.getTextBounds(text, 0, text.length(), bounds);
-
- int width = bounds.right - bounds.left;
- int height = bounds.bottom - bounds.top;
-
- float x = bitmap.getWidth() / 2.0f - width / 2.0f;
- float y = bitmap.getHeight() / 2.0f - height / 2.0f;
-
- size = bitmap.getWidth();
-
- canvas.drawText(text, 0, text.length(), x, y, paint);
- return bitmap;
- }
-
- public void remove() {
- marker.remove();
- }
-
- public int compareTo(Object o) {
- RocketOnline other = (RocketOnline) o;
-
- long diff = last_packet - other.last_packet;
-
- if (diff > 0)
- return 1;
- if (diff < 0)
- return -1;
- return 0;
- }
-
- RocketOnline(Context context, int serial, GoogleMap map, double lat, double lon, long last_packet) {
- this.serial = serial;
- String name = String.format("%d", serial);
- this.marker = map.addMarker(new MarkerOptions()
- .icon(BitmapDescriptorFactory.fromBitmap(rocket_bitmap(context, name)))
- .position(new LatLng(lat, lon))
- .visible(true));
- this.last_packet = last_packet;
- }
-}
-
-public class AltosMapOnline implements AltosDroidMapInterface, GoogleMap.OnMarkerClickListener, GoogleMap.OnMapClickListener, AltosMapTypeListener {
- public SupportMapFragment mMapFragment;
- private GoogleMap mMap;
- private boolean mapLoaded = false;
- Context context;
-
- private HashMap<Integer,RocketOnline> rockets = new HashMap<Integer,RocketOnline>();
- private Marker mPadMarker;
- private boolean pad_set;
- private Polyline mPolyline;
-
- private View map_view;
-
- private double mapAccuracy = -1;
-
- private AltosLatLon my_position = null;
- private AltosLatLon target_position = null;
-
- private AltosDroid altos_droid;
-
- public void onCreateView(AltosDroid altos_droid) {
- this.altos_droid = altos_droid;
- final int map_type = AltosPreferences.map_type();
- AltosPreferences.register_map_type_listener(this);
- mMapFragment = new SupportMapFragment() {
- @Override
- public void onActivityCreated(Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
- setupMap(map_type);
- }
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- map_view = super.onCreateView(inflater, container, savedInstanceState);
- return map_view;
- }
- @Override
- public void onDestroyView() {
- super.onDestroyView();
- map_view = null;
- }
- };
- }
-
- public void onDestroyView() {
- AltosPreferences.unregister_map_type_listener(this);
- }
-
- private double pixel_distance(LatLng a, LatLng b) {
- Projection projection = mMap.getProjection();
-
- Point a_pt = projection.toScreenLocation(a);
- Point b_pt = projection.toScreenLocation(b);
-
- return Math.hypot((double) (a_pt.x - b_pt.x), (double) (a_pt.y - b_pt.y));
- }
-
- private RocketOnline[] sorted_rockets() {
- RocketOnline[] rocket_array = rockets.values().toArray(new RocketOnline[0]);
-
- Arrays.sort(rocket_array);
- return rocket_array;
- }
-
- public void onMapClick(LatLng lat_lng) {
- ArrayList<Integer> near = new ArrayList<Integer>();
-
- for (RocketOnline rocket : sorted_rockets()) {
- LatLng pos = rocket.marker.getPosition();
-
- if (pos == null)
- continue;
-
- double distance = pixel_distance(lat_lng, pos);
- if (distance < rocket.size * 2)
- near.add(rocket.serial);
- }
-
- if (near.size() != 0)
- altos_droid.touch_trackers(near.toArray(new Integer[0]));
- }
-
- public boolean onMarkerClick(Marker marker) {
- onMapClick(marker.getPosition());
- return true;
- }
-
- public void setupMap(int map_type) {
- mMap = mMapFragment.getMap();
- if (mMap != null) {
- map_type_changed(map_type);
- mMap.setMyLocationEnabled(true);
- mMap.getUiSettings().setTiltGesturesEnabled(false);
- mMap.getUiSettings().setZoomControlsEnabled(false);
- mMap.setOnMarkerClickListener(this);
- mMap.setOnMapClickListener(this);
-
- mPadMarker = mMap.addMarker(
- new MarkerOptions().icon(BitmapDescriptorFactory.fromResource(R.drawable.pad))
- .position(new LatLng(0,0))
- .visible(false)
- );
-
- mPolyline = mMap.addPolyline(
- new PolylineOptions().add(new LatLng(0,0), new LatLng(0,0))
- .width(20)
- .color(Color.BLUE)
- .visible(false)
- );
-
- mapLoaded = true;
- }
- }
-
- public void center(double lat, double lon, double accuracy) {
- if (mMap == null)
- return;
-
- if (mapAccuracy < 0 || accuracy < mapAccuracy/10) {
- mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(lat, lon),14));
- mapAccuracy = accuracy;
- }
- }
-
- private void set_rocket(int serial, AltosState state) {
- RocketOnline rocket;
-
- if (state.gps == null || state.gps.lat == AltosLib.MISSING)
- return;
-
- if (mMap == null)
- return;
-
- if (rockets.containsKey(serial)) {
- rocket = rockets.get(serial);
- rocket.set_position(new AltosLatLon(state.gps.lat, state.gps.lon), state.received_time);
- } else {
- rocket = new RocketOnline(context,
- serial,
- mMap, state.gps.lat, state.gps.lon,
- state.received_time);
- rockets.put(serial, rocket);
- }
- }
-
- private void remove_rocket(int serial) {
- RocketOnline rocket = rockets.get(serial);
- rocket.remove();
- rockets.remove(serial);
- }
-
- public void set_visible(boolean visible) {
- if (map_view == null)
- return;
- if (visible)
- map_view.setVisibility(View.VISIBLE);
- else
- map_view.setVisibility(View.GONE);
- }
-
- public void show(TelemetryState telem_state, AltosState state, AltosGreatCircle from_receiver, Location receiver) {
-
- if (telem_state != null) {
- for (int serial : rockets.keySet()) {
- if (!telem_state.states.containsKey(serial))
- remove_rocket(serial);
- }
-
- for (int serial : telem_state.states.keySet()) {
- set_rocket(serial, telem_state.states.get(serial));
- }
- }
-
- if (state != null) {
- if (mapLoaded) {
- if (!pad_set && state.pad_lat != AltosLib.MISSING) {
- pad_set = true;
- mPadMarker.setPosition(new LatLng(state.pad_lat, state.pad_lon));
- mPadMarker.setVisible(true);
- }
- }
- if (state.gps != null && state.gps.lat != AltosLib.MISSING) {
-
- target_position = new AltosLatLon(state.gps.lat, state.gps.lon);
- if (state.gps.locked && state.gps.nsat >= 4)
- center (state.gps.lat, state.gps.lon, 10);
- }
- }
-
- if (receiver != null) {
- double accuracy;
-
- if (receiver.hasAccuracy())
- accuracy = receiver.getAccuracy();
- else
- accuracy = 1000;
-
- my_position = new AltosLatLon(receiver.getLatitude(), receiver.getLongitude());
- center (my_position.lat, my_position.lon, accuracy);
- }
-
- if (my_position != null && target_position != null && mPolyline != null) {
- mPolyline.setPoints(Arrays.asList(new LatLng(my_position.lat, my_position.lon), new LatLng(target_position.lat, target_position.lon)));
- mPolyline.setVisible(true);
- }
-
- }
-
- public void map_type_changed(int map_type) {
- if (mMap != null) {
- if (map_type == AltosMap.maptype_hybrid)
- mMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
- else if (map_type == AltosMap.maptype_satellite)
- mMap.setMapType(GoogleMap.MAP_TYPE_SATELLITE);
- else if (map_type == AltosMap.maptype_terrain)
- mMap.setMapType(GoogleMap.MAP_TYPE_TERRAIN);
- else
- mMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
- }
- }
-
- public AltosMapOnline(Context context) {
- this.context = context;
- }
-}
+++ /dev/null
-/*
- * Copyright © 2015 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.
- */
-
-package org.altusmetrum.AltosDroid;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.UUID;
-import java.util.HashMap;
-
-import android.content.Context;
-import android.hardware.usb.*;
-import android.app.*;
-import android.os.Handler;
-
-import org.altusmetrum.altoslib_13.*;
-
-public class AltosUsb extends AltosDroidLink {
-
- private Thread input_thread = null;
-
- private Handler handler;
-
- private UsbManager manager;
- private UsbDevice device;
- private UsbDeviceConnection connection;
- private UsbInterface iface;
- private UsbEndpoint in, out;
-
- private InputStream input;
- private OutputStream output;
-
- // Constructor
- public AltosUsb(Context context, UsbDevice device, Handler handler) {
- super(handler);
-// set_debug(D);
- this.handler = handler;
-
- iface = null;
- in = null;
- out = null;
-
- int niface = device.getInterfaceCount();
-
- for (int i = 0; i < niface; i++) {
-
- iface = device.getInterface(i);
-
- in = null;
- out = null;
-
- int nendpoints = iface.getEndpointCount();
-
- for (int e = 0; e < nendpoints; e++) {
- UsbEndpoint endpoint = iface.getEndpoint(e);
-
- if (endpoint.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
- switch (endpoint.getDirection()) {
- case UsbConstants.USB_DIR_OUT:
- out = endpoint;
- break;
- case UsbConstants.USB_DIR_IN:
- in = endpoint;
- break;
- }
- }
- }
-
- if (in != null && out != null)
- break;
- }
-
- if (in != null && out != null) {
- AltosDebug.debug("\tin %s out %s\n", in.toString(), out.toString());
-
- manager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
-
- if (manager == null) {
- AltosDebug.debug("USB_SERVICE failed");
- return;
- }
-
- connection = manager.openDevice(device);
-
- if (connection == null) {
- AltosDebug.debug("openDevice failed");
- return;
- }
-
- connection.claimInterface(iface, true);
-
- input_thread = new Thread(this);
- input_thread.start();
-
- // Configure the newly connected device for telemetry
- print("~\nE 0\n");
- set_monitor(false);
- }
- }
-
- static private boolean isAltusMetrum(UsbDevice device) {
- if (device.getVendorId() != AltosLib.vendor_altusmetrum)
- return false;
- if (device.getProductId() < AltosLib.product_altusmetrum_min)
- return false;
- if (device.getProductId() > AltosLib.product_altusmetrum_max)
- return false;
- return true;
- }
-
- static boolean matchProduct(int want_product, UsbDevice device) {
-
- if (!isAltusMetrum(device))
- return false;
-
- if (want_product == AltosLib.product_any)
- return true;
-
- int have_product = device.getProductId();
-
- if (want_product == AltosLib.product_basestation)
- return have_product == AltosLib.product_teledongle ||
- have_product == AltosLib.product_teleterra ||
- have_product == AltosLib.product_telebt ||
- have_product == AltosLib.product_megadongle;
-
- if (want_product == AltosLib.product_altimeter)
- return have_product == AltosLib.product_telemetrum ||
- have_product == AltosLib.product_telemega ||
- have_product == AltosLib.product_easymega ||
- have_product == AltosLib.product_telegps ||
- have_product == AltosLib.product_easymini ||
- have_product == AltosLib.product_telemini;
-
- if (have_product == AltosLib.product_altusmetrum) /* old devices match any request */
- return true;
-
- if (want_product == have_product)
- return true;
-
- return false;
- }
-
- static public boolean request_permission(Context context, UsbDevice device, PendingIntent pi) {
- UsbManager manager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
-
-// if (manager.hasPermission(device))
-// return true;
-
- AltosDebug.debug("request permission for USB device " + device.toString());
-
- manager.requestPermission(device, pi);
- return false;
- }
-
- static public UsbDevice find_device(Context context, int match_product) {
- UsbManager manager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
-
- HashMap<String,UsbDevice> devices = manager.getDeviceList();
-
- for (UsbDevice device : devices.values()) {
- int vendor = device.getVendorId();
- int product = device.getProductId();
-
- if (matchProduct(match_product, device)) {
- AltosDebug.debug("found USB device " + device.toString());
- return device;
- }
- }
-
- return null;
- }
-
- private void disconnected() {
- if (closed()) {
- AltosDebug.debug("disconnected after closed");
- return;
- }
-
- AltosDebug.debug("Sending disconnected message");
- handler.obtainMessage(TelemetryService.MSG_DISCONNECTED, this).sendToTarget();
- }
-
- void close_device() {
- UsbDeviceConnection tmp_connection;
-
- synchronized(this) {
- tmp_connection = connection;
- connection = null;
- }
-
- if (tmp_connection != null) {
- AltosDebug.debug("Closing USB device");
- tmp_connection.close();
- }
- }
-
- int read(byte[] buffer, int len) {
- int ret = connection.bulkTransfer(in, buffer, len, -1);
- AltosDebug.debug("read(%d) = %d\n", len, ret);
- return ret;
- }
-
- int write(byte[] buffer, int len) {
- int ret = connection.bulkTransfer(out, buffer, len, -1);
- AltosDebug.debug("write(%d) = %d\n", len, ret);
- return ret;
- }
-
- // Stubs of required methods when extending AltosLink
- public boolean can_cancel_reply() { return false; }
- public boolean show_reply_timeout() { return true; }
- public void hide_reply_timeout() { }
-
-}
+++ /dev/null
-/*
- * Copyright © 2013 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; 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.
- */
-
-package org.altusmetrum.AltosDroid;
-
-import android.content.Context;
-import android.support.v4.view.ViewPager;
-import android.util.AttributeSet;
-import android.view.View;
-
-public class AltosViewPager extends ViewPager {
-
- public AltosViewPager(Context context) {
- super(context);
- }
-
- public AltosViewPager(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- @Override
- protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
-
- if (v.getClass() != null &&
- v.getClass().getName() != null &&
- v.getClass().getName().endsWith("MapOffline"))
- return true;
-
- if(v.getClass() != null &&
- v.getClass().getPackage() != null &&
- v.getClass().getPackage().getName() != null &&
- v.getClass().getPackage().getName().startsWith("maps."))
- return true;
-
- return super.canScroll(v, checkV, dx, x, y);
- }
-
-}
+++ /dev/null
-/*
- * 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; 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.
- */
-
-package org.altusmetrum.AltosDroid;
-
-import android.speech.tts.TextToSpeech;
-import android.speech.tts.TextToSpeech.OnInitListener;
-import android.location.Location;
-
-import org.altusmetrum.altoslib_13.*;
-
-public class AltosVoice {
-
- private TextToSpeech tts = null;
- private boolean tts_enabled = false;
-
- static final int TELL_MODE_NONE = 0;
- static final int TELL_MODE_PAD = 1;
- static final int TELL_MODE_FLIGHT = 2;
- static final int TELL_MODE_RECOVER = 3;
-
- static final int TELL_FLIGHT_NONE = 0;
- static final int TELL_FLIGHT_STATE = 1;
- static final int TELL_FLIGHT_SPEED = 2;
- static final int TELL_FLIGHT_HEIGHT = 3;
- static final int TELL_FLIGHT_TRACK = 4;
-
- private int last_tell_mode;
- private int last_tell_serial = AltosLib.MISSING;
- private int last_state;
- private AltosGPS last_gps;
- private double last_height = AltosLib.MISSING;
- private Location last_receiver;
- private long last_speak_time;
- private int last_flight_tell = TELL_FLIGHT_NONE;
- private boolean quiet = false;
-
- private long now() {
- return System.currentTimeMillis();
- }
-
- private void reset_last() {
- last_tell_mode = TELL_MODE_NONE;
- last_speak_time = now() - 100 * 1000;
- last_gps = null;
- last_height = AltosLib.MISSING;
- last_receiver = null;
- last_state = AltosLib.ao_flight_invalid;
- last_flight_tell = TELL_FLIGHT_NONE;
- }
-
- public AltosVoice(AltosDroid a) {
- tts = new TextToSpeech(a, new OnInitListener() {
- public void onInit(int status) {
- if (status == TextToSpeech.SUCCESS) tts_enabled = true;
- }
- });
- reset_last();
- }
-
- public synchronized void set_enable(boolean enable) {
- tts_enabled = enable;
- }
-
- public synchronized void speak(String s) {
- if (!tts_enabled) return;
- last_speak_time = now();
- if (!quiet)
- tts.speak(s, TextToSpeech.QUEUE_ADD, null);
- }
-
- public synchronized long time_since_speak() {
- return now() - last_speak_time;
- }
-
- public synchronized void speak(String format, Object ... arguments) {
- speak(String.format(format, arguments));
- }
-
- public synchronized boolean is_speaking() {
- return tts.isSpeaking();
- }
-
- public void stop() {
- if (tts != null) {
- tts.stop();
- tts.shutdown();
- }
- }
-
- private boolean last_apogee_good;
- private boolean last_main_good;
- private boolean last_gps_good;
-
- private boolean tell_gonogo(String name,
- boolean current,
- boolean previous,
- boolean new_mode) {
- if (current != previous || new_mode)
- speak("%s %s.", name, current ? "ready" : "not ready");
- return current;
- }
-
- private boolean tell_pad(TelemetryState telem_state, AltosState state,
- AltosGreatCircle from_receiver, Location receiver) {
-
- if (state == null)
- return false;
-
- AltosDebug.debug("tell_pad lag %b ltm %d\n", last_apogee_good, last_tell_mode);
-
- if (state.apogee_voltage != AltosLib.MISSING)
- last_apogee_good = tell_gonogo("apogee",
- state.apogee_voltage >= AltosLib.ao_igniter_good,
- last_apogee_good,
- last_tell_mode != TELL_MODE_PAD);
-
- if (state.main_voltage != AltosLib.MISSING)
- last_main_good = tell_gonogo("main",
- state.main_voltage >= AltosLib.ao_igniter_good,
- last_main_good,
- last_tell_mode != TELL_MODE_PAD);
-
- if (state.gps != null)
- last_gps_good = tell_gonogo("G P S",
- state.gps_ready,
- last_gps_good,
- last_tell_mode != TELL_MODE_PAD);
- return true;
- }
-
-
- private boolean descending(int state) {
- return AltosLib.ao_flight_drogue <= state && state <= AltosLib.ao_flight_landed;
- }
-
- private boolean target_moved(AltosState state) {
- if (last_gps != null && state != null && state.gps != null) {
- AltosGreatCircle moved = new AltosGreatCircle(last_gps.lat, last_gps.lon, last_gps.alt,
- state.gps.lat, state.gps.lon, state.gps.alt);
- double height_change = 0;
- double height = state.height();
-
- if (height != AltosLib.MISSING && last_height != AltosLib.MISSING)
- height_change = Math.abs(last_height - height);
-
- if (moved.range < 10 && height_change < 10)
- return false;
- }
- return true;
- }
-
- private boolean receiver_moved(Location receiver) {
- if (last_receiver != null && receiver != null) {
- AltosGreatCircle moved = new AltosGreatCircle(last_receiver.getLatitude(),
- last_receiver.getLongitude(),
- last_receiver.getAltitude(),
- receiver.getLatitude(),
- receiver.getLongitude(),
- receiver.getAltitude());
- if (moved.range < 10)
- return false;
- }
- return true;
- }
-
- private boolean tell_flight(TelemetryState telem_state, AltosState state,
- AltosGreatCircle from_receiver, Location receiver) {
-
- boolean spoken = false;
-
- if (state == null)
- return false;
-
- if (last_tell_mode != TELL_MODE_FLIGHT)
- last_flight_tell = TELL_FLIGHT_NONE;
-
- if (state.state() != last_state && AltosLib.ao_flight_boost <= state.state() && state.state() <= AltosLib.ao_flight_landed) {
- speak(state.state_name());
- if (descending(state.state()) && !descending(last_state)) {
- if (state.max_height() != AltosLib.MISSING) {
- speak("max height: %s.",
- AltosConvert.height.say_units(state.max_height()));
- }
- }
- last_flight_tell = TELL_FLIGHT_STATE;
- return true;
- }
-
- if (last_tell_mode == TELL_MODE_FLIGHT && last_flight_tell == TELL_FLIGHT_TRACK) {
- if (time_since_speak() < 10 * 1000)
- return false;
- if (!target_moved(state) && !receiver_moved(receiver))
- return false;
- }
-
- double speed;
- double height;
-
- if (last_flight_tell == TELL_FLIGHT_NONE || last_flight_tell == TELL_FLIGHT_STATE || last_flight_tell == TELL_FLIGHT_TRACK) {
- last_flight_tell = TELL_FLIGHT_SPEED;
-
- if (state.state() <= AltosLib.ao_flight_coast) {
- speed = state.speed();
- } else {
- speed = state.gps_speed();
- if (speed == AltosLib.MISSING)
- speed = state.speed();
- }
-
- if (speed != AltosLib.MISSING) {
- speak("speed: %s.", AltosConvert.speed.say_units(speed));
- return true;
- }
- }
-
- if (last_flight_tell == TELL_FLIGHT_SPEED) {
- last_flight_tell = TELL_FLIGHT_HEIGHT;
- height = state.height();
-
- if (height != AltosLib.MISSING) {
- speak("height: %s.", AltosConvert.height.say_units(height));
- return true;
- }
- }
-
- if (last_flight_tell == TELL_FLIGHT_HEIGHT) {
- last_flight_tell = TELL_FLIGHT_TRACK;
- if (from_receiver != null) {
- speak("bearing %s %d, elevation %d, distance %s.",
- from_receiver.bearing_words(
- AltosGreatCircle.BEARING_VOICE),
- (int) (from_receiver.bearing + 0.5),
- (int) (from_receiver.elevation + 0.5),
- AltosConvert.distance.say(from_receiver.distance));
- return true;
- }
- }
-
- return spoken;
- }
-
- private boolean tell_recover(TelemetryState telem_state, AltosState state,
- AltosGreatCircle from_receiver, Location receiver) {
-
- if (from_receiver == null)
- return false;
-
- if (last_tell_mode == TELL_MODE_RECOVER) {
- if (!target_moved(state) && !receiver_moved(receiver))
- return false;
- if (time_since_speak() <= 10 * 1000)
- return false;
- }
-
- String direction = AltosDroid.direction(from_receiver, receiver);
- if (direction == null)
- direction = String.format("Bearing %d", (int) (from_receiver.bearing + 0.5));
-
- speak("%s, distance %s.", direction,
- AltosConvert.distance.say_units(from_receiver.distance));
-
- return true;
- }
-
- public void tell(TelemetryState telem_state, AltosState state,
- AltosGreatCircle from_receiver, Location receiver,
- AltosDroidTab tab, boolean quiet) {
-
- this.quiet = quiet;
-
- boolean spoken = false;
-
- if (!tts_enabled) return;
-
- if (is_speaking()) return;
-
- int tell_serial = last_tell_serial;
-
- if (state != null)
- tell_serial = state.cal_data().serial;
-
- if (tell_serial != last_tell_serial)
- reset_last();
-
- int tell_mode = TELL_MODE_NONE;
-
- if (tab.tab_name().equals(AltosDroid.tab_pad_name))
- tell_mode = TELL_MODE_PAD;
- else if (tab.tab_name().equals(AltosDroid.tab_flight_name))
- tell_mode = TELL_MODE_FLIGHT;
- else
- tell_mode = TELL_MODE_RECOVER;
-
- if (tell_mode == TELL_MODE_PAD)
- spoken = tell_pad(telem_state, state, from_receiver, receiver);
- else if (tell_mode == TELL_MODE_FLIGHT)
- spoken = tell_flight(telem_state, state, from_receiver, receiver);
- else
- spoken = tell_recover(telem_state, state, from_receiver, receiver);
-
- if (spoken) {
- last_tell_mode = tell_mode;
- last_tell_serial = tell_serial;
- if (state != null) {
- last_state = state.state();
- last_height = state.height();
- if (state.gps != null)
- last_gps = state.gps;
- }
- if (receiver != null)
- last_receiver = receiver;
- }
- }
-}
+++ /dev/null
-/*
- * 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; 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.
- */
-
-package org.altusmetrum.AltosDroid;
-
-public class BuildInfo {
- public static final String version = "@VERSION@";
- public static final String git_describe = "@DESCRIBE@";
- public static final String branch = "@BRANCH@";
- public static final String commitnum = "@COMMITNUM@";
- public static final String commithash = "@COMMITHASH@";
- public static final String builddate = "@BUILDDATE@";
- public static final String buildtime = "@BUILDTIME@";
- public static final String buildtz = "@BUILDTZ@";
-}
-
+++ /dev/null
-/*
- * Copyright © 2015 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.
- */
-
-package org.altusmetrum.AltosDroid;
-
-public class DeviceAddress {
- public String address;
- public String name;
-
- public DeviceAddress(String address, String name) {
- this.address = address;
- this.name = name;
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.altusmetrum.AltosDroid;
-
-import java.util.Set;
-import org.altusmetrum.AltosDroid.R;
-
-import android.app.Activity;
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Bundle;
-import android.view.View;
-import android.view.Window;
-import android.view.View.OnClickListener;
-import android.widget.AdapterView;
-import android.widget.ArrayAdapter;
-import android.widget.Button;
-import android.widget.ListView;
-import android.widget.TextView;
-import android.widget.AdapterView.OnItemClickListener;
-
-/**
- * This Activity appears as a dialog. It lists any paired devices and
- * devices detected in the area after discovery. When a device is chosen
- * by the user, the MAC address of the device is sent back to the parent
- * Activity in the result Intent.
- */
-public class DeviceListActivity extends Activity {
-
- // Return Intent extra
- public static final String EXTRA_DEVICE_ADDRESS = "device_address";
- public static final String EXTRA_DEVICE_NAME = "device_name";
-
- // Member fields
- private BluetoothAdapter mBtAdapter;
- private ArrayAdapter<String> mPairedDevicesArrayAdapter;
- private ArrayAdapter<String> mNewDevicesArrayAdapter;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- // Setup the window
- requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
- setContentView(R.layout.device_list);
-
- // Set result CANCELED incase the user backs out
- setResult(Activity.RESULT_CANCELED);
-
- // Initialize the button to perform device discovery
- Button scanButton = (Button) findViewById(R.id.button_scan);
- scanButton.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- doDiscovery();
- v.setVisibility(View.GONE);
- }
- });
-
- // Initialize array adapters. One for already paired devices and
- // one for newly discovered devices
- mPairedDevicesArrayAdapter = new ArrayAdapter<String>(this, R.layout.device_name);
- mNewDevicesArrayAdapter = new ArrayAdapter<String>(this, R.layout.device_name);
-
- // Find and set up the ListView for paired devices
- ListView pairedListView = (ListView) findViewById(R.id.paired_devices);
- pairedListView.setAdapter(mPairedDevicesArrayAdapter);
- pairedListView.setOnItemClickListener(mDeviceClickListener);
-
- // Find and set up the ListView for newly discovered devices
- ListView newDevicesListView = (ListView) findViewById(R.id.new_devices);
- newDevicesListView.setAdapter(mNewDevicesArrayAdapter);
- newDevicesListView.setOnItemClickListener(mDeviceClickListener);
-
- // Register for broadcasts when a device is discovered
- IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
- this.registerReceiver(mReceiver, filter);
-
- // Register for broadcasts when discovery has finished
- filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
- this.registerReceiver(mReceiver, filter);
-
- // Get the local Bluetooth adapter
- mBtAdapter = BluetoothAdapter.getDefaultAdapter();
-
- // Get a set of currently paired devices
- Set<BluetoothDevice> pairedDevices = mBtAdapter.getBondedDevices();
-
- // If there are paired devices, add each one to the ArrayAdapter
- if (pairedDevices.size() > 0) {
- findViewById(R.id.title_paired_devices).setVisibility(View.VISIBLE);
- for (BluetoothDevice device : pairedDevices)
- if (device.getName().startsWith("TeleBT"))
- mPairedDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
-
- } else {
- String noDevices = getResources().getText(R.string.none_paired).toString();
- mPairedDevicesArrayAdapter.add(noDevices);
- }
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
-
- // Make sure we're not doing discovery anymore
- if (mBtAdapter != null) {
- mBtAdapter.cancelDiscovery();
- }
-
- // Unregister broadcast listeners
- this.unregisterReceiver(mReceiver);
- }
-
- /**
- * Start device discover with the BluetoothAdapter
- */
- private void doDiscovery() {
- AltosDebug.debug("doDiscovery()");
-
- // Indicate scanning in the title
- setProgressBarIndeterminateVisibility(true);
- setTitle(R.string.scanning);
-
- // Turn on sub-title for new devices
- findViewById(R.id.title_new_devices).setVisibility(View.VISIBLE);
-
- // If we're already discovering, stop it
- if (mBtAdapter.isDiscovering()) {
- mBtAdapter.cancelDiscovery();
- }
-
- // Request discover from BluetoothAdapter
- mBtAdapter.startDiscovery();
- }
-
- // The on-click listener for all devices in the ListViews
- private OnItemClickListener mDeviceClickListener = new OnItemClickListener() {
- public void onItemClick(AdapterView<?> av, View v, int arg2, long arg3) {
- // Cancel discovery because it's costly and we're about to connect
- mBtAdapter.cancelDiscovery();
-
- // Get the device MAC address, which is the last 17 chars in the View
- String info = ((TextView) v).getText().toString();
- String address = info.substring(info.length() - 17);
-
- int newline = info.indexOf('\n');
-
- String name = null;
- if (newline > 0)
- name = info.substring(0, newline);
- else
- name = info;
-
- AltosDebug.debug("******* selected item '%s'", info);
-
- // Create the result Intent and include the MAC address
- Intent intent = new Intent();
- intent.putExtra(EXTRA_DEVICE_ADDRESS, address);
- intent.putExtra(EXTRA_DEVICE_NAME, name);
-
- // Set result and finish this Activity
- setResult(Activity.RESULT_OK, intent);
- finish();
- }
- };
-
- // The BroadcastReceiver that listens for discovered devices and
- // changes the title when discovery is finished
- private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
-
- // When discovery finds a device
- if (BluetoothDevice.ACTION_FOUND.equals(action)) {
-
- /* Get the BluetoothDevice object from the Intent
- */
- BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
-
- /* If it's already paired, skip it, because it's been listed already
- */
- if (device != null && device.getBondState() != BluetoothDevice.BOND_BONDED)
- {
- String name = device.getName();
- if (name != null && name.startsWith("TeleBT"))
- mNewDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
- }
-
- /* When discovery is finished, change the Activity title
- */
- } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
- setProgressBarIndeterminateVisibility(false);
- setTitle(R.string.select_device);
- if (mNewDevicesArrayAdapter.getCount() == 0) {
- String noDevices = getResources().getText(R.string.none_found).toString();
- mNewDevicesArrayAdapter.add(noDevices);
- }
- }
- }
- };
-
-}
+++ /dev/null
-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;
- }
-}
+++ /dev/null
-/*
- * Copyright © 2013 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; 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.
- */
-
-package org.altusmetrum.AltosDroid;
-
-import android.content.res.Resources;
-import android.graphics.drawable.Drawable;
-import android.widget.ImageView;
-import android.view.View;
-
-public class GoNoGoLights {
- private Boolean state;
- private Boolean missing;
- private Boolean set;
-
- private ImageView red;
- private ImageView green;
-
- private Drawable dRed;
- private Drawable dGreen;
- private Drawable dGray;
-
- public GoNoGoLights(ImageView in_red, ImageView in_green, Resources r) {
- red = in_red;
- green = in_green;
- state = false;
- missing = true;
- set = false;
-
- dRed = r.getDrawable(R.drawable.redled);
- dGreen = r.getDrawable(R.drawable.greenled);
- dGray = r.getDrawable(R.drawable.grayled);
- }
-
- public void set(Boolean s, Boolean m) {
- if (set && s == state && m == missing) return;
- state = s;
- missing = m;
- set = true;
- if (missing) {
- red.setImageDrawable(dGray);
- green.setImageDrawable(dGray);
- } else if (state) {
- red.setImageDrawable(dGray);
- green.setImageDrawable(dGreen);
- } else {
- red.setImageDrawable(dRed);
- green.setImageDrawable(dGray);
- }
- }
-}
+++ /dev/null
-/*
- * Copyright © 2016 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.
- */
-
-package org.altusmetrum.AltosDroid;
-
-import java.util.*;
-import org.altusmetrum.AltosDroid.R;
-
-import android.app.Activity;
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Bundle;
-import android.view.View;
-import android.view.Window;
-import android.view.View.OnClickListener;
-import android.widget.*;
-import android.widget.AdapterView.*;
-
-import org.altusmetrum.altoslib_13.*;
-
-public class IdleModeActivity extends Activity {
- private EditText callsign;
- private Button connect;
- private Button disconnect;
- private Button reboot;
- private Button igniters;
-
- public static final String EXTRA_IDLE_MODE = "idle_mode";
- public static final String EXTRA_IDLE_RESULT = "idle_result";
-
- public static final int IDLE_MODE_CONNECT = 1;
- public static final int IDLE_MODE_REBOOT = 2;
- public static final int IDLE_MODE_IGNITERS = 3;
- public static final int IDLE_MODE_DISCONNECT = 4;
-
- private void done(int type) {
- AltosPreferences.set_callsign(callsign());
- Intent intent = new Intent();
- intent.putExtra(EXTRA_IDLE_RESULT, type);
- setResult(Activity.RESULT_OK, intent);
- finish();
- }
-
- private String callsign() {
- return callsign.getEditableText().toString();
- }
-
- public void connect_idle() {
- done(IDLE_MODE_CONNECT);
- }
-
- public void disconnect_idle() {
- AltosDebug.debug("Disconnect idle button pressed");
- done(IDLE_MODE_DISCONNECT);
- }
-
- public void reboot_idle() {
- done(IDLE_MODE_REBOOT);
- }
-
- public void igniters_idle() {
- done(IDLE_MODE_IGNITERS);
- }
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- // Setup the window
- requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
- setContentView(R.layout.idle_mode);
-
- callsign = (EditText) findViewById(R.id.set_callsign);
- callsign.setText(new StringBuffer(AltosPreferences.callsign()));
-
- connect = (Button) findViewById(R.id.connect_idle);
- connect.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- connect_idle();
- }
- });
- disconnect = (Button) findViewById(R.id.disconnect_idle);
- disconnect.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- disconnect_idle();
- }
- });
-
- boolean idle_mode = getIntent().getBooleanExtra(AltosDroid.EXTRA_IDLE_MODE, false);
-
- if (idle_mode)
- connect.setVisibility(View.GONE);
- else
- disconnect.setVisibility(View.GONE);
-
- reboot = (Button) findViewById(R.id.reboot_idle);
- reboot.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- reboot_idle();
- }
- });
- igniters = (Button) findViewById(R.id.igniters_idle);
- igniters.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- igniters_idle();
- }
- });
-
- // Set result CANCELED incase the user backs out
- setResult(Activity.RESULT_CANCELED);
- }
-}
+++ /dev/null
-/*
- * Copyright © 2016 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.
- */
-
-package org.altusmetrum.AltosDroid;
-
-import java.lang.ref.WeakReference;
-import java.util.*;
-import org.altusmetrum.AltosDroid.R;
-
-import android.app.Activity;
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
-import android.content.*;
-import android.graphics.*;
-import android.os.*;
-import android.view.*;
-import android.view.View.*;
-import android.widget.*;
-import android.widget.AdapterView.*;
-
-import org.altusmetrum.altoslib_13.*;
-
-class IgniterItem {
- public String name;
- public String pretty;
- public String status;
- public LinearLayout igniter_view = null;
- public TextView pretty_view = null;
- public TextView status_view = null;
-
- private void update() {
- if (pretty_view != null)
- pretty_view.setText(pretty);
- if (status_view != null)
- status_view.setText(status);
- }
-
- public void set(String name, String pretty, String status) {
- if (!name.equals(this.name) ||
- !pretty.equals(this.pretty) ||
- !status.equals(this.status))
- {
- this.name = name;
- this.pretty = pretty;
- this.status = status;
- update();
- }
- }
-
- public void realize(LinearLayout igniter_view,
- TextView pretty_view,
- TextView status_view) {
- if (igniter_view != this.igniter_view ||
- pretty_view != this.pretty_view ||
- status_view != this.status_view)
- {
- this.igniter_view = igniter_view;
- this.pretty_view = pretty_view;
- this.status_view = status_view;
- update();
- }
- }
-
- public IgniterItem() {
- }
-}
-
-class IgniterAdapter extends ArrayAdapter<IgniterItem> {
- int resource;
- int selected_item = -1;
-
- public IgniterAdapter(Context context, int in_resource) {
- super(context, in_resource);
- resource = in_resource;
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- IgniterItem item = getItem(position);
- if (item.igniter_view == null) {
- LinearLayout igniter_view = new LinearLayout(getContext());
- String inflater = Context.LAYOUT_INFLATER_SERVICE;
- LayoutInflater li = (LayoutInflater) getContext().getSystemService(inflater);
- li.inflate(resource, igniter_view, true);
-
- item.realize(igniter_view,
- (TextView) igniter_view.findViewById(R.id.igniter_name),
- (TextView) igniter_view.findViewById(R.id.igniter_status));
- }
- if (position == selected_item)
- item.igniter_view.setBackgroundColor(Color.RED);
- else
- item.igniter_view.setBackgroundColor(Color.BLACK);
- return item.igniter_view;
- }
-}
-
-public class IgniterActivity extends Activity {
- private ListView igniters_view;
- private ToggleButton arm;
- private Button fire;
-
- private HashMap<String,IgniterItem> igniters = new HashMap<String,IgniterItem>();;
-
- private IgniterAdapter igniters_adapter;
-
- private boolean is_bound;
- private Messenger service = null;
- private final Messenger messenger = new Messenger(new IncomingHandler(this));
-
- private Timer query_timer;
- private boolean query_timer_running;
-
- private Timer arm_timer;
- private int arm_remaining;
-
- public static final int IGNITER_QUERY = 1;
- public static final int IGNITER_FIRE = 2;
-
- // The Handler that gets information back from the Telemetry Service
- static class IncomingHandler extends Handler {
- private final WeakReference<IgniterActivity> igniter_activity;
- IncomingHandler(IgniterActivity ia) { igniter_activity = new WeakReference<IgniterActivity>(ia); }
-
- @Override
- public void handleMessage(Message msg) {
- IgniterActivity ia = igniter_activity.get();
-
- switch (msg.what) {
- case AltosDroid.MSG_IGNITER_STATUS:
- ia.igniter_status((HashMap <String,Integer>) msg.obj);
- break;
- }
- }
- };
-
-
- private ServiceConnection connection = new ServiceConnection() {
- public void onServiceConnected(ComponentName className, IBinder binder) {
- service = new Messenger(binder);
- query_timer_tick();
- }
-
- public void onServiceDisconnected(ComponentName className) {
- // This is called when the connection with the service has been unexpectedly disconnected - process crashed.
- service = null;
- }
- };
-
- void doBindService() {
- bindService(new Intent(this, TelemetryService.class), connection, Context.BIND_AUTO_CREATE);
- is_bound = true;
- }
-
- void doUnbindService() {
- if (is_bound) {
- // If we have received the service, and hence registered with it, then now is the time to unregister.
- unbindService(connection);
- is_bound = false;
- }
- }
-
- private void done() {
- Intent intent = new Intent();
- setResult(Activity.RESULT_OK, intent);
- finish();
- }
-
- class FireThread extends Thread {
- private final String igniter;
-
- @Override
- public void run() {
- Message msg = Message.obtain(null, TelemetryService.MSG_IGNITER_FIRE, igniter);
- try {
- service.send(msg);
- } catch (RemoteException re) {
- }
- }
-
- public FireThread(String igniter) {
- this.igniter = igniter;
- }
- }
-
- private void fire_igniter() {
- if (igniters_adapter.selected_item >= 0) {
- IgniterItem item = igniters_adapter.getItem(igniters_adapter.selected_item);
- FireThread ft = new FireThread(item.name);
- ft.run();
- arm.setChecked(false);
- }
- }
-
- private void arm_igniter(boolean is_checked) {
- if (is_checked) {
- arm_timer_stop();
- arm_timer = new Timer();
- arm_remaining = 10;
- arm_set_text();
- fire.setEnabled(true);
- arm_timer.scheduleAtFixedRate(new TimerTask() {
- public void run() {
- arm_timer_tick();
- }},
- 1000L, 1000L);
- } else {
- arm_timer_stop();
- fire.setEnabled(false);
- }
- }
-
- private synchronized void query_timer_tick() {
- if (query_timer_running)
- return;
- if (service == null)
- return;
- query_timer_running = true;
- Thread thread = new Thread(new Runnable() {
- public void run() {
- try {
- Message msg = Message.obtain(null, TelemetryService.MSG_IGNITER_QUERY);
- msg.replyTo = messenger;
- if (service == null) {
- synchronized(IgniterActivity.this) {
- query_timer_running = false;
- }
- } else
- service.send(msg);
- } catch (RemoteException re) {
- AltosDebug.debug("igniter query thread failed");
- synchronized(IgniterActivity.this) {
- query_timer_running = false;
- }
- }
- }
- });
- thread.start();
- }
-
- private boolean set_igniter(HashMap <String,Integer> status, String name, String pretty) {
- if (!status.containsKey(name))
- return false;
-
- IgniterItem item;
- if (!igniters.containsKey(name)) {
- item = new IgniterItem();
- igniters.put(name, item);
- igniters_adapter.add(item);
- } else
- item = igniters.get(name);
-
- item.set(name, pretty, AltosIgnite.status_string(status.get(name)));
- return true;
- }
-
- private synchronized void igniter_status(HashMap <String,Integer> status) {
- query_timer_running = false;
- if (status == null) {
- AltosDebug.debug("no igniter status");
- return;
- }
- set_igniter(status, "drogue", "Apogee");
- set_igniter(status, "main", "Main");
- for (int extra = 0;; extra++) {
- String name = String.format("%d", extra);
- String pretty = String.format("%c", 'A' + extra);
- if (!set_igniter(status, name, pretty))
- break;
- }
- }
-
- private synchronized void arm_timer_stop() {
- if (arm_timer != null) {
- arm_timer.cancel();
- arm_timer = null;
- }
- arm_remaining = 0;
- }
-
- private void arm_set_text() {
- String text = String.format("Armed %d", arm_remaining);
-
- if (arm.isChecked())
- arm.setText(text);
- arm.setTextOn(text);
- }
-
- private void arm_timer_tick() {
- --arm_remaining;
- if (arm_remaining <= 0) {
- arm_timer_stop();
- runOnUiThread(new Runnable() {
- public void run() {
- arm.setChecked(false);
- fire.setEnabled(false);
- }
- });
- } else {
- runOnUiThread(new Runnable() {
- public void run() {
- arm_set_text();
- }
- });
- }
- }
-
- private void select_item(int position) {
- if (position != igniters_adapter.selected_item) {
- if (igniters_adapter.selected_item >= 0)
- igniters_view.setItemChecked(igniters_adapter.selected_item, false);
- if (position >= 0) {
- igniters_view.setItemChecked(position, true);
- arm.setEnabled(true);
- } else
- arm.setEnabled(false);
- igniters_adapter.selected_item = position;
- }
- }
-
- private class IgniterItemClickListener implements ListView.OnItemClickListener {
- @Override
- public void onItemClick(AdapterView<?> av, View v, int position, long id) {
- AltosDebug.debug("select %d\n", position);
- select_item(position);
- }
- }
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- // Setup the window
- requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
- setContentView(R.layout.igniters);
-
- igniters_view = (ListView) findViewById(R.id.igniters);
- igniters_view.setClickable(true);
-
- igniters_adapter = new IgniterAdapter(this, R.layout.igniter_status);
-
- igniters_view.setAdapter(igniters_adapter);
- igniters_view.setOnItemClickListener(new IgniterItemClickListener());
-
- fire = (Button) findViewById(R.id.igniter_fire);
- fire.setEnabled(false);
- fire.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- fire_igniter();
- }
- });
-
- arm = (ToggleButton) findViewById(R.id.igniter_arm);
- arm.setEnabled(false);
- arm.setOnCheckedChangeListener(new ToggleButton.OnCheckedChangeListener() {
- public void onCheckedChanged(CompoundButton v, boolean is_checked) {
- arm_igniter(is_checked);
- }
- });
-
- // Set result CANCELED incase the user backs out
- setResult(Activity.RESULT_CANCELED);
- }
-
- @Override
- protected void onStart() {
- super.onStart();
- doBindService();
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- query_timer = new Timer(true);
- query_timer.scheduleAtFixedRate(new TimerTask() {
- public void run() {
- query_timer_tick();
- }},
- 0L, 5000L);
- }
-
- @Override
- protected void onPause() {
- super.onPause();
- if (query_timer != null) {
- query_timer.cancel();
- query_timer = null;
- }
- arm_timer_stop();
- arm.setChecked(false);
- fire.setEnabled(false);
- }
-
- @Override
- protected void onStop() {
- super.onStop();
- doUnbindService();
- }
-}
+++ /dev/null
-/*
- * Copyright © 2016 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.
- */
-
-package org.altusmetrum.AltosDroid;
-
-import java.lang.ref.WeakReference;
-import java.util.*;
-import java.text.*;
-import org.altusmetrum.AltosDroid.R;
-
-import android.app.Activity;
-import android.content.*;
-import android.graphics.*;
-import android.os.*;
-import android.view.*;
-import android.view.View.*;
-import android.view.inputmethod.*;
-import android.widget.*;
-import android.widget.AdapterView.*;
-
-import org.altusmetrum.altoslib_13.*;
-
-class FrequencyItem {
- public AltosFrequency frequency;
- public LinearLayout frequency_view = null;
- public TextView pretty_view = null;
-
- private void update() {
- if (pretty_view != null && frequency != null)
- pretty_view.setText(frequency.toString());
- }
-
- public void realize(LinearLayout frequency_view,
- TextView pretty_view) {
- if (frequency_view != this.frequency_view ||
- pretty_view != this.pretty_view)
- {
- this.frequency_view = frequency_view;
- this.pretty_view = pretty_view;
- update();
- }
- }
-
- public void set_frequency(AltosFrequency frequency) {
- this.frequency = frequency;
- update();
- }
-
- public FrequencyItem(AltosFrequency frequency) {
- this.frequency = frequency;
- }
-}
-
-class FrequencyAdapter extends ArrayAdapter<FrequencyItem> {
- int resource;
- int selected_item = -1;
-
- public FrequencyAdapter(Context context, int in_resource) {
- super(context, in_resource);
- resource = in_resource;
- }
-
- public int count() {
- int count;
-
- for (count = 0;; count++) {
- try {
- getItem(count);
- } catch (IndexOutOfBoundsException ie) {
- return count;
- }
- }
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- FrequencyItem item = getItem(position);
- if (item.frequency_view == null) {
- LinearLayout frequency_view = new LinearLayout(getContext());
- String inflater = Context.LAYOUT_INFLATER_SERVICE;
- LayoutInflater li = (LayoutInflater) getContext().getSystemService(inflater);
- li.inflate(resource, frequency_view, true);
-
- item.realize(frequency_view,
- (TextView) frequency_view.findViewById(R.id.frequency));
- }
- if (position == selected_item)
- item.frequency_view.setBackgroundColor(Color.RED);
- else
- item.frequency_view.setBackgroundColor(Color.BLACK);
- return item.frequency_view;
- }
-}
-
-public class ManageFrequenciesActivity extends Activity {
- private ListView frequencies_view;
-
- private Button set;
- private Button remove;
- private Button done;
-
- private EditText set_frequency;
- private EditText set_description;
-
- private HashMap<String,FrequencyItem> frequencies = new HashMap<String,FrequencyItem>();;
-
- private FrequencyAdapter frequencies_adapter;
-
- private boolean is_bound;
- private boolean changed = false;
-
- private void done() {
-
- set();
-
- if (changed) {
- AltosFrequency[] frequencies = new AltosFrequency[frequencies_adapter.count()];
- for (int i = 0; i < frequencies.length; i++)
- frequencies[i] = frequencies_adapter.getItem(i).frequency;
- AltosPreferences.set_common_frequencies(frequencies);
- }
-
- Intent intent = new Intent();
- setResult(Activity.RESULT_OK, intent);
- finish();
- }
-
- private void load_item() {
- if (frequencies_adapter.selected_item >= 0) {
- FrequencyItem item = frequencies_adapter.getItem(frequencies_adapter.selected_item);
-
- set_frequency.setText(item.frequency.frequency_string());
- set_description.setText(item.frequency.description);
- } else {
- set_frequency.setText("");
- set_description.setText("");
- }
- }
-
- private void select_item(int position) {
- if (position != frequencies_adapter.selected_item) {
- if (frequencies_adapter.selected_item >= 0)
- frequencies_view.setItemChecked(frequencies_adapter.selected_item, false);
- if (position >= 0)
- frequencies_view.setItemChecked(position, true);
- frequencies_adapter.selected_item = position;
- } else {
- if (frequencies_adapter.selected_item >= 0)
- frequencies_view.setItemChecked(frequencies_adapter.selected_item, false);
- frequencies_adapter.selected_item = -1;
- }
- load_item();
- }
-
- private int find(AltosFrequency frequency) {
- for (int pos = 0; pos < frequencies_adapter.getCount(); pos++) {
- FrequencyItem item = frequencies_adapter.getItem(pos);
- if (item.frequency.frequency == frequency.frequency &&
- item.frequency.description.equals(frequency.description))
- return pos;
- }
- return -1;
- }
-
- private int insert_item(AltosFrequency frequency) {
- FrequencyItem new_item = new FrequencyItem(frequency);
- int pos;
- for (pos = 0; pos < frequencies_adapter.getCount(); pos++) {
- FrequencyItem item = frequencies_adapter.getItem(pos);
- if (item.frequency.frequency == new_item.frequency.frequency) {
- item.set_frequency(frequency);
- return pos;
- }
- if (item.frequency.frequency > new_item.frequency.frequency)
- break;
- }
- frequencies_adapter.insert(new_item, pos);
- return pos;
- }
-
- private class FrequencyItemClickListener implements ListView.OnItemClickListener {
- @Override
- public void onItemClick(AdapterView<?> av, View v, int position, long id) {
- select_item(position);
- }
- }
-
- private void hide_keyboard() {
- InputMethodManager imm = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
- View view = getCurrentFocus();
- if (view != null)
- imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
- }
-
- private void set() {
- String frequency_text = set_frequency.getEditableText().toString();
- String description_text = set_description.getEditableText().toString();
-
- try {
- double f = AltosParse.parse_double_locale(frequency_text);
- AltosFrequency frequency = new AltosFrequency(f, description_text);
- int pos;
-
- pos = find(frequency);
- if (pos < 0) {
- pos = insert_item(frequency);
- changed = true;
- }
- frequencies_adapter.selected_item = -1;
- select_item(pos);
- } catch (ParseException pe) {
- }
- hide_keyboard();
- }
-
- private void remove() {
- if (frequencies_adapter.selected_item >= 0) {
- frequencies_adapter.remove(frequencies_adapter.getItem(frequencies_adapter.selected_item));
- select_item(-1);
- frequencies_view.setAdapter(frequencies_adapter);
- changed = true;
- }
- }
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- // Setup the window
- requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
- setContentView(R.layout.manage_frequencies);
-
- frequencies_view = (ListView) findViewById(R.id.frequencies);
- frequencies_view.setClickable(true);
-
- frequencies_adapter = new FrequencyAdapter(this, R.layout.frequency);
-
- frequencies_view.setAdapter(frequencies_adapter);
- frequencies_view.setOnItemClickListener(new FrequencyItemClickListener());
-
- AltosFrequency[] frequencies = AltosPreferences.common_frequencies();
- for (AltosFrequency frequency : frequencies)
- insert_item(frequency);
-
- set_frequency = (EditText) findViewById(R.id.set_frequency);
- set_description = (EditText) findViewById(R.id.set_description);
-
- set = (Button) findViewById(R.id.set);
- set.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- set();
- }
- });
-
- remove = (Button) findViewById(R.id.remove);
- remove.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- remove();
- }
- });
-
- done = (Button) findViewById(R.id.done);
- done.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- done();
- }
- });
-
- // Set result CANCELED incase the user backs out
- setResult(Activity.RESULT_CANCELED);
- }
-
- @Override
- protected void onStart() {
- super.onStart();
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- }
-
- @Override
- protected void onPause() {
- super.onPause();
- }
-
- @Override
- protected void onStop() {
- super.onStop();
- }
-}
+++ /dev/null
-/*
- * Copyright © 2015 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.
- */
-
-package org.altusmetrum.AltosDroid;
-
-import java.util.*;
-import org.altusmetrum.AltosDroid.R;
-
-import android.app.Activity;
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Bundle;
-import android.view.View;
-import android.view.Window;
-import android.view.View.OnClickListener;
-import android.widget.*;
-import android.widget.AdapterView.*;
-
-import org.altusmetrum.altoslib_13.*;
-
-public class MapTypeActivity extends Activity {
- private Button hybrid;
- private Button satellite;
- private Button roadmap;
- private Button terrain;
- private int selected_type;
-
- public static final String EXTRA_MAP_TYPE = "map_type";
-
- private void done(int type) {
-
- Intent intent = new Intent();
- intent.putExtra(EXTRA_MAP_TYPE, type);
- setResult(Activity.RESULT_OK, intent);
- finish();
- }
-
- public void selectType(View view) {
- AltosDebug.debug("selectType %s", view.toString());
- if (view == hybrid)
- done(AltosMap.maptype_hybrid);
- if (view == satellite)
- done(AltosMap.maptype_satellite);
- if (view == roadmap)
- done(AltosMap.maptype_roadmap);
- if (view == terrain)
- done(AltosMap.maptype_terrain);
- }
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- // Setup the window
- requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
- setContentView(R.layout.map_type);
-
- hybrid = (Button) findViewById(R.id.map_type_hybrid);
- satellite = (Button) findViewById(R.id.map_type_satellite);
- roadmap = (Button) findViewById(R.id.map_type_roadmap);
- terrain = (Button) findViewById(R.id.map_type_terrain);
-
- // Set result CANCELED incase the user backs out
- setResult(Activity.RESULT_CANCELED);
- }
-}
+++ /dev/null
-/*
- * Copyright © 2015 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.
- */
-
-package org.altusmetrum.AltosDroid;
-
-import java.util.*;
-import java.io.*;
-import java.text.*;
-
-import org.altusmetrum.AltosDroid.R;
-
-import android.app.Activity;
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Bundle;
-import android.view.View;
-import android.view.Window;
-import android.view.View.OnClickListener;
-import android.widget.*;
-import android.widget.AdapterView.*;
-import android.location.Location;
-import android.location.LocationManager;
-import android.location.LocationListener;
-import android.location.Criteria;
-
-import org.altusmetrum.altoslib_13.*;
-
-/**
- * This Activity appears as a dialog. It lists any paired devices and
- * devices detected in the area after discovery. When a device is chosen
- * by the user, the MAC address of the device is sent back to the parent
- * Activity in the result Intent.
- */
-public class PreloadMapActivity extends Activity implements AltosLaunchSiteListener, AltosMapLoaderListener, LocationListener {
-
- private ArrayAdapter<AltosLaunchSite> known_sites_adapter;
-
-/*
- private CheckBox hybrid;
- private CheckBox satellite;
- private CheckBox roadmap;
- private CheckBox terrain;
-*/
-
- private Spinner known_sites_spinner;
- private Spinner min_zoom;
- private Spinner max_zoom;
- private TextView radius_label;
- private Spinner radius;
-
- private EditText latitude;
- private EditText longitude;
-
- private ProgressBar progress;
-
- private AltosMapLoader loader;
-
- long loader_notify_time;
-
- /* AltosMapLoaderListener interfaces */
- public void loader_start(final int max) {
- loader_notify_time = System.currentTimeMillis();
-
- this.runOnUiThread(new Runnable() {
- public void run() {
- progress.setMax(max);
- progress.setProgress(0);
- }
- });
- }
-
- public void loader_notify(final int cur, final int max, final String name) {
- long now = System.currentTimeMillis();
-
- if (now - loader_notify_time < 100)
- return;
-
- loader_notify_time = now;
-
- this.runOnUiThread(new Runnable() {
- public void run() {
- progress.setProgress(cur);
- }
- });
- }
-
- public void loader_done(int max) {
- loader = null;
- this.runOnUiThread(new Runnable() {
- public void run() {
- progress.setProgress(0);
- finish();
- }
- });
- }
-
- public void debug(String format, Object ... arguments) {
- AltosDebug.debug(format, arguments);
- }
-
- /* AltosLaunchSiteListener interface */
-
- public void notify_launch_sites(final List<AltosLaunchSite> sites) {
- this.runOnUiThread(new Runnable() {
- public void run() {
- for (AltosLaunchSite site : sites)
- known_sites_adapter.add(site);
- }
- });
- }
-
- /* LocationProvider interface */
-
- AltosLaunchSite current_location_site;
-
- public void onLocationChanged(Location location) {
- AltosDebug.debug("location changed");
- if (current_location_site == null) {
- AltosLaunchSite selected_item = (AltosLaunchSite) known_sites_spinner.getSelectedItem();
-
- current_location_site = new AltosLaunchSite("Current Location", location.getLatitude(), location.getLongitude());
- known_sites_adapter.insert(current_location_site, 0);
-
- if (selected_item != null)
- known_sites_spinner.setSelection(known_sites_adapter.getPosition(selected_item));
- else {
- latitude.setText(new StringBuffer(String.format("%12.6f", current_location_site.latitude)));
- longitude.setText(new StringBuffer(String.format("%12.6f", current_location_site.longitude)));
- }
- } else {
- current_location_site.latitude = location.getLatitude();
- current_location_site.longitude = location.getLongitude();
- }
- }
-
- public void onStatusChanged(String provider, int status, Bundle extras) {
- }
-
- public void onProviderEnabled(String provider) {
- }
-
- public void onProviderDisabled(String provider) {
- }
-
- private double text(EditText view) throws ParseException {
- return AltosParse.parse_double_locale(view.getEditableText().toString());
- }
-
- private double latitude() throws ParseException {
- return text(latitude);
- }
-
- private double longitude() throws ParseException {
- return text(longitude);
- }
-
- private int value(Spinner spinner) {
- return (Integer) spinner.getSelectedItem();
- }
-
- private int min_z() {
- return value(min_zoom);
- }
-
- private int max_z() {
- return value(max_zoom);
- }
-
- private double value_distance(Spinner spinner) {
- return (Double) spinner.getSelectedItem();
- }
-
- private double radius() {
- double r = value_distance(radius);
- if (AltosPreferences.imperial_units())
- r = AltosConvert.miles_to_meters(r);
- else
- r = r * 1000;
- return r;
- }
-
-/*
- private int bit(CheckBox box, int value) {
- if (box.isChecked())
- return 1 << value;
- return 0;
- }
-*/
-
- private int types() {
-/*
- return (bit(hybrid, AltosMap.maptype_hybrid) |
- bit(satellite, AltosMap.maptype_satellite) |
- bit(roadmap, AltosMap.maptype_roadmap) |
- bit(terrain, AltosMap.maptype_terrain));
-*/
- return 1 << AltosMap.maptype_hybrid;
- }
-
- private void load() {
- if (loader != null)
- return;
-
- try {
- double lat = latitude();
- double lon = longitude();
- int min = min_z();
- int max = max_z();
- double r = radius();
- int t = types();
-
- AltosDebug.debug("PreloadMap load %f %f %d %d %f %d\n",
- lat, lon, min, max, r, t);
- loader = new AltosMapLoader(this, lat, lon, min, max, r, t, AltosMapOffline.scale);
- } catch (ParseException e) {
- AltosDebug.debug("PreloadMap load raised exception %s", e.toString());
- }
- }
-
- private void add_numbers(Spinner spinner, int min, int max, int def) {
-
- ArrayAdapter<Integer> adapter = new ArrayAdapter<Integer>(this, android.R.layout.simple_spinner_item);
-
- int spinner_def = 0;
- int pos = 0;
-
- for (int i = min; i <= max; i++) {
- adapter.add(new Integer(i));
- if (i == def)
- spinner_def = pos;
- pos++;
- }
-
- spinner.setAdapter(adapter);
- spinner.setSelection(spinner_def);
- }
-
-
- private void add_distance(Spinner spinner, double[] distances_km, double def_km, double[] distances_mi, double def_mi) {
-
- ArrayAdapter<Double> adapter = new ArrayAdapter<Double>(this, android.R.layout.simple_spinner_item);
-
- int spinner_def = 0;
- int pos = 0;
-
- double[] distances;
- double def;
- if (AltosPreferences.imperial_units()) {
- distances = distances_mi;
- def = def_mi;
- } else {
- distances = distances_km;
- def = def_km;
- }
-
- for (int i = 0; i < distances.length; i++) {
- adapter.add(distances[i]);
- if (distances[i] == def)
- spinner_def = pos;
- pos++;
- }
-
- spinner.setAdapter(adapter);
- spinner.setSelection(spinner_def);
- }
-
-
-
- class SiteListListener implements OnItemSelectedListener {
- public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
- AltosLaunchSite site = (AltosLaunchSite) parent.getItemAtPosition(pos);
- latitude.setText(new StringBuffer(String.format("%12.6f", site.latitude)));
- longitude.setText(new StringBuffer(String.format("%12.6f", site.longitude)));
- }
- public void onNothingSelected(AdapterView<?> parent) {
- }
-
- public SiteListListener() {
- }
- }
-
- double[] radius_mi = { 1, 2, 5, 10, 20 };
- double radius_def_mi = 2;
- double[] radius_km = { 1, 2, 5, 10, 20, 30 };
- double radius_def_km = 2;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- // Setup the window
- requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
- setContentView(R.layout.map_preload);
-
- // Set result CANCELED incase the user backs out
- setResult(Activity.RESULT_CANCELED);
-
- // Initialize the button to perform device discovery
- Button loadButton = (Button) findViewById(R.id.preload_load);
- loadButton.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- load();
- }
- });
-
- latitude = (EditText) findViewById(R.id.preload_latitude);
- longitude = (EditText) findViewById(R.id.preload_longitude);
-
-/*
- hybrid = (CheckBox) findViewById(R.id.preload_hybrid);
- satellite = (CheckBox) findViewById(R.id.preload_satellite);
- roadmap = (CheckBox) findViewById(R.id.preload_roadmap);
- terrain = (CheckBox) findViewById(R.id.preload_terrain);
-
- hybrid.setChecked(true);
-*/
-
- min_zoom = (Spinner) findViewById(R.id.preload_min_zoom);
- add_numbers(min_zoom,
- AltosMap.min_zoom - AltosMap.default_zoom,
- AltosMap.max_zoom - AltosMap.default_zoom, -2);
- max_zoom = (Spinner) findViewById(R.id.preload_max_zoom);
- add_numbers(max_zoom,
- AltosMap.min_zoom - AltosMap.default_zoom,
- AltosMap.max_zoom - AltosMap.default_zoom, 2);
- radius_label = (TextView) findViewById(R.id.preload_radius_label);
- radius = (Spinner) findViewById(R.id.preload_radius);
- if (AltosPreferences.imperial_units())
- radius_label.setText("Radius (miles)");
- else
- radius_label.setText("Radius (km)");
- add_distance(radius, radius_km, radius_def_km, radius_mi, radius_def_mi);
-
- progress = (ProgressBar) findViewById(R.id.preload_progress);
-
- // Initialize array adapters. One for already paired devices and
- // one for newly discovered devices
- known_sites_spinner = (Spinner) findViewById(R.id.preload_site_list);
-
- known_sites_adapter = new ArrayAdapter<AltosLaunchSite>(this, android.R.layout.simple_spinner_item);
-
- known_sites_adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
-
- known_sites_spinner.setAdapter(known_sites_adapter);
- known_sites_spinner.setOnItemSelectedListener(new SiteListListener());
-
- // Listen for GPS and Network position updates
- LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
-
- locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 1, this);
-
- new AltosLaunchSites(this);
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
-
- if (loader != null)
- loader.abort();
-
- // Stop listening for location updates
- ((LocationManager) getSystemService(Context.LOCATION_SERVICE)).removeUpdates(this);
- }
-}
+++ /dev/null
-/*
- * Copyright © 2016 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.
- */
-
-package org.altusmetrum.AltosDroid;
-
-import java.lang.ref.WeakReference;
-import java.util.*;
-import org.altusmetrum.AltosDroid.R;
-
-import android.app.Activity;
-import android.bluetooth.*;
-import android.content.*;
-import android.os.*;
-import android.view.*;
-import android.view.View.*;
-import android.widget.*;
-import android.widget.AdapterView.*;
-
-import org.altusmetrum.altoslib_13.*;
-
-public class SetupActivity extends Activity {
- private Spinner select_rate;
- private Spinner set_units;
- private Spinner map_type;
- private Spinner map_source;
- private Button manage_frequencies;
- private Button preload_maps;
- private Button done;
-
- private boolean is_bound;
- private Messenger service = null;
-
- public final static String EXTRA_SETUP_CHANGES = "setup_changes";
-
- private ServiceConnection connection = new ServiceConnection() {
- public void onServiceConnected(ComponentName className, IBinder binder) {
- service = new Messenger(binder);
- }
-
- public void onServiceDisconnected(ComponentName className) {
- // This is called when the connection with the service has been unexpectedly disconnected - process crashed.
- service = null;
- }
- };
-
- void doBindService() {
- bindService(new Intent(this, TelemetryService.class), connection, Context.BIND_AUTO_CREATE);
- is_bound = true;
- }
-
- void doUnbindService() {
- if (is_bound) {
- // If we have received the service, and hence registered with it, then now is the time to unregister.
- unbindService(connection);
- is_bound = false;
- }
- }
-
- static final String[] rates = {
- "38400",
- "9600",
- "2400",
- };
-
- static final String[] map_types = {
- "Hybrid",
- "Satellite",
- "Roadmap",
- "Terrain"
- };
-
- static final int[] map_type_values = {
- AltosMap.maptype_hybrid,
- AltosMap.maptype_satellite,
- AltosMap.maptype_roadmap,
- AltosMap.maptype_terrain,
- };
-
- static final String[] map_sources = {
- "Online",
- "Offline"
- };
-
- private int set_telemetry_rate;
- private int set_map_source;
- private int set_map_type;
- private boolean set_imperial_units;
-
- private int changes = 0;
-
- private void add_change(int change) {
- changes |= change;
- }
-
- private void done() {
- Intent intent = new Intent();
- if ((changes & AltosDroid.SETUP_BAUD) != 0)
- AltosPreferences.set_telemetry_rate(1, set_telemetry_rate);
- if ((changes & AltosDroid.SETUP_UNITS) != 0)
- AltosPreferences.set_imperial_units(set_imperial_units);
- if ((changes & AltosDroid.SETUP_MAP_SOURCE) != 0)
- AltosDroidPreferences.set_map_source(set_map_source);
- if ((changes & AltosDroid.SETUP_MAP_TYPE) != 0)
- AltosPreferences.set_map_type(set_map_type);
- intent.putExtra(EXTRA_SETUP_CHANGES, changes);
- setResult(Activity.RESULT_OK, intent);
- finish();
- }
-
- private void add_strings(Spinner spinner, String[] strings, int def) {
- ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item);
-
- for (int i = 0; i < strings.length; i++)
- adapter.add(strings[i]);
-
- spinner.setAdapter(adapter);
- if (def >= 0)
- spinner.setSelection(def);
- }
-
- private int default_rate_pos() {
- int default_rate = AltosPreferences.telemetry_rate(1);
-
- for (int pos = 0; pos < rates.length; pos++) {
- if (string_to_rate(rates[pos]) == default_rate)
- return pos;
- }
- return -1;
- }
-
- private void setBaud(int baud) {
- try {
- service.send(Message.obtain(null, TelemetryService.MSG_SETBAUD, baud));
- set_telemetry_rate = baud;
- add_change(AltosDroid.SETUP_BAUD);
- } catch (RemoteException e) {
- }
- }
-
- private int string_to_rate(String baud) {
- int rate = AltosLib.ao_telemetry_rate_38400;
- try {
- int value = Integer.parseInt(baud);
- switch (value) {
- case 2400:
- rate = AltosLib.ao_telemetry_rate_2400;
- break;
- case 9600:
- rate = AltosLib.ao_telemetry_rate_9600;
- break;
- case 38400:
- rate = AltosLib.ao_telemetry_rate_38400;
- break;
- }
- } catch (NumberFormatException e) {
- }
- return rate;
- }
-
- private void setBaud(String baud) {
- setBaud(string_to_rate(baud));
- }
-
- private void select_rate(int pos) {
- setBaud(rates[pos]);
- }
-
- static final String[] units = {
- "Metric",
- "Imperial"
- };
-
- private int default_units_pos() {
- boolean imperial = AltosPreferences.imperial_units();
-
- if (imperial)
- return 1;
- return 0;
- }
-
- private void set_units(int pos) {
- switch (pos) {
- default:
- set_imperial_units = false;
- break;
- case 1:
- set_imperial_units = true;
- break;
- }
- add_change(AltosDroid.SETUP_UNITS);
- }
-
- private int default_map_type_pos() {
- int default_map_type = AltosPreferences.map_type();
-
- for (int pos = 0; pos < map_types.length; pos++)
- if (map_type_values[pos] == default_map_type)
- return pos;
- return 0;
- }
-
- private void select_map_type(int pos) {
- set_map_type = map_type_values[pos];
- add_change(AltosDroid.SETUP_MAP_TYPE);
- }
-
- private int default_map_source_pos() {
- int default_source = AltosDroidPreferences.map_source();
-
- switch (default_source) {
- case AltosDroidPreferences.MAP_SOURCE_OFFLINE:
- return 1;
- default:
- return 0;
- }
- }
-
- private void select_map_source(int pos) {
- switch (pos) {
- default:
- set_map_source = AltosDroidPreferences.MAP_SOURCE_ONLINE;
- break;
- case 1:
- set_map_source = AltosDroidPreferences.MAP_SOURCE_OFFLINE;
- break;
- }
- add_change(AltosDroid.SETUP_MAP_SOURCE);
- }
-
- private void manage_frequencies(){
- Intent intent = new Intent(this, ManageFrequenciesActivity.class);
- startActivity(intent);
- }
-
- private void preload_maps(){
- Intent intent = new Intent(this, PreloadMapActivity.class);
- startActivity(intent);
- }
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- AltosDebug.init(this);
- AltosDebug.debug("+++ ON CREATE +++");
-
- // Initialise preferences
- AltosDroidPreferences.init(this);
-
- // Setup the window
- requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
- setContentView(R.layout.setup);
-
- select_rate = (Spinner) findViewById(R.id.select_rate);
- add_strings(select_rate, rates, default_rate_pos());
- select_rate.setOnItemSelectedListener(new OnItemSelectedListener() {
- public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
- select_rate(pos);
- }
- public void onNothingSelected(AdapterView<?> parent) {
- }
- });
-
- set_units = (Spinner) findViewById(R.id.set_units);
- add_strings(set_units, units, default_units_pos());
- set_units.setOnItemSelectedListener(new OnItemSelectedListener() {
- public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
- set_units(pos);
- }
- public void onNothingSelected(AdapterView<?> parent) {
- }
- });
-
- map_type = (Spinner) findViewById(R.id.map_type);
- add_strings(map_type, map_types, default_map_type_pos());
- map_type.setOnItemSelectedListener(new OnItemSelectedListener() {
- public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
- select_map_type(pos);
- }
- public void onNothingSelected(AdapterView<?> parent) {
- }
- });
-
- map_source = (Spinner) findViewById(R.id.map_source);
- add_strings(map_source, map_sources, default_map_source_pos());
- map_source.setOnItemSelectedListener(new OnItemSelectedListener() {
- public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
- select_map_source(pos);
- }
- public void onNothingSelected(AdapterView<?> parent) {
- }
- });
-
-
- manage_frequencies = (Button) findViewById(R.id.manage_frequencies);
- manage_frequencies.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- manage_frequencies();
- }
- });
-
- preload_maps = (Button) findViewById(R.id.preload_maps);
- preload_maps.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- preload_maps();
- }
- });
-
- done = (Button) findViewById(R.id.done);
- done.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- done();
- }
- });
-
- // Set result for when the user backs out
- setResult(Activity.RESULT_CANCELED);
- }
-
- @Override
- protected void onStart() {
- super.onStart();
- doBindService();
- }
-
- @Override
- protected void onStop() {
- super.onStop();
- doUnbindService();
- }
-}
+++ /dev/null
-/*
- * Copyright © 2013 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; 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.
- */
-
-package org.altusmetrum.AltosDroid;
-
-import org.altusmetrum.altoslib_13.*;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.view.*;
-import android.widget.*;
-import android.location.Location;
-
-public class TabFlight extends AltosDroidTab {
- private TextView speed_view;
- private TextView height_view;
- private TextView max_speed_view;
- private TextView max_height_view;
- private TextView elevation_view;
- private TextView range_view;
- private TextView bearing_view;
- private TextView compass_view;
- private TextView distance_view;
- private TextView latitude_view;
- private TextView longitude_view;
- private View apogee_view;
- private TextView apogee_voltage_view;
- private TextView apogee_voltage_label;
- private GoNoGoLights apogee_lights;
- private View main_view;
- private TextView main_voltage_view;
- private TextView main_voltage_label;
- private GoNoGoLights main_lights;
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- View v = inflater.inflate(R.layout.tab_flight, container, false);
-
- speed_view = (TextView) v.findViewById(R.id.speed_value);
- height_view = (TextView) v.findViewById(R.id.height_value);
- max_speed_view = (TextView) v.findViewById(R.id.max_speed_value);
- max_height_view= (TextView) v.findViewById(R.id.max_height_value);
- elevation_view = (TextView) v.findViewById(R.id.elevation_value);
- range_view = (TextView) v.findViewById(R.id.range_value);
- bearing_view = (TextView) v.findViewById(R.id.bearing_value);
- compass_view = (TextView) v.findViewById(R.id.compass_value);
- distance_view = (TextView) v.findViewById(R.id.distance_value);
- latitude_view = (TextView) v.findViewById(R.id.lat_value);
- longitude_view = (TextView) v.findViewById(R.id.lon_value);
-
- apogee_view = v.findViewById(R.id.apogee_view);
- apogee_voltage_view = (TextView) v.findViewById(R.id.apogee_voltage_value);
- apogee_lights = new GoNoGoLights((ImageView) v.findViewById(R.id.apogee_redled),
- (ImageView) v.findViewById(R.id.apogee_greenled),
- getResources());
- apogee_voltage_label = (TextView) v.findViewById(R.id.apogee_voltage_label);
-
- main_view = v.findViewById(R.id.main_view);
- main_voltage_view = (TextView) v.findViewById(R.id.main_voltage_value);
- main_lights = new GoNoGoLights((ImageView) v.findViewById(R.id.main_redled),
- (ImageView) v.findViewById(R.id.main_greenled),
- getResources());
- main_voltage_label = (TextView) v.findViewById(R.id.main_voltage_label);
-
- return v;
- }
-
- public String tab_name() { return AltosDroid.tab_flight_name; }
-
- public void show(TelemetryState telem_state, AltosState state, AltosGreatCircle from_receiver, Location receiver) {
- if (state != null) {
- set_value(speed_view, AltosConvert.speed, 6, state.speed());
- set_value(height_view, AltosConvert.height, 6, state.height());
- set_value(max_speed_view, AltosConvert.speed, 6, state.max_speed());
- set_value(max_height_view, AltosConvert.height, 6, state.max_height());
- if (from_receiver != null) {
- elevation_view.setText(AltosDroid.number("%3.0f°", from_receiver.elevation));
- set_value(range_view, AltosConvert.distance, 6, from_receiver.range);
- bearing_view.setText(AltosDroid.number("%3.0f°", from_receiver.bearing));
- compass_view.setText(from_receiver.bearing_words(AltosGreatCircle.BEARING_LONG));
- set_value(distance_view, AltosConvert.distance, 6, from_receiver.distance);
- } else {
- elevation_view.setText("<unknown>");
- range_view.setText("<unknown>");
- bearing_view.setText("<unknown>");
- compass_view.setText("<unknown>");
- distance_view.setText("<unknown>");
- }
- if (state.gps != null) {
- latitude_view.setText(AltosDroid.pos(state.gps.lat, "N", "S"));
- longitude_view.setText(AltosDroid.pos(state.gps.lon, "E", "W"));
- }
-
- if (state.apogee_voltage == AltosLib.MISSING) {
- apogee_view.setVisibility(View.GONE);
- } else {
- apogee_voltage_view.setText(AltosDroid.number("%4.2f V", state.apogee_voltage));
- apogee_lights.set(state.apogee_voltage > 3.2, state.apogee_voltage == AltosLib.MISSING);
- apogee_view.setVisibility(View.VISIBLE);
- }
-
- if (state.main_voltage == AltosLib.MISSING) {
- main_view.setVisibility(View.GONE);
- } else {
- main_voltage_view.setText(AltosDroid.number("%4.2f V", state.main_voltage));
- main_lights.set(state.main_voltage > 3.2, state.main_voltage == AltosLib.MISSING);
- main_view.setVisibility(View.VISIBLE);
- }
- }
- }
-
-}
+++ /dev/null
-/*
- * Copyright © 2013 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; 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.
- */
-
-package org.altusmetrum.AltosDroid;
-
-import java.util.*;
-import java.io.*;
-
-import org.altusmetrum.altoslib_13.*;
-
-import android.app.Activity;
-import android.graphics.*;
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentTransaction;
-import android.view.*;
-import android.widget.*;
-import android.location.Location;
-import android.content.*;
-
-public class TabMap extends AltosDroidTab implements AltosDroidMapSourceListener {
-
- AltosLatLon here;
-
- private TextView mDistanceView;
- private TextView mBearingLabel;
- private TextView mBearingView;
- private TextView mTargetLatitudeView;
- private TextView mTargetLongitudeView;
- private TextView mReceiverLatitudeView;
- private TextView mReceiverLongitudeView;
- private AltosMapOffline map_offline;
- private AltosMapOnline map_online;
- private View view;
- private int map_source;
-
- @Override
- public void onAttach(Activity activity) {
- super.onAttach(activity);
- }
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- view = inflater.inflate(R.layout.tab_map, container, false);
- int map_source = AltosDroidPreferences.map_source();
-
- mDistanceView = (TextView)view.findViewById(R.id.distance_value);
- mBearingLabel = (TextView)view.findViewById(R.id.bearing_label);
- mBearingView = (TextView)view.findViewById(R.id.bearing_value);
- mTargetLatitudeView = (TextView)view.findViewById(R.id.target_lat_value);
- mTargetLongitudeView = (TextView)view.findViewById(R.id.target_lon_value);
- mReceiverLatitudeView = (TextView)view.findViewById(R.id.receiver_lat_value);
- mReceiverLongitudeView = (TextView)view.findViewById(R.id.receiver_lon_value);
- map_offline = (AltosMapOffline)view.findViewById(R.id.map_offline);
- map_offline.onCreateView(altos_droid);
- map_online = new AltosMapOnline(view.getContext());
- map_online.onCreateView(altos_droid);
- map_source_changed(AltosDroidPreferences.map_source());
- AltosDroidPreferences.register_map_source_listener(this);
- return view;
- }
-
- @Override
- public void onActivityCreated(Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
- if (map_online != null)
- getChildFragmentManager().beginTransaction().add(R.id.map_online, map_online.mMapFragment).commit();
- }
-
- @Override
- public void onDestroyView() {
- super.onDestroyView();
- map_offline.onDestroyView();
- map_online.onDestroyView();
- AltosDroidPreferences.unregister_map_source_listener(this);
- }
-
- public String tab_name() { return AltosDroid.tab_map_name; }
-
- private void center(double lat, double lon, double accuracy) {
- if (map_offline != null)
- map_offline.center(lat, lon, accuracy);
- if (map_online != null)
- map_online.center(lat, lon, accuracy);
- }
-
- public void show(TelemetryState telem_state, AltosState state, AltosGreatCircle from_receiver, Location receiver) {
- if (from_receiver != null) {
- String direction = AltosDroid.direction(from_receiver, receiver);
- if (direction != null) {
- mBearingLabel.setText("Direction");
- mBearingView.setText(direction);
- } else {
- mBearingLabel.setText("Bearing");
- mBearingView.setText(String.format("%3.0f°", from_receiver.bearing));
- }
- set_value(mDistanceView, AltosConvert.distance, 6, from_receiver.distance);
- } else {
- mBearingLabel.setText("Bearing");
- mBearingView.setText("");
- set_value(mDistanceView, AltosConvert.distance, 6, AltosLib.MISSING);
- }
-
- if (state != null) {
- if (state.gps != null) {
- mTargetLatitudeView.setText(AltosDroid.pos(state.gps.lat, "N", "S"));
- mTargetLongitudeView.setText(AltosDroid.pos(state.gps.lon, "E", "W"));
- }
- }
-
- if (receiver != null) {
- double accuracy;
-
- here = new AltosLatLon(receiver.getLatitude(), receiver.getLongitude());
- if (receiver.hasAccuracy())
- accuracy = receiver.getAccuracy();
- else
- accuracy = 1000;
- mReceiverLatitudeView.setText(AltosDroid.pos(here.lat, "N", "S"));
- mReceiverLongitudeView.setText(AltosDroid.pos(here.lon, "E", "W"));
- center (here.lat, here.lon, accuracy);
- }
- if (map_source == AltosDroidPreferences.MAP_SOURCE_OFFLINE) {
- if (map_offline != null)
- map_offline.show(telem_state, state, from_receiver, receiver);
- } else {
- if (map_online != null)
- map_online.show(telem_state, state, from_receiver, receiver);
- }
- }
-
- public void map_source_changed(int map_source) {
- this.map_source = map_source;
- if (map_source == AltosDroidPreferences.MAP_SOURCE_OFFLINE) {
- if (map_online != null)
- map_online.set_visible(false);
- if (map_offline != null) {
- map_offline.set_visible(true);
- map_offline.show(last_telem_state, last_state, last_from_receiver, last_receiver);
- }
- } else {
- if (map_offline != null)
- map_offline.set_visible(false);
- if (map_online != null) {
- map_online.set_visible(true);
- map_online.show(last_telem_state, last_state, last_from_receiver, last_receiver);
- }
- }
- }
-
- public TabMap() {
- }
-}
+++ /dev/null
-/*
- * Copyright © 2013 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; 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.
- */
-
-package org.altusmetrum.AltosDroid;
-
-import org.altusmetrum.altoslib_13.*;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.view.*;
-import android.widget.*;
-import android.location.Location;
-
-public class TabPad extends AltosDroidTab {
- private TextView battery_voltage_view;
- private GoNoGoLights battery_lights;
-
- private TableRow receiver_row;
- private TextView receiver_voltage_view;
- private TextView receiver_voltage_label;
- private GoNoGoLights receiver_voltage_lights;
-
- private TableRow apogee_row;
- private TextView apogee_voltage_view;
- private TextView apogee_voltage_label;
- private GoNoGoLights apogee_lights;
-
- private TableRow main_row;
- private TextView main_voltage_view;
- private TextView main_voltage_label;
- private GoNoGoLights main_lights;
-
- private TextView data_logging_view;
- private GoNoGoLights data_logging_lights;
-
- private TextView gps_locked_view;
- private GoNoGoLights gps_locked_lights;
-
- private TextView gps_ready_view;
- private GoNoGoLights gps_ready_lights;
-
- private TextView receiver_latitude_view;
- private TextView receiver_longitude_view;
- private TextView receiver_altitude_view;
-
- private TableRow[] ignite_row = new TableRow[4];
- private TextView[] ignite_voltage_view = new TextView[4];
- private TextView[] ignite_voltage_label = new TextView[4];
- private GoNoGoLights[] ignite_lights = new GoNoGoLights[4];
-
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- View v = inflater.inflate(R.layout.tab_pad, container, false);
- battery_voltage_view = (TextView) v.findViewById(R.id.battery_voltage_value);
- battery_lights = new GoNoGoLights((ImageView) v.findViewById(R.id.battery_redled),
- (ImageView) v.findViewById(R.id.battery_greenled),
- getResources());
-
- receiver_row = (TableRow) v.findViewById(R.id.receiver_row);
- receiver_voltage_view = (TextView) v.findViewById(R.id.receiver_voltage_value);
- receiver_voltage_label = (TextView) v.findViewById(R.id.receiver_voltage_label);
- receiver_voltage_lights = new GoNoGoLights((ImageView) v.findViewById(R.id.receiver_redled),
- (ImageView) v.findViewById(R.id.receiver_greenled),
- getResources());
-
- apogee_row = (TableRow) v.findViewById(R.id.apogee_row);
- apogee_voltage_view = (TextView) v.findViewById(R.id.apogee_voltage_value);
- apogee_voltage_label = (TextView) v.findViewById(R.id.apogee_voltage_label);
- apogee_lights = new GoNoGoLights((ImageView) v.findViewById(R.id.apogee_redled),
- (ImageView) v.findViewById(R.id.apogee_greenled),
- getResources());
-
- main_row = (TableRow) v.findViewById(R.id.main_row);
- main_voltage_view = (TextView) v.findViewById(R.id.main_voltage_value);
- main_voltage_label = (TextView) v.findViewById(R.id.main_voltage_label);
- main_lights = new GoNoGoLights((ImageView) v.findViewById(R.id.main_redled),
- (ImageView) v.findViewById(R.id.main_greenled),
- getResources());
-
- data_logging_view = (TextView) v.findViewById(R.id.logging_value);
- data_logging_lights = new GoNoGoLights((ImageView) v.findViewById(R.id.logging_redled),
- (ImageView) v.findViewById(R.id.logging_greenled),
- getResources());
-
- gps_locked_view = (TextView) v.findViewById(R.id.gps_locked_value);
- gps_locked_lights = new GoNoGoLights((ImageView) v.findViewById(R.id.gps_locked_redled),
- (ImageView) v.findViewById(R.id.gps_locked_greenled),
- getResources());
-
- gps_ready_view = (TextView) v.findViewById(R.id.gps_ready_value);
- gps_ready_lights = new GoNoGoLights((ImageView) v.findViewById(R.id.gps_ready_redled),
- (ImageView) v.findViewById(R.id.gps_ready_greenled),
- getResources());
-
- for (int i = 0; i < 4; i++) {
- int row_id, view_id, label_id, lights_id;
- int red_id, green_id;
- switch (i) {
- case 0:
- default:
- row_id = R.id.ignite_a_row;
- view_id = R.id.ignite_a_voltage_value;
- label_id = R.id.ignite_a_voltage_label;
- red_id = R.id.ignite_a_redled;
- green_id = R.id.ignite_a_greenled;
- break;
- case 1:
- row_id = R.id.ignite_b_row;
- view_id = R.id.ignite_b_voltage_value;
- label_id = R.id.ignite_b_voltage_label;
- red_id = R.id.ignite_b_redled;
- green_id = R.id.ignite_b_greenled;
- break;
- case 2:
- row_id = R.id.ignite_c_row;
- view_id = R.id.ignite_c_voltage_value;
- label_id = R.id.ignite_c_voltage_label;
- red_id = R.id.ignite_c_redled;
- green_id = R.id.ignite_c_greenled;
- break;
- case 3:
- row_id = R.id.ignite_d_row;
- view_id = R.id.ignite_d_voltage_value;
- label_id = R.id.ignite_d_voltage_label;
- red_id = R.id.ignite_d_redled;
- green_id = R.id.ignite_d_greenled;
- break;
- }
- ignite_row[i] = (TableRow) v.findViewById(row_id);
- ignite_voltage_view[i] = (TextView) v.findViewById(view_id);
- ignite_voltage_label[i] = (TextView) v.findViewById(label_id);
- ignite_lights[i] = new GoNoGoLights((ImageView) v.findViewById(red_id),
- (ImageView) v.findViewById(green_id),
- getResources());
- }
-
- receiver_latitude_view = (TextView) v.findViewById(R.id.receiver_lat_value);
- receiver_longitude_view = (TextView) v.findViewById(R.id.receiver_lon_value);
- receiver_altitude_view = (TextView) v.findViewById(R.id.receiver_alt_value);
- return v;
- }
-
- public String tab_name() { return AltosDroid.tab_pad_name; }
-
- public void show(TelemetryState telem_state, AltosState state, AltosGreatCircle from_receiver, Location receiver) {
- if (state != null) {
- battery_voltage_view.setText(AltosDroid.number(" %4.2f V", state.battery_voltage));
- battery_lights.set(state.battery_voltage >= AltosLib.ao_battery_good, state.battery_voltage == AltosLib.MISSING);
- if (state.apogee_voltage == AltosLib.MISSING) {
- apogee_row.setVisibility(View.GONE);
- } else {
- apogee_voltage_view.setText(AltosDroid.number(" %4.2f V", state.apogee_voltage));
- apogee_row.setVisibility(View.VISIBLE);
- }
- apogee_lights.set(state.apogee_voltage >= AltosLib.ao_igniter_good, state.apogee_voltage == AltosLib.MISSING);
- if (state.main_voltage == AltosLib.MISSING) {
- main_row.setVisibility(View.GONE);
- } else {
- main_voltage_view.setText(AltosDroid.number(" %4.2f V", state.main_voltage));
- main_row.setVisibility(View.VISIBLE);
- }
- main_lights.set(state.main_voltage >= AltosLib.ao_igniter_good, state.main_voltage == AltosLib.MISSING);
-
- int num_igniter = state.igniter_voltage == null ? 0 : state.igniter_voltage.length;
-
- for (int i = 0; i < 4; i++) {
- double voltage = i >= num_igniter ? AltosLib.MISSING : state.igniter_voltage[i];
- if (voltage == AltosLib.MISSING) {
- ignite_row[i].setVisibility(View.GONE);
- } else {
- ignite_voltage_view[i].setText(AltosDroid.number(" %4.2f V", voltage));
- ignite_row[i].setVisibility(View.VISIBLE);
- }
- ignite_lights[i].set(voltage >= AltosLib.ao_igniter_good, voltage == AltosLib.MISSING);
- }
-
- if (state.cal_data().flight != 0) {
- if (state.state() <= AltosLib.ao_flight_pad)
- data_logging_view.setText("Ready to record");
- else if (state.state() < AltosLib.ao_flight_landed)
- data_logging_view.setText("Recording data");
- else
- data_logging_view.setText("Recorded data");
- } else {
- data_logging_view.setText("Storage full");
- }
- data_logging_lights.set(state.cal_data().flight != 0, state.cal_data().flight == AltosLib.MISSING);
-
- if (state.gps != null) {
- int soln = state.gps.nsat;
- int nsat = state.gps.cc_gps_sat != null ? state.gps.cc_gps_sat.length : 0;
- gps_locked_view.setText(String.format("%d in soln, %d in view", soln, nsat));
- gps_locked_lights.set(state.gps.locked && state.gps.nsat >= 4, false);
- if (state.gps_ready)
- gps_ready_view.setText("Ready");
- else
- gps_ready_view.setText(AltosDroid.integer("Waiting %d", state.gps_waiting));
- } else
- gps_locked_lights.set(false, true);
- gps_ready_lights.set(state.gps_ready, state.gps == null);
- }
-
- if (telem_state != null) {
- if (telem_state.receiver_battery == AltosLib.MISSING) {
- receiver_row.setVisibility(View.GONE);
- } else {
- receiver_voltage_view.setText(AltosDroid.number(" %4.2f V", telem_state.receiver_battery));
- receiver_row.setVisibility(View.VISIBLE);
- }
- receiver_voltage_lights.set(telem_state.receiver_battery >= AltosLib.ao_battery_good, telem_state.receiver_battery == AltosLib.MISSING);
- }
-
- if (receiver != null) {
- double altitude = AltosLib.MISSING;
- if (receiver.hasAltitude())
- altitude = receiver.getAltitude();
- receiver_latitude_view.setText(AltosDroid.pos(receiver.getLatitude(), "N", "S"));
- receiver_longitude_view.setText(AltosDroid.pos(receiver.getLongitude(), "E", "W"));
- set_value(receiver_altitude_view, AltosConvert.height, 1, altitude);
- }
- }
-}
+++ /dev/null
-/*
- * Copyright © 2013 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; 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.
- */
-
-package org.altusmetrum.AltosDroid;
-
-import org.altusmetrum.altoslib_13.*;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.TextView;
-import android.location.Location;
-
-public class TabRecover extends AltosDroidTab {
- private TextView mBearingView;
- private TextView mDirectionView;
- private TextView mDistanceView;
- private TextView mTargetLatitudeView;
- private TextView mTargetLongitudeView;
- private TextView mReceiverLatitudeView;
- private TextView mReceiverLongitudeView;
- private TextView mMaxHeightView;
- private TextView mMaxSpeedView;
- private TextView mMaxAccelView;
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- View v = inflater.inflate(R.layout.tab_recover, container, false);
-
- mBearingView = (TextView) v.findViewById(R.id.bearing_value);
- mDirectionView = (TextView) v.findViewById(R.id.direction_value);
- mDistanceView = (TextView) v.findViewById(R.id.distance_value);
- mTargetLatitudeView = (TextView) v.findViewById(R.id.target_lat_value);
- mTargetLongitudeView = (TextView) v.findViewById(R.id.target_lon_value);
- mReceiverLatitudeView = (TextView) v.findViewById(R.id.receiver_lat_value);
- mReceiverLongitudeView = (TextView) v.findViewById(R.id.receiver_lon_value);
- mMaxHeightView = (TextView) v.findViewById(R.id.max_height_value);
- mMaxSpeedView = (TextView) v.findViewById(R.id.max_speed_value);
- mMaxAccelView = (TextView) v.findViewById(R.id.max_accel_value);
-
- return v;
- }
-
- public String tab_name() { return AltosDroid.tab_recover_name; }
-
- public void show(TelemetryState telem_state, AltosState state, AltosGreatCircle from_receiver, Location receiver) {
- if (from_receiver != null) {
- mBearingView.setText(String.format("%3.0f°", from_receiver.bearing));
- set_value(mDistanceView, AltosConvert.distance, 6, from_receiver.distance);
- String direction = AltosDroid.direction(from_receiver, receiver);
- if (direction == null)
- mDirectionView.setText("");
- else
- mDirectionView.setText(direction);
- }
- if (state != null && state.gps != null) {
- mTargetLatitudeView.setText(AltosDroid.pos(state.gps.lat, "N", "S"));
- mTargetLongitudeView.setText(AltosDroid.pos(state.gps.lon, "E", "W"));
- }
-
- if (receiver != null) {
- mReceiverLatitudeView.setText(AltosDroid.pos(receiver.getLatitude(), "N", "S"));
- mReceiverLongitudeView.setText(AltosDroid.pos(receiver.getLongitude(), "E", "W"));
- }
-
- if (state != null) {
- set_value(mMaxHeightView, AltosConvert.height, 6, state.max_height());
- set_value(mMaxAccelView, AltosConvert.accel, 6, state.max_acceleration());
- set_value(mMaxSpeedView, AltosConvert.speed, 6, state.max_speed());
- }
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.altusmetrum.AltosDroid;
-
-import java.util.ArrayList;
-
-import android.content.Context;
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentTransaction;
-import android.support.v4.app.FragmentActivity;
-import android.support.v4.app.FragmentPagerAdapter;
-import android.support.v4.view.ViewPager;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.TabHost;
-import android.widget.TabWidget;
-
-/**
- * This is a helper class that implements the management of tabs and all
- * details of connecting a ViewPager with associated TabHost. It relies on a
- * trick. Normally a tab host has a simple API for supplying a View or
- * Intent that each tab will show. This is not sufficient for switching
- * between pages. So instead we make the content part of the tab host
- * 0dp high (it is not shown) and the TabsAdapter supplies its own dummy
- * view to show as the tab content. It listens to changes in tabs, and takes
- * care of switch to the correct paged in the ViewPager whenever the selected
- * tab changes.
- */
-public class TabsAdapter extends FragmentPagerAdapter
- implements TabHost.OnTabChangeListener, ViewPager.OnPageChangeListener {
- private final Context mContext;
- private final TabHost mTabHost;
- private final ViewPager mViewPager;
- private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
- private int position;
-
- static class TabInfo {
- private final String tag;
- private final Class<?> clss;
- private final Bundle args;
- private Fragment fragment;
-
- TabInfo(String _tag, Class<?> _class, Bundle _args) {
- tag = _tag;
- clss = _class;
- args = _args;
- }
- }
-
- static class DummyTabFactory implements TabHost.TabContentFactory {
- private final Context mContext;
-
- public DummyTabFactory(Context context) {
- mContext = context;
- }
-
- public View createTabContent(String tag) {
- View v = new View(mContext);
- v.setMinimumWidth(0);
- v.setMinimumHeight(0);
- return v;
- }
- }
-
- public TabsAdapter(FragmentActivity activity, TabHost tabHost, ViewPager pager) {
- super(activity.getSupportFragmentManager());
- mContext = activity;
- mTabHost = tabHost;
- mViewPager = pager;
- mTabHost.setOnTabChangedListener(this);
- mViewPager.setAdapter(this);
- mViewPager.setOnPageChangeListener(this);
- }
-
- public void addTab(TabHost.TabSpec tabSpec, Class<?> clss, Bundle args) {
- tabSpec.setContent(new DummyTabFactory(mContext));
- String tag = tabSpec.getTag();
-
- TabInfo info = new TabInfo(tag, clss, args);
- mTabs.add(info);
- mTabHost.addTab(tabSpec);
- notifyDataSetChanged();
- }
-
- @Override
- public int getCount() {
- return mTabs.size();
- }
-
- @Override
- public Fragment getItem(int position) {
- TabInfo info = mTabs.get(position);
- AltosDebug.debug("TabsAdapter.getItem(%d)", position);
- info.fragment = Fragment.instantiate(mContext, info.clss.getName(), info.args);
- return info.fragment;
- }
-
- public Fragment currentItem() {
- TabInfo info = mTabs.get(position);
- return info.fragment;
- }
-
- public void onTabChanged(String tabId) {
- AltosDroidTab prev_frag = (AltosDroidTab) mTabs.get(position).fragment;
-
- position = mTabHost.getCurrentTab();
-
- AltosDroidTab cur_frag = (AltosDroidTab) mTabs.get(position).fragment;
-
- if (prev_frag != cur_frag) {
- if (prev_frag != null) {
- prev_frag.set_visible(false);
- }
- }
- if (cur_frag != null) {
- cur_frag.set_visible(true);
- }
- AltosDebug.debug("TabsAdapter.onTabChanged(%s) = %d", tabId, position);
- mViewPager.setCurrentItem(position);
- }
-
- public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
- }
-
- public void onPageSelected(int position) {
- // Unfortunately when TabHost changes the current tab, it kindly
- // also takes care of putting focus on it when not in touch mode.
- // The jerk.
- // This hack tries to prevent this from pulling focus out of our
- // ViewPager.
- TabWidget widget = mTabHost.getTabWidget();
- int oldFocusability = widget.getDescendantFocusability();
- widget.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
- mTabHost.setCurrentTab(position);
- widget.setDescendantFocusability(oldFocusability);
- }
-
- public void onPageScrollStateChanged(int state) {
- }
-}
+++ /dev/null
-package org.altusmetrum.AltosDroid;
-
-import org.altusmetrum.altoslib_13.*;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Environment;
-
-public class TelemetryLogger {
- private Context context = null;
- private AltosLink link = null;
- private AltosLog logger = null;
-
- private BroadcastReceiver mExternalStorageReceiver;
-
- public TelemetryLogger(Context in_context, AltosLink in_link) {
- context = in_context;
- link = in_link;
-
- startWatchingExternalStorage();
- }
-
- public void stop() {
- stopWatchingExternalStorage();
- close();
- }
-
- private void close() {
- if (logger != null) {
- AltosDebug.debug("Shutting down Telemetry Logging");
- logger.close();
- logger = null;
- }
- }
-
- void handleExternalStorageState() {
- String state = Environment.getExternalStorageState();
- if (Environment.MEDIA_MOUNTED.equals(state)) {
- if (logger == null) {
- AltosDebug.debug("Starting up Telemetry Logging");
- logger = new AltosLog(link);
- }
- } else {
- AltosDebug.debug("External Storage not present - stopping");
- close();
- }
- }
-
- void startWatchingExternalStorage() {
- mExternalStorageReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- handleExternalStorageState();
- }
- };
- IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_MEDIA_MOUNTED);
- filter.addAction(Intent.ACTION_MEDIA_REMOVED);
- context.registerReceiver(mExternalStorageReceiver, filter);
- handleExternalStorageState();
- }
-
- void stopWatchingExternalStorage() {
- context.unregisterReceiver(mExternalStorageReceiver);
- }
-
-}
+++ /dev/null
-/*
- * 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; 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.
- */
-
-
-package org.altusmetrum.AltosDroid;
-
-import java.text.*;
-import java.io.*;
-import java.util.*;
-import java.util.concurrent.*;
-import android.os.Handler;
-
-import org.altusmetrum.altoslib_13.*;
-
-
-public class TelemetryReader extends Thread {
-
- int crc_errors;
-
- Handler handler;
-
- AltosLink link;
-
- LinkedBlockingQueue<AltosLine> telemQueue;
-
- public AltosTelemetry 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);
- return telem;
- }
-
- public void close() {
- link.remove_monitor(telemQueue);
- link = null;
- telemQueue.clear();
- telemQueue = null;
- }
-
- public void run() {
- try {
- AltosDebug.debug("starting loop");
- while (telemQueue != null) {
- try {
- AltosTelemetry telem = read();
- telem.set_frequency(link.frequency);
- handler.obtainMessage(TelemetryService.MSG_TELEMETRY, telem).sendToTarget();
- } catch (ParseException pp) {
- AltosDebug.error("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) {
- AltosDebug.error("IO exception in telemetry reader");
- handler.obtainMessage(TelemetryService.MSG_DISCONNECTED, link).sendToTarget();
- } finally {
- close();
- }
- }
-
- public TelemetryReader (AltosLink in_link, Handler in_handler) {
- AltosDebug.debug("connected TelemetryReader create started");
- link = in_link;
- handler = in_handler;
-
- telemQueue = new LinkedBlockingQueue<AltosLine>();
- link.add_monitor(telemQueue);
- link.set_telemetry(AltosLib.ao_telemetry_standard);
-
- AltosDebug.debug("connected TelemetryReader created");
- }
-}
+++ /dev/null
-/*
- * 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; 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.
- */
-
-package org.altusmetrum.AltosDroid;
-
-import java.lang.ref.WeakReference;
-import java.util.concurrent.TimeoutException;
-import java.util.*;
-
-import android.app.Notification;
-//import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.app.Service;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothAdapter;
-import android.hardware.usb.*;
-import android.content.Intent;
-import android.content.Context;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.Handler;
-import android.os.Message;
-import android.os.Messenger;
-import android.os.RemoteException;
-import android.os.Looper;
-import android.widget.Toast;
-import android.location.Criteria;
-
-import org.altusmetrum.altoslib_13.*;
-
-public class TelemetryService extends Service implements AltosIdleMonitorListener {
-
- static final int MSG_REGISTER_CLIENT = 1;
- static final int MSG_UNREGISTER_CLIENT = 2;
- static final int MSG_CONNECT = 3;
- static final int MSG_OPEN_USB = 4;
- static final int MSG_CONNECTED = 5;
- static final int MSG_CONNECT_FAILED = 6;
- static final int MSG_DISCONNECTED = 7;
- static final int MSG_TELEMETRY = 8;
- static final int MSG_SETFREQUENCY = 9;
- static final int MSG_CRC_ERROR = 10;
- static final int MSG_SETBAUD = 11;
- static final int MSG_DISCONNECT = 12;
- static final int MSG_DELETE_SERIAL = 13;
- static final int MSG_BLUETOOTH_ENABLED = 14;
- static final int MSG_MONITOR_IDLE_START= 15;
- static final int MSG_MONITOR_IDLE_STOP = 16;
- static final int MSG_REBOOT = 17;
- static final int MSG_IGNITER_QUERY = 18;
- static final int MSG_IGNITER_FIRE = 19;
-
- // Unique Identification Number for the Notification.
- // We use it on Notification start, and to cancel it.
- private int NOTIFICATION = R.string.telemetry_service_label;
- //private NotificationManager mNM;
-
- ArrayList<Messenger> clients = new ArrayList<Messenger>(); // Keeps track of all current registered clients.
- final Handler handler = new IncomingHandler(this);
- final Messenger messenger = new Messenger(handler); // Target we publish for clients to send messages to IncomingHandler.
-
- // Name of the connected device
- DeviceAddress address;
- private AltosDroidLink altos_link = null;
- private TelemetryReader telemetry_reader = null;
- private TelemetryLogger telemetry_logger = null;
-
- // Local Bluetooth adapter
- private BluetoothAdapter bluetooth_adapter = null;
-
- // Last data seen; send to UI when it starts
- private TelemetryState telemetry_state;
-
- // Idle monitor if active
- AltosIdleMonitor idle_monitor = null;
-
- // Igniter bits
- AltosIgnite ignite = null;
- boolean ignite_running;
-
- // Handler of incoming messages from clients.
- static class IncomingHandler extends Handler {
- private final WeakReference<TelemetryService> service;
- IncomingHandler(TelemetryService s) { service = new WeakReference<TelemetryService>(s); }
-
- @Override
- public void handleMessage(Message msg) {
- DeviceAddress address;
-
- TelemetryService s = service.get();
- AltosDroidLink bt = null;
- if (s == null)
- return;
-
- switch (msg.what) {
-
- /* Messages from application */
- case MSG_REGISTER_CLIENT:
- s.add_client(msg.replyTo);
- break;
- case MSG_UNREGISTER_CLIENT:
- s.remove_client(msg.replyTo);
- break;
- case MSG_CONNECT:
- AltosDebug.debug("Connect command received");
- address = (DeviceAddress) msg.obj;
- AltosDroidPreferences.set_active_device(address);
- s.start_altos_bluetooth(address, false);
- break;
- case MSG_OPEN_USB:
- AltosDebug.debug("Open USB command received");
- UsbDevice device = (UsbDevice) msg.obj;
- s.start_usb(device);
- break;
- case MSG_DISCONNECT:
- AltosDebug.debug("Disconnect command received");
- s.address = null;
- if (!(Boolean) msg.obj)
- AltosDroidPreferences.set_active_device(null);
- s.disconnect(true);
- break;
- case MSG_DELETE_SERIAL:
- AltosDebug.debug("Delete Serial command received");
- s.delete_serial((Integer) msg.obj);
- break;
- case MSG_SETFREQUENCY:
- AltosDebug.debug("MSG_SETFREQUENCY");
- s.telemetry_state.frequency = (Double) msg.obj;
- if (s.telemetry_state.connect == TelemetryState.CONNECT_CONNECTED) {
- try {
- s.altos_link.set_radio_frequency(s.telemetry_state.frequency);
- s.altos_link.save_frequency();
- } catch (InterruptedException e) {
- } catch (TimeoutException e) {
- }
- }
- s.send_to_clients();
- break;
- case MSG_SETBAUD:
- AltosDebug.debug("MSG_SETBAUD");
- s.telemetry_state.telemetry_rate = (Integer) msg.obj;
- if (s.telemetry_state.connect == TelemetryState.CONNECT_CONNECTED) {
- s.altos_link.set_telemetry_rate(s.telemetry_state.telemetry_rate);
- s.altos_link.save_telemetry_rate();
- }
- s.send_to_clients();
- break;
-
- /*
- *Messages from AltosBluetooth
- */
- case MSG_CONNECTED:
- AltosDebug.debug("MSG_CONNECTED");
- bt = (AltosDroidLink) msg.obj;
-
- if (bt != s.altos_link) {
- AltosDebug.debug("Stale message");
- break;
- }
- AltosDebug.debug("Connected to device");
- try {
- s.connected();
- } catch (InterruptedException ie) {
- }
- break;
- case MSG_CONNECT_FAILED:
- AltosDebug.debug("MSG_CONNECT_FAILED");
- bt = (AltosDroidLink) msg.obj;
-
- if (bt != s.altos_link) {
- AltosDebug.debug("Stale message");
- break;
- }
- if (s.address != null) {
- AltosDebug.debug("Connection failed... retrying");
- s.start_altos_bluetooth(s.address, true);
- } else {
- s.disconnect(true);
- }
- break;
- case MSG_DISCONNECTED:
-
- /* This can be sent by either AltosDroidLink or TelemetryReader */
- AltosDebug.debug("MSG_DISCONNECTED");
- bt = (AltosDroidLink) msg.obj;
-
- if (bt != s.altos_link) {
- AltosDebug.debug("Stale message");
- break;
- }
- if (s.address != null) {
- AltosDebug.debug("Connection lost... retrying");
- s.start_altos_bluetooth(s.address, true);
- } else {
- s.disconnect(true);
- }
- break;
-
- /*
- * Messages from TelemetryReader
- */
- case MSG_TELEMETRY:
- s.telemetry((AltosTelemetry) msg.obj);
- break;
- case MSG_CRC_ERROR:
- // forward crc error messages
- s.telemetry_state.crc_errors = (Integer) msg.obj;
- s.send_to_clients();
- break;
- case MSG_BLUETOOTH_ENABLED:
- AltosDebug.debug("TelemetryService notes that BT is now enabled");
- address = AltosDroidPreferences.active_device();
- if (address != null && !address.address.startsWith("USB"))
- s.start_altos_bluetooth(address, false);
- break;
- case MSG_MONITOR_IDLE_START:
- AltosDebug.debug("start monitor idle");
- s.start_idle_monitor();
- break;
- case MSG_MONITOR_IDLE_STOP:
- AltosDebug.debug("stop monitor idle");
- s.stop_idle_monitor();
- break;
- case MSG_REBOOT:
- AltosDebug.debug("reboot");
- s.reboot_remote();
- break;
- case MSG_IGNITER_QUERY:
- AltosDebug.debug("igniter query");
- s.igniter_query(msg.replyTo);
- break;
- case MSG_IGNITER_FIRE:
- AltosDebug.debug("igniter fire");
- s.igniter_fire((String) msg.obj);
- break;
- default:
- super.handleMessage(msg);
- }
- }
- }
-
- /* Handle telemetry packet
- */
- private void telemetry(AltosTelemetry telem) {
- AltosState state;
-
- if (telemetry_state.states.containsKey(telem.serial()))
- state = telemetry_state.states.get(telem.serial());
- else
- state = new AltosState(new AltosCalData());
- telem.provide_data(state);
- telemetry_state.states.put(telem.serial(), state);
- telemetry_state.quiet = false;
- if (state != null) {
- AltosPreferences.set_state(state,telem.serial());
- }
- send_to_clients();
- }
-
- /* Construct the message to deliver to clients
- */
- private Message message() {
- if (telemetry_state == null)
- AltosDebug.debug("telemetry_state null!");
- if (telemetry_state.states == null)
- AltosDebug.debug("telemetry_state.states null!");
- return Message.obtain(null, AltosDroid.MSG_STATE, telemetry_state);
- }
-
- /* A new friend has connected
- */
- private void add_client(Messenger client) {
-
- clients.add(client);
- AltosDebug.debug("Client bound to service");
-
- /* On connect, send the current state to the new client
- */
- send_to_client(client);
- send_idle_mode_to_client(client);
-
- /* If we've got an address from a previous session, then
- * go ahead and try to reconnect to the device
- */
- if (address != null && telemetry_state.connect == TelemetryState.CONNECT_DISCONNECTED) {
- AltosDebug.debug("Reconnecting now...");
- start_altos_bluetooth(address, false);
- }
- }
-
- /* A client has disconnected, clean up
- */
- private void remove_client(Messenger client) {
- clients.remove(client);
- AltosDebug.debug("Client unbound from service");
-
- /* When the list of clients is empty, stop the service if
- * we have no current telemetry source
- */
-
- if (clients.isEmpty() && telemetry_state.connect == TelemetryState.CONNECT_DISCONNECTED) {
- AltosDebug.debug("No clients, no connection. Stopping\n");
- stopSelf();
- }
- }
-
- private void send_to_client(Messenger client) {
- Message m = message();
- try {
- client.send(m);
- } catch (RemoteException e) {
- AltosDebug.error("Client %s disappeared", client.toString());
- remove_client(client);
- }
- }
-
- private void send_to_clients() {
- for (Messenger client : clients)
- send_to_client(client);
- }
-
- private void send_idle_mode_to_client(Messenger client) {
- Message m = Message.obtain(null, AltosDroid.MSG_IDLE_MODE, idle_monitor != null);
- try {
- client.send(m);
- } catch (RemoteException e) {
- AltosDebug.error("Client %s disappeared", client.toString());
- remove_client(client);
- }
- }
-
- private void send_idle_mode_to_clients() {
- for (Messenger client : clients)
- send_idle_mode_to_client(client);
- }
-
- private void telemetry_start() {
- if (telemetry_reader == null && idle_monitor == null && !ignite_running) {
- telemetry_reader = new TelemetryReader(altos_link, handler);
- telemetry_reader.start();
- }
- }
-
- private void telemetry_stop() {
- if (telemetry_reader != null) {
- AltosDebug.debug("disconnect(): stopping TelemetryReader");
- telemetry_reader.interrupt();
- try {
- telemetry_reader.join();
- } catch (InterruptedException e) {
- }
- telemetry_reader = null;
- }
- }
-
- private void disconnect(boolean notify) {
- AltosDebug.debug("disconnect(): begin");
-
- telemetry_state.connect = TelemetryState.CONNECT_DISCONNECTED;
- telemetry_state.address = null;
-
- if (idle_monitor != null)
- stop_idle_monitor();
-
- if (altos_link != null)
- altos_link.closing();
-
- stop_receiver_voltage_timer();
-
- telemetry_stop();
- if (telemetry_logger != null) {
- AltosDebug.debug("disconnect(): stopping TelemetryLogger");
- telemetry_logger.stop();
- telemetry_logger = null;
- }
- if (altos_link != null) {
- AltosDebug.debug("disconnect(): stopping AltosDroidLink");
- altos_link.close();
- altos_link = null;
- ignite = null;
- }
- telemetry_state.config = null;
- if (notify) {
- AltosDebug.debug("disconnect(): send message to clients");
- send_to_clients();
- if (clients.isEmpty()) {
- AltosDebug.debug("disconnect(): no clients, terminating");
- stopSelf();
- }
- }
- }
-
- private void start_usb(UsbDevice device) {
- AltosUsb d = new AltosUsb(this, device, handler);
-
- if (d != null) {
- disconnect(false);
- altos_link = d;
- try {
- connected();
- } catch (InterruptedException ie) {
- }
- }
- }
-
- private void delete_serial(int serial) {
- telemetry_state.states.remove((Integer) serial);
- AltosPreferences.remove_state(serial);
- send_to_clients();
- }
-
- private void start_altos_bluetooth(DeviceAddress address, boolean pause) {
- if (bluetooth_adapter == null || !bluetooth_adapter.isEnabled())
- return;
-
- disconnect(false);
-
- // Get the BluetoothDevice object
- BluetoothDevice device = bluetooth_adapter.getRemoteDevice(address.address);
-
- this.address = address;
- AltosDebug.debug("start_altos_bluetooth(): Connecting to %s (%s)", device.getName(), device.getAddress());
- altos_link = new AltosBluetooth(device, handler, pause);
- telemetry_state.connect = TelemetryState.CONNECT_CONNECTING;
- telemetry_state.address = address;
- send_to_clients();
- }
-
- private void start_idle_monitor() {
- if (altos_link != null && idle_monitor == null) {
- telemetry_stop();
- idle_monitor = new AltosIdleMonitor(this, altos_link, true, false);
- idle_monitor.set_callsign(AltosPreferences.callsign());
- idle_monitor.start();
- send_idle_mode_to_clients();
- }
- }
-
- private void stop_idle_monitor() {
- if (idle_monitor != null) {
- try {
- idle_monitor.abort();
- } catch (InterruptedException ie) {
- }
- idle_monitor = null;
- telemetry_start();
- send_idle_mode_to_clients();
- }
- }
-
- private void reboot_remote() {
- if (altos_link != null) {
- stop_idle_monitor();
- try {
- altos_link.start_remote();
- altos_link.printf("r eboot\n");
- altos_link.flush_output();
- } catch (TimeoutException te) {
- } catch (InterruptedException ie) {
- } finally {
- try {
- altos_link.stop_remote();
- } catch (InterruptedException ie) {
- }
- }
- }
- }
-
- private void ensure_ignite() {
- if (ignite == null)
- ignite = new AltosIgnite(altos_link, true, false);
- }
-
- private synchronized void igniter_query(Messenger client) {
- ensure_ignite();
- HashMap<String,Integer> status_map = null;
- ignite_running = true;
- try {
- stop_idle_monitor();
- try {
- status_map = ignite.status();
- } catch (InterruptedException ie) {
- AltosDebug.debug("ignite.status interrupted");
- } catch (TimeoutException te) {
- AltosDebug.debug("ignite.status timeout");
- }
- } finally {
- ignite_running = false;
- }
- Message m = Message.obtain(null, AltosDroid.MSG_IGNITER_STATUS, status_map);
- try {
- client.send(m);
- } catch (RemoteException e) {
- }
- }
-
- private synchronized void igniter_fire(String igniter) {
- ensure_ignite();
- ignite_running = true;
- stop_idle_monitor();
- try {
- ignite.fire(igniter);
- } catch (InterruptedException ie) {
- } finally {
- ignite_running = false;
- }
- }
-
- // Timer for receiver battery voltage monitoring
- Timer receiver_voltage_timer;
-
- private void update_receiver_voltage() {
- if (altos_link != null && idle_monitor == null && !ignite_running) {
- try {
- double voltage = altos_link.monitor_battery();
- telemetry_state.receiver_battery = voltage;
- send_to_clients();
- } catch (InterruptedException ie) {
- }
- }
- }
-
- private void stop_receiver_voltage_timer() {
- if (receiver_voltage_timer != null) {
- receiver_voltage_timer.cancel();
- receiver_voltage_timer.purge();
- receiver_voltage_timer = null;
- }
- }
-
- private void start_receiver_voltage_timer() {
- if (receiver_voltage_timer == null && altos_link.has_monitor_battery()) {
- receiver_voltage_timer = new Timer();
- receiver_voltage_timer.scheduleAtFixedRate(new TimerTask() { public void run() {update_receiver_voltage();}}, 1000L, 10000L);
- }
- }
-
- private void connected() throws InterruptedException {
- AltosDebug.debug("connected top");
- AltosDebug.check_ui("connected\n");
- try {
- if (altos_link == null)
- throw new InterruptedException("no bluetooth");
- telemetry_state.config = altos_link.config_data();
- altos_link.set_radio_frequency(telemetry_state.frequency);
- altos_link.set_telemetry_rate(telemetry_state.telemetry_rate);
- } catch (TimeoutException e) {
- // If this timed out, then we really want to retry it, but
- // probably safer to just retry the connection from scratch.
- AltosDebug.debug("connected timeout");
- if (address != null) {
- AltosDebug.debug("connected timeout, retrying");
- start_altos_bluetooth(address, true);
- } else {
- handler.obtainMessage(MSG_CONNECT_FAILED).sendToTarget();
- disconnect(true);
- }
- return;
- }
-
- AltosDebug.debug("connected bluetooth configured");
- telemetry_state.connect = TelemetryState.CONNECT_CONNECTED;
- telemetry_state.address = address;
-
- telemetry_start();
-
- AltosDebug.debug("connected TelemetryReader started");
-
- telemetry_logger = new TelemetryLogger(this, altos_link);
-
- start_receiver_voltage_timer();
-
- AltosDebug.debug("Notify UI of connection");
-
- send_to_clients();
- }
-
-
- @Override
- public void onCreate() {
-
- AltosDebug.init(this);
-
- // Initialise preferences
- AltosDroidPreferences.init(this);
-
- // Get local Bluetooth adapter
- bluetooth_adapter = BluetoothAdapter.getDefaultAdapter();
-
- telemetry_state = new TelemetryState();
-
- // Create a reference to the NotificationManager so that we can update our notifcation text later
- //mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
-
- telemetry_state.connect = TelemetryState.CONNECT_DISCONNECTED;
- telemetry_state.address = null;
-
- /* Pull the saved state information out of the preferences database
- */
- ArrayList<Integer> serials = AltosPreferences.list_states();
-
- telemetry_state.latest_serial = AltosPreferences.latest_state();
-
- telemetry_state.quiet = true;
-
- AltosDebug.debug("latest serial %d\n", telemetry_state.latest_serial);
-
- for (int serial : serials) {
- AltosState saved_state = AltosPreferences.state(serial);
- if (saved_state != null) {
- if (telemetry_state.latest_serial == 0)
- telemetry_state.latest_serial = serial;
-
- AltosDebug.debug("recovered old state serial %d flight %d",
- serial,
- saved_state.cal_data().flight);
- if (saved_state.gps != null)
- AltosDebug.debug("\tposition %f,%f",
- saved_state.gps.lat,
- saved_state.gps.lon);
- telemetry_state.states.put(serial, saved_state);
- } else {
- AltosDebug.debug("Failed to recover state for %d", serial);
- AltosPreferences.remove_state(serial);
- }
- }
- }
-
- @Override
- public int onStartCommand(Intent intent, int flags, int startId) {
- AltosDebug.debug("Received start id %d: %s", startId, intent);
-
- CharSequence text = getText(R.string.telemetry_service_started);
-
- // Create notification to be displayed while the service runs
- Notification notification = new Notification(R.drawable.am_status_c, text, 0);
-
- // The PendingIntent to launch our activity if the user selects this notification
- PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
- new Intent(this, AltosDroid.class), 0);
-
- // Set the info for the views that show in the notification panel.
- notification.setLatestEventInfo(this, getText(R.string.telemetry_service_label), text, contentIntent);
-
- // Set the notification to be in the "Ongoing" section.
- notification.flags |= Notification.FLAG_ONGOING_EVENT;
-
- // Move us into the foreground.
- startForeground(NOTIFICATION, notification);
-
- /* Start bluetooth if we don't have a connection already */
- if (intent != null &&
- (telemetry_state.connect == TelemetryState.CONNECT_NONE ||
- telemetry_state.connect == TelemetryState.CONNECT_DISCONNECTED))
- {
- String action = intent.getAction();
-
- if (action.equals(AltosDroid.ACTION_BLUETOOTH)) {
- DeviceAddress address = AltosDroidPreferences.active_device();
- if (address != null && !address.address.startsWith("USB"))
- start_altos_bluetooth(address, false);
- }
- }
-
- // We want this service to continue running until it is explicitly
- // stopped, so return sticky.
- return START_STICKY;
- }
-
- @Override
- public void onDestroy() {
-
- // Stop the bluetooth Comms threads
- disconnect(true);
-
- // Demote us from the foreground, and cancel the persistent notification.
- stopForeground(true);
-
- // Tell the user we stopped.
- Toast.makeText(this, R.string.telemetry_service_stopped, Toast.LENGTH_SHORT).show();
- }
-
- @Override
- public IBinder onBind(Intent intent) {
- return messenger.getBinder();
- }
-
- /* AltosIdleMonitorListener */
- public void update(AltosState state, AltosListenerState listener_state) {
- telemetry_state.states.put(state.cal_data().serial, state);
- telemetry_state.receiver_battery = listener_state.battery;
- send_to_clients();
- }
-
- public void failed() {
- }
-
- public void error(String reason) {
- stop_idle_monitor();
- }
-}
+++ /dev/null
-/*
- * 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; 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.
- */
-
-package org.altusmetrum.AltosDroid;
-
-import java.util.*;
-import org.altusmetrum.altoslib_13.*;
-import android.location.Location;
-
-public class TelemetryState {
- public static final int CONNECT_NONE = 0;
- public static final int CONNECT_DISCONNECTED = 1;
- public static final int CONNECT_CONNECTING = 2;
- public static final int CONNECT_CONNECTED = 3;
-
- int connect;
- DeviceAddress address;
- AltosConfigData config;
- int crc_errors;
- double receiver_battery;
- double frequency;
- int telemetry_rate;
-
- boolean quiet;
-
- HashMap<Integer,AltosState> states;
-
- int latest_serial;
-
- public TelemetryState() {
- connect = CONNECT_NONE;
- config = null;
- states = new HashMap<Integer,AltosState>();
- crc_errors = 0;
- receiver_battery = AltosLib.MISSING;
- frequency = AltosPreferences.frequency(0);
- telemetry_rate = AltosPreferences.telemetry_rate(0);
- }
-}
return false;
if (product.startsWith("TeleMetrum-v2"))
return false;
+ if (product.startsWith("TeleMetrum-v3"))
+ return false;
if (product.startsWith("EasyMega"))
return false;
return true;
if (product != null) {
if (product.startsWith("EasyMega-v2"))
return true;
+ if (product.startsWith("TeleMetrum-v3"))
+ return true;
}
throw new AltosUnknownProduct(product);
}
if (product != null) {
if (product.startsWith("EasyMega-v2"))
return AltosAdxl375.X_AXIS;
+ if (product.startsWith("TeleMetrum-v3"))
+ return AltosAdxl375.X_AXIS;
}
throw new AltosUnknownProduct(product);
}
this.frequency = frequency;
}
+ public void set_avoid_duplicate_files() {
+ }
+
/* Called after all records are captured */
public void finish() {
}
class AltosEepromNameData extends AltosDataListener {
AltosGPS gps = null;
+ boolean avoid_duplicate_files = false;
+
public void set_rssi(int rssi, int status) { }
public void set_received_time(long received_time) { }
public void set_apogee_voltage(double volts) { }
public void set_main_voltage(double volts) { }
+ public void set_avoid_duplicate_files() {
+ avoid_duplicate_files = true;
+ }
+
public void set_gps(AltosGPS gps) {
super.set_gps(gps);
if (gps != null &&
private AltosFile MakeFile(int serial, int flight, AltosEepromNameData name_data) throws IOException {
AltosFile eeprom_name;
- if (name_data.gps != null) {
- AltosGPS gps = name_data.gps;
- eeprom_name = new AltosFile(gps.year, gps.month, gps.day,
- serial, flight, "eeprom");
- } else
- eeprom_name = new AltosFile(serial, flight, "eeprom");
+ for (;;) {
+ if (name_data.gps != null) {
+ AltosGPS gps = name_data.gps;
+ eeprom_name = new AltosFile(gps.year, gps.month, gps.day,
+ serial, flight, "eeprom");
+ } else
+ eeprom_name = new AltosFile(serial, flight, "eeprom");
+ if (!name_data.avoid_duplicate_files)
+ break;
+ if (!eeprom_name.exists())
+ break;
+ flight++;
+ }
return eeprom_name;
}
return set.cal_data();
}
+ public boolean valid() {
+ return set.valid();
+ }
+
public void capture_series(AltosDataListener series) {
set.capture_series(series);
}
case AltosLib.AO_LOG_FORMAT_TELEMEGA_OLD:
return mag_y();
case AltosLib.AO_LOG_FORMAT_EASYMEGA_2:
- return mag_y();
+ return mag_x();
default:
return AltosLib.MISSING;
}
--- /dev/null
+/*
+ * Copyright © 2019 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.
+ */
+
+package org.altusmetrum.altoslib_13;
+
+public class AltosEepromRecordMicroPeak2 extends AltosEepromRecord {
+ public static final int record_length = 2;
+
+ private static final int PA_GROUND_OFFSET = 0;
+ private static final int PA_MIN_OFFSET = 4;
+ private static final int N_SAMPLES_OFFSET = 8;
+ private static final int STARTING_LOG_OFFSET = 10;
+
+ private static final int LOG_ID_MICROPEAK = 0;
+ private static final int LOG_ID_MICROKITE = 1;
+ private static final int LOG_ID_MICROPEAK2 = 2;
+
+ private int value16(int o) {
+ return eeprom.data16(o);
+ }
+
+ private int value32(int o) {
+ return eeprom.data32(o);
+ }
+
+ public int cmd() {
+ if (start == 0)
+ return AltosLib.AO_LOG_FLIGHT;
+ return AltosLib.AO_LOG_SENSOR;
+ }
+
+ private int pa_ground() {
+ return value32(PA_GROUND_OFFSET);
+ }
+
+ private int pa_min() {
+ return value32(PA_MIN_OFFSET);
+ }
+
+ private int log_id() {
+ return value16(N_SAMPLES_OFFSET) >> 12;
+ }
+
+ private int n_samples() {
+ return value16(N_SAMPLES_OFFSET) & 0xfff;
+ }
+
+ private int ticks_per_sample() {
+ int log_id = log_id();
+
+ if (log_id == LOG_ID_MICROPEAK)
+ return 2;
+ if (log_id == LOG_ID_MICROKITE)
+ return 200;
+ if (log_id == LOG_ID_MICROPEAK2)
+ return 10;
+ return 1;
+ }
+
+ public int tick() {
+ if (start <= STARTING_LOG_OFFSET)
+ return 0;
+ return ((start - STARTING_LOG_OFFSET) / 2) * ticks_per_sample();
+ }
+
+ public double ticks_per_sec() {
+ int log_id = log_id();
+
+ if (log_id == LOG_ID_MICROPEAK)
+ return 1000.0/96.0;
+ if (log_id == LOG_ID_MICROKITE)
+ return 1000 / 96.0;
+ if (log_id == LOG_ID_MICROPEAK2)
+ return 100.0;
+ return 100.0;
+ }
+
+ int mix_in (int high, int low) {
+ return high - (high & 0xffff) + low;
+ }
+
+ boolean closer (int target, int a, int b) {
+ return Math.abs (target - a) < Math.abs(target - b);
+ }
+
+ private int pressure() {
+ int cur = value32(PA_GROUND_OFFSET);
+ for (int s = STARTING_LOG_OFFSET; s <= start; s += 2) {
+ int k = value16(s);
+ int same = mix_in(cur, k);
+ int up = mix_in(cur + 0x10000, k);
+ int down = mix_in(cur - 0x10000, k);
+
+ if (closer (cur, same, up)) {
+ if (closer (cur, same, down))
+ cur = same;
+ else
+ cur = down;
+ } else {
+ if (closer (cur, up, down))
+ cur = up;
+ else
+ cur = down;
+ }
+ }
+ return cur;
+ }
+
+ public void provide_data(AltosDataListener listener, AltosCalData cal_data) {
+ listener.set_tick(tick());
+ switch (cmd()) {
+ case AltosLib.AO_LOG_FLIGHT:
+ int pa_ground = pa_ground();
+ int pa_min = pa_min();
+ int n_samples = n_samples();
+ int log_id = log_id();
+ listener.set_state(AltosLib.ao_flight_pad);
+ listener.cal_data().set_ground_pressure(pa_ground);
+ listener.cal_data().set_ticks_per_sec(ticks_per_sec());
+ listener.cal_data().set_boost_tick();
+ listener.set_avoid_duplicate_files();
+ break;
+ case AltosLib.AO_LOG_SENSOR:
+ listener.set_state(AltosLib.ao_flight_boost);
+ listener.set_pressure(pressure());
+ break;
+ }
+ }
+
+ public int next_start() {
+ if (start == 0)
+ return STARTING_LOG_OFFSET;
+ if (start + 2 >= STARTING_LOG_OFFSET + 2 * n_samples())
+ return -1;
+ return start + 2;
+ }
+
+ public AltosEepromRecord next() {
+ int s = next_start();
+ if (s < 0)
+ return null;
+ return new AltosEepromRecordMicroPeak2(eeprom, s);
+ }
+
+ public AltosEepromRecordMicroPeak2(AltosEeprom eeprom, int start) {
+ super(eeprom, start, record_length);
+ }
+
+ public AltosEepromRecordMicroPeak2(AltosEeprom eeprom) {
+ this(eeprom, 0);
+ }
+}
AltosEeprom eeprom;
TreeSet<AltosEepromRecord> ordered;
AltosCalData cal_data;
+ boolean valid;
public AltosConfigData config_data() {
return eeprom.config_data();
listener.finish();
}
+ public boolean valid() {
+ return valid;
+ }
+
public AltosEepromRecordSet(AltosEeprom eeprom) {
this.eeprom = eeprom;
case AltosLib.AO_LOG_FORMAT_TELEFIRETWO:
record = new AltosEepromRecordFireTwo(eeprom);
break;
+ case AltosLib.AO_LOG_FORMAT_MICROPEAK2:
+ record = new AltosEepromRecordMicroPeak2(eeprom);
+ break;
}
+ ordered = new TreeSet<AltosEepromRecord>();
+
if (record == null) {
System.out.printf("failed to parse log format %d\n", config_data.log_format);
+ valid = false;
return;
}
- ordered = new TreeSet<AltosEepromRecord>();
+ valid = true;
+
int tick = 0;
boolean first = true;
public String description;
public int hashCode() {
- return new Double(frequency).hashCode();
+ return Double.valueOf(frequency).hashCode();
}
public boolean equals(Object o) {
return odt.toEpochSecond();
}
+ public AltosLatLon lat_lon() {
+ return new AltosLatLon(lat, lon);
+ }
+
public AltosGPS(AltosTelemetryMap map) throws ParseException {
String state = map.get_string(AltosTelemetryLegacy.AO_TELEM_GPS_STATE,
AltosTelemetryLegacy.AO_TELEM_GPS_STATE_ERROR);
return -1;
try {
- /* Walk the descriptors looking for the device */
+ /* The address of this has moved depending on
+ * padding in the linker script. Look forward
+ * and backwards two bytes to see if we can find it
+ */
a = usb_descriptors.address;
- while (get_u8(a+1) != AO_USB_DESC_DEVICE) {
- int delta = get_u8(a);
- a += delta;
- if (delta == 0 || a >= max_address)
- return -1;
- }
- return a;
+
+ if (get_u8(a) == 0x12 && get_u8(a+1) == AO_USB_DESC_DEVICE)
+ return a;
+ else if (get_u8(a+1) == 0x12 && get_u8(a+3) == AO_USB_DESC_DEVICE)
+ return a + 2;
+ else if (get_u8(a-2) == 0x12 && get_u8(a-1) == AO_USB_DESC_DEVICE)
+ return a - 2;
+
+ return -1;
} catch (ArrayIndexOutOfBoundsException ae) {
return -1;
}
return n;
}
- static public void provide_data(AltosDataListener listener, AltosLink link) throws InterruptedException {
+ public static final int orient_telemega = 0;
+ public static final int orient_easymega_v2 = 1;
+
+ private int accel_across(int orient) {
+ switch (orient) {
+ case orient_telemega:
+ return accel_x;
+ case orient_easymega_v2:
+ return -accel_y;
+ default:
+ return AltosLib.MISSING;
+ }
+ }
+
+ private int accel_along(int orient) {
+ switch (orient) {
+ case orient_telemega:
+ return accel_y;
+ case orient_easymega_v2:
+ return accel_x;
+ default:
+ return AltosLib.MISSING;
+ }
+ }
+
+ private int accel_through(int orient) {
+ return accel_z;
+ }
+
+ private int gyro_roll(int orient) {
+ switch (orient) {
+ case orient_telemega:
+ return gyro_y;
+ case orient_easymega_v2:
+ return gyro_x;
+ default:
+ return AltosLib.MISSING;
+ }
+ }
+
+ private int gyro_pitch(int orient) {
+ switch (orient) {
+ case orient_telemega:
+ return gyro_x;
+ case orient_easymega_v2:
+ return -gyro_y;
+ default:
+ return AltosLib.MISSING;
+ }
+ }
+
+ private int gyro_yaw(int orient) {
+ return gyro_z;
+ }
+
+ private int mag_across(int orient) {
+ switch (orient) {
+ case orient_telemega:
+ return mag_x;
+ case orient_easymega_v2:
+ return -mag_y;
+ default:
+ return AltosLib.MISSING;
+ }
+ }
+
+ private int mag_along(int orient) {
+ switch (orient) {
+ case orient_telemega:
+ return mag_y;
+ case orient_easymega_v2:
+ return mag_x;
+ default:
+ return AltosLib.MISSING;
+ }
+ }
+
+ private int mag_through(int orient) {
+ return mag_z;
+ }
+
+ static public void provide_data(AltosDataListener listener, AltosLink link, int orient) throws InterruptedException {
try {
AltosIMU imu = new AltosIMU(link);
AltosCalData cal_data = listener.cal_data();
if (imu != null) {
- listener.set_gyro(cal_data.gyro_roll(imu.gyro_y),
- cal_data.gyro_pitch(imu.gyro_x),
- cal_data.gyro_yaw(imu.gyro_z));
- listener.set_accel_ground(imu.accel_y,
- imu.accel_x,
- imu.accel_z);
+ listener.set_gyro(cal_data.gyro_roll(imu.gyro_roll(orient)),
+ cal_data.gyro_pitch(imu.gyro_pitch(orient)),
+ cal_data.gyro_yaw(imu.gyro_yaw(orient)));
+ listener.set_accel_ground(imu.accel_along(orient),
+ imu.accel_across(orient),
+ imu.accel_through(orient));
if (imu.mag_x != AltosLib.MISSING) {
- listener.set_mag(cal_data.mag_along(imu.mag_y),
- cal_data.mag_across(imu.mag_x),
- cal_data.mag_through(imu.mag_z));
+ listener.set_mag(cal_data.mag_along(imu.mag_along(orient)),
+ cal_data.mag_across(imu.mag_across(orient)),
+ cal_data.mag_through(imu.mag_through(orient)));
}
}
} catch (TimeoutException te) {
static final int idle_gps = 0;
static final int idle_imu = 1;
- static final int idle_mag = 2;
+ static final int idle_imu_em_v2 = 2;
+ static final int idle_mag = 3;
static final int idle_mma655x = 4;
static final int idle_ms5607 = 5;
static final int idle_adxl375 = 6;
AltosGPS.provide_data(listener, link);
break;
case idle_imu:
- AltosIMU.provide_data(listener, link);
+ AltosIMU.provide_data(listener, link, AltosIMU.orient_telemega);
+ break;
+ case idle_imu_em_v2:
+ AltosIMU.provide_data(listener, link, AltosIMU.orient_easymega_v2);
break;
case idle_mag:
AltosMag.provide_data(listener, link);
AltosIdler.idle_ms5607,
AltosIdler.idle_sensor_metrum),
+ new AltosIdler("TeleMetrum-v3",
+ AltosIdler.idle_gps,
+ AltosIdler.idle_adxl375,
+ AltosIdler.idle_ms5607,
+ AltosIdler.idle_sensor_metrum),
+
new AltosIdler("TeleMega-v0",
AltosIdler.idle_gps,
AltosIdler.idle_mma655x,
new AltosIdler("EasyMega-v2",
AltosIdler.idle_adxl375,
AltosIdler.idle_ms5607,
- AltosIdler.idle_imu,
+ AltosIdler.idle_imu_em_v2,
AltosIdler.idle_sensor_mega),
new AltosIdler("TeleGPS-v1",
AltosIdler.idle_gps,
}
break;
case type_long:
- result.append(new Long(l_number).toString());
+ result.append(Long.valueOf(l_number).toString());
break;
case type_string:
quote(result, string);
* all inner classes are only members of their immediate outer
* class
*/
+ @SuppressWarnings("unchecked")
private Object make(Class c, Class enclosing_class, Object enclosing_object) {
Object ret;
if (c == Boolean.TYPE) {
Constructor<?> ctor = ((Class<?>)c).getDeclaredConstructor((Class<?>) enclosing_class);
object = ctor.newInstance(enclosing_object);
} else {
- object = c.newInstance();
+ object = c.getDeclaredConstructor().newInstance();
}
for (; c != Object.class; c = c.getSuperclass()) {
for (Field field : c.getDeclaredFields()) {
public double lon;
public int hashCode() {
- return new Double(lat).hashCode() ^ new Double(lon).hashCode();
+ return Double.valueOf(lat).hashCode() ^ Double.valueOf(lon).hashCode();
}
public boolean equals(Object o) {
public static final int AO_LOG_FORMAT_EASYMINI2 = 14;
public static final int AO_LOG_FORMAT_TELEMEGA_3 = 15;
public static final int AO_LOG_FORMAT_EASYMEGA_2 = 16;
+ public static final int AO_LOG_FORMAT_TELESTATIC = 17;
+ public static final int AO_LOG_FORMAT_MICROPEAK2 = 18;
public static final int AO_LOG_FORMAT_NONE = 127;
public static boolean isspace(int c) {
return false;
}
- public void show(AltosGPS gps, int state) {
-
+ public void show(AltosGPS gps, double time, int state, double gps_height) {
/*
* If insufficient gps data, nothing to update
*/
}
if (path != null) {
- AltosMapRectangle damage = path.add(gps.lat, gps.lon, state);
+ AltosMapRectangle damage = path.add(gps, time, state, gps_height);
if (damage != null)
repaint(damage, AltosMapPath.stroke_width);
}
public void show(AltosState state, AltosListenerState listener_state) {
- show(state.gps, state.state());
+ show(state.gps, state.time, state.state(), state.gps_height());
}
public void centre(AltosLatLon lat_lon) {
centre(lat_lon);
}
- public void add_mark(double lat, double lon, int state) {
+ public AltosMapMark add_mark(double lat, double lon, int state) {
+ AltosMapMark mark;
synchronized(marks) {
- AltosMapMark mark = map_interface.new_mark(lat, lon, state);
+ mark = map_interface.new_mark(lat, lon, state);
if (mark != null)
marks.add(mark);
}
repaint();
+ return mark;
+ }
+
+ public void del_mark(AltosMapMark mark) {
+ marks.remove(mark);
}
public void clear_marks() {
drag_stop(x, y);
}
+ public AltosMapPathPoint nearest(int x, int y) {
+ notice_user_input();
+ if (path == null)
+ return null;
+ if (transform == null)
+ return null;
+ AltosLatLon at = transform.screen_lat_lon(new AltosPointInt(x, y));
+ return path.nearest(at);
+ }
+
public AltosMap(AltosMapInterface map_interface, int scale) {
this.map_interface = map_interface;
this.scale = scale;
public abstract void paint(AltosMapTransform t);
- public AltosMapRectangle add(double lat, double lon, int state) {
- AltosMapPathPoint point = new AltosMapPathPoint(new AltosLatLon (lat, lon), state);
+ public AltosMapRectangle add(AltosGPS gps, double time, int state, double gps_height) {
+ AltosMapPathPoint point = new AltosMapPathPoint(gps, time, state, gps_height);
AltosMapRectangle rect = null;
if (!point.equals(last_point)) {
if (last_point != null)
- rect = new AltosMapRectangle(last_point.lat_lon, point.lat_lon);
+ rect = new AltosMapRectangle(last_point.gps.lat_lon(), point.gps.lat_lon());
points.add (point);
last_point = point;
}
return rect;
}
+ private double dist(AltosLatLon lat_lon, AltosMapPathPoint point) {
+ return (new AltosGreatCircle(lat_lon.lat,
+ lat_lon.lon,
+ point.gps.lat,
+ point.gps.lon)).distance;
+ }
+
+ public AltosMapPathPoint nearest(AltosLatLon lat_lon) {
+ AltosMapPathPoint nearest = null;
+ double nearest_dist = 0;
+ for (AltosMapPathPoint point : points) {
+ if (nearest == null) {
+ nearest = point;
+ nearest_dist = dist(lat_lon, point);
+ } else {
+ double d = dist(lat_lon, point);
+ if (d < nearest_dist) {
+ nearest = point;
+ nearest_dist = d;
+ }
+ }
+ }
+ return nearest;
+ }
+
public void clear () {
points = new LinkedList<AltosMapPathPoint>();
}
import java.util.concurrent.*;
public class AltosMapPathPoint {
- public AltosLatLon lat_lon;
+ public AltosGPS gps;
+ public double time;
public int state;
+ public double gps_height;
public int hashCode() {
- return lat_lon.hashCode() ^ state;
+ return Double.valueOf(gps.lat).hashCode() ^ Double.valueOf(gps.lon).hashCode() ^ state;
}
public boolean equals(Object o) {
AltosMapPathPoint other = (AltosMapPathPoint) o;
- return lat_lon.equals(other.lat_lon) && state == other.state;
+ return gps.lat == other.gps.lat && gps.lon == other.gps.lon && state == other.state;
}
- public AltosMapPathPoint(AltosLatLon lat_lon, int state) {
- this.lat_lon = lat_lon;
+ public AltosMapPathPoint(AltosGPS gps, double time, int state, double gps_height) {
+ this.gps = gps;
+ this.time = time;
this.state = state;
+ this.gps_height = gps_height;
}
}
return lat_lon(screen_point(screen));
}
- public AltosPointDouble point(AltosLatLon lat_lon) {
+ public AltosPointDouble point(double lat, double lon) {
double x, y;
double e;
- x = lat_lon.lon * scale_x;
+ x = lon * scale_x;
- e = Math.sin(Math.toRadians(lat_lon.lat));
+ e = Math.sin(Math.toRadians(lat));
e = Math.max(e,-(1-1.0E-15));
e = Math.min(e, 1-1.0E-15 );
return new AltosPointDouble(x, y);
}
+ public AltosPointDouble point(AltosLatLon lat_lon) {
+ return point(lat_lon.lat, lat_lon.lon);
+ }
+
public AltosPointDouble screen(AltosPointDouble point) {
return new AltosPointDouble(point.x - offset_x, point.y - offset_y);
}
return screen(point(lat_lon));
}
+ public AltosPointDouble screen(double lat, double lon) {
+ return screen(point(lat, lon));
+ }
+
private boolean has_location;
public boolean has_location() {
public double x, y;
public int hashCode() {
- return new Double(x).hashCode() ^ new Double(y).hashCode();
+ return Double.valueOf(x).hashCode() ^ Double.valueOf(y).hashCode();
}
public boolean equals(Object o) {
public interface AltosRecordSet {
public AltosCalData cal_data();
public void capture_series(AltosDataListener listener);
+ public boolean valid();
}
return cal_data;
}
+ public boolean valid() {
+ return true;
+ }
+
public void capture_series(AltosDataListener listener) {
AltosCalData cal_data = cal_data();
int speed() { return int16(20); }
int height_16() { return int16(22); }
- int ground_accel() { return int16(24); }
- int ground_pres() { return int16(26); }
+ int ground_pres() { return int16(24); }
+ int ground_accel() { return int16(26); }
int accel_plus_g() { return int16(28); }
int accel_minus_g() { return int16(30); }
public abstract double inverse(double v, boolean imperial_units);
public String string_value(double v, boolean imperial_units) {
- return new Double(value(v, imperial_units)).toString();
+ return Double.valueOf(value(v, imperial_units)).toString();
}
public abstract String show_units(boolean imperial_units);
-AM_JAVACFLAGS=-target 1.6 -encoding UTF-8 -Xlint:deprecation -Xlint:unchecked -source 6
+AM_JAVACFLAGS=$(JAVAC_VERSION_FLAGS) -encoding UTF-8 -Xlint:deprecation -Xlint:unchecked
JAVAROOT=bin
VERSION=1
-CLASSPATH_ENV=mkdir -p $(JAVAROOT); CLASSPATH="bin:$(FREETTS)/*:/usr/share/java/*"
+CLASSPATH_ENV=mkdir -p $(JAVAROOT); CLASSPATH=bin
SRC=.
AltosEepromRecordMini.java \
AltosEepromRecordGps.java \
AltosEepromRecordFireTwo.java \
+ AltosEepromRecordMicroPeak2.java \
AltosEepromRecordSet.java \
AltosEepromChunk.java \
AltosEepromDownload.java \
$(JAR): classaltoslib.stamp
jar cf $@ -C bin org
+if STRIP_NONDETERMINISM
+ $(STRIP_NONDETERMINISM) $@
+endif
return pyro_firing_time;
}
+ private String aprs_interval_string(int interval) {
+ if (interval == 0)
+ return "Disabled";
+ return Integer.toString(interval);
+ }
+
+ private int aprs_interval_value(String interval) throws AltosConfigDataException {
+ if (interval.equalsIgnoreCase("Disabled"))
+ return 0;
+ return parse_int("aprs interval", interval, false);
+ }
+
public void set_aprs_interval(int new_aprs_interval) {
if (new_aprs_interval != AltosLib.MISSING)
- aprs_interval_value.setSelectedItem(Integer.toString(new_aprs_interval));
+ aprs_interval_value.setSelectedItem(aprs_interval_string(new_aprs_interval));
aprs_interval_value.setVisible(new_aprs_interval != AltosLib.MISSING);
aprs_interval_label.setVisible(new_aprs_interval != AltosLib.MISSING);
set_aprs_interval_tool_tip();
}
public int aprs_interval() throws AltosConfigDataException {
- if (aprs_interval_value.isVisible()) {
- String s = aprs_interval_value.getSelectedItem().toString();
-
- return parse_int("aprs interval", s, false);
- }
+ if (aprs_interval_value.isVisible())
+ return aprs_interval_value(aprs_interval_value.getSelectedItem().toString());
return AltosLib.MISSING;
}
void fill_map(AltosFlightSeries flight_series) {
boolean any_gps = false;
AltosGPSTimeValue gtv_last = null;
+ double gps_pad_altitude = flight_series.cal_data().gps_pad_altitude;;
if (flight_series.gps_series != null) {
for (AltosGPSTimeValue gtv : flight_series.gps_series) {
gps.nsat >= 4) {
if (map == null)
map = new AltosUIMap();
- map.show(gps, (int) flight_series.value_before(AltosFlightSeries.state_name, gtv.time));
+ double gps_height = gps.alt - gps_pad_altitude;
+ int state = (int) flight_series.value_before(AltosFlightSeries.state_name, gtv.time);
+ map.show(gps, gtv.time, state, gps_height);
this.gps = gps;
gtv_last = gtv;
has_gps = true;
}
if (gtv_last != null) {
int state = (int) flight_series.value_after(AltosFlightSeries.state_name, gtv_last.time);
+ double gps_height = gps.alt - gps_pad_altitude;
if (state == AltosLib.ao_flight_landed)
- map.show(gtv_last.gps, state);
+ map.show(gtv_last.gps, gtv_last.time, state,gps_height);
}
}
/* OSXAdapter interfaces */
public void macosx_file_handler(String path) {
- process_graph(new File(path));
+ process_graph(null, new File(path));
}
public void macosx_quit_handler() {
public void graph_flights(AltosEepromList flights) {
for (AltosEepromLog flight : flights) {
if (flight.graph_selected && flight.file != null) {
- process_graph(flight.file);
+ process_graph(this, flight.file);
}
}
}
new AltosCSVUI(AltosUI.this, series, chooser.file());
}
+ private static boolean graph_file(AltosUI altosui, AltosRecordSet set, File file) {
+ if (set == null)
+ return false;
+ if (!set.valid()) {
+ JOptionPane.showMessageDialog(altosui,
+ String.format("Failed to parse file %s", file),
+ "Graph Failed",
+ JOptionPane.ERROR_MESSAGE);
+ return false;
+ }
+ try {
+ new AltosGraphUI(set, file);
+ return true;
+ } catch (InterruptedException ie) {
+ } catch (IOException ie) {
+ }
+ return false;
+ }
+
/* Load a flight log CSV file and display a pretty graph.
*/
AltosDataChooser chooser;
chooser = new AltosDataChooser(this);
AltosRecordSet set = chooser.runDialog();
- if (set == null)
- return;
- try {
- new AltosGraphUI(set, chooser.file());
- } catch (InterruptedException ie) {
- } catch (IOException ie) {
- }
+ graph_file(this, set, chooser.file());
}
private void ConfigureAltosUI() {
return true;
}
- static boolean process_graph(File file) {
+ static boolean process_graph(AltosUI altosui, File file) {
AltosRecordSet set = record_set(file);
- if (set == null)
- return false;
- try {
- new AltosGraphUI(set, file);
- return true;
- } catch (InterruptedException ie) {
- } catch (IOException ie) {
- }
- return false;
+ return graph_file(altosui, set, file);
}
static boolean process_summary(File file) {
if (altosui == null)
altosui = new AltosUI();
case process_graph:
- if (!process_graph(file))
+ if (!process_graph(null, file))
++errors;
break;
case process_replay:
JAVAROOT=classes
-AM_JAVACFLAGS=-target 1.6 -encoding UTF-8 -Xlint:deprecation -Xlint:unchecked -source 6
+AM_JAVACFLAGS=$(JAVAC_VERSION_FLAGS) -encoding UTF-8 -Xlint:deprecation -Xlint:unchecked
man_MANS=altosui.1
FIRMWARE_TD=$(FIRMWARE_TD_3_0)
FIRMWARE_TM_2_0=$(top_srcdir)/src/telemetrum-v2.0/telemetrum-v2.0-$(VERSION).ihx
-FIRMWARE_TM=$(FIRMWARE_TM_2_0)
+FIRMWARE_TM_3_0=$(top_srcdir)/src/telemetrum-v3.0/telemetrum-v3.0-$(VERSION).ihx
+FIRMWARE_TM=$(FIRMWARE_TM_2_0) $(FIRMWARE_TM_3_0)
FIRMWARE_TELEMINI_3_0=$(top_srcdir)/src/telemini-v3.0/telemini-v3.0-$(VERSION).ihx
FIRMWARE_TELEMINI=$(FIRMWARE_TELEMINI_3_0)
FIRMWARE_TMEGA=$(FIRMWARE_TMEGA_1_0) $(FIRMWARE_TMEGA_2_0) $(FIRMWARE_TMEGA_3_0)
FIRMWARE_EMINI_1_0=$(top_srcdir)/src/easymini-v1.0/easymini-v1.0-$(VERSION).ihx
-FIRMWARE_EMINI=$(FIRMWARE_EMINI_1_0)
+FIRMWARE_EMINI_2_0=$(top_srcdir)/src/easymini-v2.0/easymini-v2.0-$(VERSION).ihx
+FIRMWARE_EMINI=$(FIRMWARE_EMINI_1_0) $(FIRMWARE_EMINI_2_0)
FIRMWARE_EMEGA_1_0=$(top_srcdir)/src/easymega-v1.0/easymega-v1.0-$(VERSION).ihx
FIRMWARE_EMEGA_2_0=$(top_srcdir)/src/easymega-v2.0/easymega-v2.0-$(VERSION).ihx
$(ICONJAR) \
-C classes altosui \
-C ../libaltos libaltosJNI
+if STRIP_NONDETERMINISM
+ $(STRIP_NONDETERMINISM) $@
+endif
$(FATJAR): classaltosui.stamp Manifest-fat.txt $(ALTOSLIB_CLASS) $(ALTOSUILIB_CLASS) $(FREETTS_CLASS) $(JFREECHART_CLASS) $(JCOMMON_CLASS) $(LIBALTOS) $(JAVA_ICONS)
jar cfm $@ Manifest-fat.txt \
$(ICONJAR) \
-C classes altosui \
-C ../libaltos libaltosJNI
+if STRIP_NONDETERMINISM
+ $(STRIP_NONDETERMINISM) $@
+endif
Manifest.txt: Makefile
echo 'Main-Class: altosui.AltosUI' > $@
return false;
}
- if (existing_config.radio_calibration_broken) {
+ if (existing_config != null && existing_config.radio_calibration_broken) {
int ret = JOptionPane.showConfirmDialog(this,
String.format("Radio calibration value %d may be incorrect\nFlash anyways?",
existing_config.radio_calibration),
public void run () {
try {
AltosLink link = null;
+ boolean new_device = false;
for (;;) {
System.out.printf("Attempting to open %s\n", device.toShortString());
- link = new AltosSerial(device);
+ for (int i = 0; i < 20; i++) {
+ link = new AltosSerial(device);
+ if (link != null)
+ break;
+
+ if (!new_device)
+ break;
+
+ System.out.printf("Waiting for device to become ready\n");
+
+ Thread.sleep(1000);
+ }
if (link == null)
throw new IOException(String.format("%s: open failed",
device.toShortString()));
if (!matched) {
System.out.printf("Identified new device %s\n", d.toShortString());
device = (AltosUSBDevice) d;
+ new_device = true;
break;
}
}
{
Container pane;
Box box;
+ JLabel product_label;
JLabel serial_label;
JLabel radio_calibration_label;
+ JLabel product_value;
JFrame owner;
JTextField serial_value;
JTextField radio_calibration_value;
int y = 0;
+ /* Product name */
+ /* Serial */
+ c = new GridBagConstraints();
+ c.gridx = 0; c.gridy = y;
+ c.gridwidth = 3;
+ c.fill = GridBagConstraints.NONE;
+ c.anchor = GridBagConstraints.LINE_START;
+ c.insets = il;
+ product_label = new JLabel("Product:");
+ pane.add(product_label, c);
+
+ c = new GridBagConstraints();
+ c.gridx = 3; c.gridy = y;
+ c.gridwidth = 3;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.weightx = 1;
+ c.anchor = GridBagConstraints.LINE_START;
+ c.insets = ir;
+ product_value = new JLabel(config.usb_product);
+ pane.add(product_value, c);
+
+ y++;
+
/* Serial */
c = new GridBagConstraints();
c.gridx = 0; c.gridy = y;
y++;
- if (AltosLib.has_radio(config.usb_id.pid)) {
+ if (config == null || AltosLib.has_radio(config.usb_id.pid)) {
/* Radio calibration value */
c = new GridBagConstraints();
c.gridx = 0; c.gridy = y;
this.series = null;
this.axis_index = 0;
- enable.register_shape_listener(this);
+ if (enable != null)
+ enable.register_shape_listener(this);
axes_added = new Hashtable<Integer,Boolean>();
Graphics2D g;
Font tile_font;
Font line_font;
+ AltosMapMark nearest_mark;
static Point2D.Double point2d(AltosPointDouble pt) {
return new Point2D.Double(pt.x, pt.y);
map.touch_continue(e.getPoint().x, e.getPoint().y, is_drag_event(e));
}
+ String pos(double p, String pos, String neg) {
+ if (p == AltosLib.MISSING)
+ return "";
+ String h = pos;
+ if (p < 0) {
+ h = neg;
+ p = -p;
+ }
+ int deg = (int) Math.floor(p);
+ double min = (p - Math.floor(p)) * 60.0;
+ return String.format("%s %4d° %9.6f'", h, deg, min);
+ }
+
+ String height(double h, String label) {
+ if (h == AltosLib.MISSING)
+ return "";
+ return String.format(" %s%s",
+ AltosConvert.height.show(6, h),
+ label);
+ }
+
+ String speed(double s, String label) {
+ if (s == AltosLib.MISSING)
+ return "";
+ return String.format(" %s%s",
+ AltosConvert.speed.show(6, s),
+ label);
+ }
+
public void mouseMoved(MouseEvent e) {
+ AltosMapPathPoint point = map.nearest(e.getPoint().x, e.getPoint().y);
+
+ if (point != null) {
+ if (nearest_mark == null)
+ nearest_mark = map.add_mark(point.gps.lat,
+ point.gps.lon,
+ point.state);
+ else {
+ nearest_mark.lat_lon.lat = point.gps.lat;
+ nearest_mark.lat_lon.lon = point.gps.lon;
+ nearest_mark.state = point.state;
+ }
+ nearest_label.setText(String.format("%9.2f sec %s%s%s%s",
+ point.time,
+ pos(point.gps.lat,
+ "N", "S"),
+ pos(point.gps.lon,
+ "E", "W"),
+ height(point.gps_height, ""),
+ speed(point.gps.ground_speed, "(h)"),
+ speed(point.gps.climb_rate, "(v)")));
+ } else {
+ nearest_label.setText("");
+ }
+ repaint();
}
/* MouseListener methods */
g.setStroke(new BasicStroke(stroke_width, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
for (AltosMapPathPoint point : points) {
- Point2D.Double cur = point2d(t.screen(point.lat_lon));
+ Point2D.Double cur = point2d(t.screen(point.gps.lat, point.gps.lon));
if (prev != null) {
Line2D.Double line = new Line2D.Double (prev, cur);
Rectangle bounds = line.getBounds();
public void set_font() {
tile_font = AltosUILib.value_font;
line_font = AltosUILib.status_font;
+ if (nearest_label != null)
+ nearest_label.setFont(AltosUILib.value_font);
}
public void font_size_changed(int font_size) {
JLabel zoom_label;
+ JLabel nearest_label;
+
public void set_maptype(int type) {
/*
map.set_maptype(type);
map.show(state, listener_state);
}
- public void show(AltosGPS gps, int state) {
- map.show(gps, state);
+ public void show(AltosGPS gps, double time, int state, double gps_height) {
+ map.show(gps, time, state, gps_height);
}
public String getName() {
c.weighty = 0;
add(zoom_out, c);
+
+ nearest_label = new JLabel("", JLabel.LEFT);
+ nearest_label.setFont(tile_font);
+
+ c = new GridBagConstraints();
+ c.anchor = GridBagConstraints.CENTER;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.gridx = 0;
+ c.gridy = 11;
+ c.weightx = 0;
+ c.weighty = 0;
+ c.gridwidth = 1;
+ c.gridheight = 1;
+ add(nearest_label, c);
/*
maptype_combo = new JComboBox<String>(map.maptype_labels);
-AM_JAVACFLAGS=-target 1.6 -encoding UTF-8 -Xlint:deprecation -Xlint:unchecked -source 6
+AM_JAVACFLAGS=$(JAVAC_VERSION_FLAGS) -encoding UTF-8 -Xlint:deprecation -Xlint:unchecked
JAVAROOT=bin
$(JAR): classaltosuilib.stamp $(ICONS)
jar cf $@ $(ICONJAR) -C $(JAVAROOT) .
+if STRIP_NONDETERMINISM
+ $(STRIP_NONDETERMINISM) $@
+endif
PASS=0
FAIL=0
WEAK=0
-../ao-tools/ao-chaosread/ao-chaosread $serial --infinite --bytes | for test in $tests done; do
+chaosread $serial --infinite --bytes | for test in $tests done; do
case $test in
*:*:*)
dnum=`echo $test | sed 's/:.*$//'`
#!/bin/sh
-VERSION=2.0
+VERSION=3.0
PRODUCT=TeleMetrum
BASE=`echo $PRODUCT | tr 'A-Z' 'a-z'`
echo "$PRODUCT-v$VERSION Test Program"
-echo "Copyright 2014 by Keith Packard. Released under GPL v2"
+echo "Copyright 2019 by Bdale Garbee. Released under GPL v2"
echo
echo "Expectations:"
echo "\t$PRODUCT v$VERSION powered from USB"
--- /dev/null
+#!/bin/sh
+
+VERSION=2.0
+PRODUCT=TeleMetrum
+BASE=`echo $PRODUCT | tr 'A-Z' 'a-z'`
+
+echo "$PRODUCT-v$VERSION Test Program"
+echo "Copyright 2014 by Keith Packard. Released under GPL v2"
+echo
+echo "Expectations:"
+echo "\t$PRODUCT v$VERSION powered from USB"
+echo
+
+ret=1
+ao-list | while read product serial dev; do
+ case "$product" in
+ "$PRODUCT-v$VERSION")
+
+ echo "Testing $product $serial $dev"
+ echo ""
+
+ ./test-igniters "$dev" drogue main
+ echo ""
+
+ echo "Testing baro sensor"
+ ../ao-tools/ao-test-baro/ao-test-baro --tty="$dev"
+
+ case $? in
+ 0)
+ ;;
+ *)
+ echo "failed"
+ exit 1
+ esac
+ echo""
+
+ FLASHSIZE=8388608
+
+ echo "Testing flash"
+ ../ao-tools/ao-test-flash/ao-test-flash --tty="$dev" "$FLASHSIZE"
+
+ case $? in
+ 0)
+ ;;
+ *)
+ echo "failed"
+ exit 1
+ esac
+ echo""
+
+ echo "Testing GPS"
+ ../ao-tools/ao-test-gps/ao-test-gps --tty="$dev"
+
+ case $? in
+ 0)
+ ;;
+ *)
+ echo "failed"
+ exit 1
+ esac
+ echo""
+
+ echo "$PRODUCT-v$VERSION" serial "$serial" is ready to ship
+ echo "\007"
+ ret=0
+ ;;
+ esac
+done
--- /dev/null
+#!/bin/sh
+
+PRODUCT=TeleFireEight
+VERSION=2.0
+REPO=~/altusmetrumllc/Binaries
+
+if [ -x /usr/bin/ao-flash-stm ]; then
+ FLASH_STM=/usr/bin/ao-flash-stm
+else
+ echo "Can't find ao-flash-stm! Aborting."
+ exit 1
+fi
+
+if [ -x /usr/bin/ao-usbload ]; then
+ USBLOAD=/usr/bin/ao-usbload
+else
+ echo "Can't find ao-usbload! Aborting."
+ exit 1
+fi
+
+echo "$PRODUCT v$VERSION Turn-On and Calibration Program"
+echo "Copyright 2019 by Bdale Garbee. Released under GPL v2"
+echo
+echo "Expectations:"
+echo "\t$PRODUCT v$VERSION"
+echo "\t\twith USB cable attached"
+echo "\t\twith ST-Link-V2 cabled to debug header"
+echo
+
+case $# in
+ 1)
+ SERIAL="$1"
+ echo "$PRODUCT-$VERSION serial number: $SERIAL"
+ ;;
+ 0)
+ echo -n "$PRODUCT-$VERSION serial number: "
+ read SERIAL
+ ;;
+ *)
+ echo "Usage: $0 <serial-number>" 1>&2
+ exit 1;
+ ;;
+esac
+
+echo $FLASH_STM
+
+$FLASH_STM $REPO/loaders/telefireeight-v$VERSION*.elf
+
+sleep 3
+
+$USBLOAD --serial=$SERIAL $REPO/telefireeight-v$VERSION*.elf || exit 1
+
+sleep 5
+
+dev=`ao-list | awk '/'"$PRODUCT"'-v'"$VERSION"'/ { print $3; exit(0); }'`
+
+case "$dev" in
+/dev/tty*)
+ echo "$PRODUCT found on $dev"
+ ;;
+*)
+ echo 'No '"$PRODUCT"'-v'"$VERSION"' found'
+ exit 1
+ ;;
+esac
+
+echo 'E 0' > $dev
+SERIAL=$SERIAL ./cal-freq $dev
+echo 'E 1' > $dev
+
+echo "$PRODUCT-v$VERSION" serial "$SERIAL" is ready for integration and testing
+echo "\007"
+
+exit $?
exit 1
fi
-VERSION=2.0
+VERSION=3.0
PRODUCT=TeleMetrum
echo "$PRODUCT v$VERSION Turn-On and Calibration Program"
--- /dev/null
+#!/bin/sh
+
+if [ -x /usr/bin/ao-flash-stm ]; then
+ FLASH_STM=/usr/bin/ao-flash-stm
+else
+ echo "Can't find ao-flash-stm! Aborting."
+ exit 1
+fi
+
+if [ -x /usr/bin/ao-usbload ]; then
+ USBLOAD=/usr/bin/ao-usbload
+else
+ echo "Can't find ao-usbload! Aborting."
+ exit 1
+fi
+
+VERSION=2.0
+PRODUCT=TeleMetrum
+
+echo "$PRODUCT v$VERSION Turn-On and Calibration Program"
+echo "Copyright 2014 by Bdale Garbee. Released under GPL v2"
+echo
+echo "Expectations:"
+echo "\t$PRODUCT 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 "$PRODUCT-$VERSION serial number: "
+
+case $# in
+ 1)
+ SERIAL="$1"
+ echo "$PRODUCT-$VERSION serial number: $SERIAL"
+ ;;
+ 0)
+ echo -n "$PRODUCT-$VERSION serial number: "
+ read SERIAL
+ ;;
+ *)
+ echo "Usage: $0 <serial-number>" 1>&2
+ exit 1;
+ ;;
+esac
+
+echo $FLASH_STM
+
+$FLASH_STM ~/altusmetrumllc/Binaries/loaders/telemetrum-v$VERSION-*.elf || exit 1
+
+sleep 3
+
+$USBLOAD --serial=$SERIAL ~/altusmetrumllc/Binaries/telemetrum-v$VERSION-*.elf || exit 1
+
+sleep 5
+
+dev=`ao-list | awk '/TeleMetrum-v'"$VERSION"'/ { print $3; exit(0); }'`
+
+case "$dev" in
+/dev/tty*)
+ echo "TeleMetrum found on $dev"
+ ;;
+*)
+ echo 'No TeleMetrum-v'"$VERSION"' found'
+ exit 1
+ ;;
+esac
+
+echo 'E 0' > $dev
+
+SERIAL=$SERIAL ./cal-freq $dev
+
+failed=1
+while [ $failed = 1 ]; do
+ ../ao-tools/ao-cal-accel/ao-cal-accel $dev
+ failed=$?
+done
+
+echo 'E 1' > $dev
+
+./test-telemetrum
+
+exit $?
ao-dumpflash ao-edit-telem ao-dump-up ao-elftohex \
ao-flash ao-usbload ao-test-igniter ao-test-baro \
ao-test-flash ao-cal-accel ao-test-gps ao-usbtrng \
- ao-cal-freq ao-chaosread ao-makebin
+ ao-cal-freq ao-makebin
if LIBSTLINK
SUBDIRS += ao-stmload
endif
bin_PROGRAMS=ao-bitbang
-AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
+AM_CFLAGS=$(WARN_CFLAGS) -I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
AO_BITBANG_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a
ao_bitbang_DEPENDENCIES = $(AO_BITBANG_LIBS)
--- /dev/null
+bin_PROGRAMS=ao-bm70
+
+AM_CFLAGS=-O0 -g
+
+ao_bm70_SOURCES = ao-bm70.c
+
+man_MANS=ao-bm70.1
--- /dev/null
+bin_PROGRAMS=ao-chaosread
+
+AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
+
+ao_chaosread_LDADD=$(LIBUSB_LIBS)
+
+ao_chaosread_SOURCES = ao-chaosread.c
+
+man_MANS = ao-chaosread.1
bin_PROGRAMS=ao-cal-accel
-AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
+AM_CFLAGS=$(WARN_CFLAGS) -I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
ao_cal_accel_DEPENDENCIES = $(top_builddir)/ao-tools/lib/libao-tools.a
exit(1);
}
-void
+static void
done(struct cc_usb *cc, int code)
{
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;
-}
-
-static int
-starts_with(char *whole, char *prefix)
-{
- int whole_len = strlen(whole);
- int prefix_len = strlen(prefix);
-
- if (prefix_len > whole_len)
- return 0;
- return strncmp(whole, prefix, prefix_len) == 0;
-}
-
static char **
tok(char *line) {
char **strs = malloc (sizeof (char *)), *str;
return strs;
}
-static void
-free_strs(char **strs) {
- char *str;
- int i;
-
- for (i = 0; (str = strs[i]) != NULL; i++)
- free(str);
- free(strs);
-}
-
struct flash {
struct flash *next;
char line[512];
return head;
}
-static void
-free_flash(struct flash *b) {
- struct flash *n;
-
- while (b) {
- n = b->next;
- free_strs(b->strs);
- free(b);
- b = n;
- }
-}
-
-char **
+static char **
find_flash(struct flash *b, char *word0) {
- int i;
for (;b; b = b->next) {
if (strstr(b->line, word0))
return b->strs;
return NULL;
}
-void
+static void
await_key(void)
{
struct termios termios, termios_save;
tcsetattr(0, TCSAFLUSH, &termios_save);
}
-int
+static int
do_cal(struct cc_usb *usb) {
struct flash *b;
char **accel;
char line[1024];
- int l;
+ int l = 0;
int running = 0;
int worked = 1;
main (int argc, char **argv)
{
char *device = NULL;
- char *filename;
- Elf *e;
- unsigned int s;
- int i;
int c;
- int tries;
struct cc_usb *cc = NULL;
char *tty = NULL;
- int success;
int verbose = 0;
int ret = 0;
- int expected_size;
while ((c = getopt_long(argc, argv, "rT:D:c:s:v:", options, NULL)) != -1) {
switch (c) {
bin_PROGRAMS=ao-cal-freq
-AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
+AM_CFLAGS=$(WARN_CFLAGS) -I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
ao_cal_freq_DEPENDENCIES = $(top_builddir)/ao-tools/lib/libao-tools.a
exit(1);
}
-void
-done(struct cc_usb *cc, int code)
-{
- 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;
-}
-
-static int
-starts_with(char *whole, char *prefix)
-{
- int whole_len = strlen(whole);
- int prefix_len = strlen(prefix);
-
- if (prefix_len > whole_len)
- return 0;
- return strncmp(whole, prefix, prefix_len) == 0;
-}
-
static char **
tok(char *line) {
char **strs = malloc (sizeof (char *)), *str;
return strs;
}
-static void
-free_strs(char **strs) {
- char *str;
- int i;
-
- for (i = 0; (str = strs[i]) != NULL; i++)
- free(str);
- free(strs);
-}
-
struct flash {
struct flash *next;
char line[512];
return head;
}
-static void
-free_flash(struct flash *b) {
- struct flash *n;
-
- while (b) {
- n = b->next;
- free_strs(b->strs);
- free(b);
- b = n;
- }
-}
-
-char **
+static char **
find_flash(struct flash *b, char *word0) {
- int i;
for (;b; b = b->next) {
if (strstr(b->line, word0))
return b->strs;
return NULL;
}
-void
-await_key(void)
-{
- struct termios termios, termios_save;
- char buf[512];
-
- tcgetattr(0, &termios);
- termios_save = termios;
- cfmakeraw(&termios);
- tcsetattr(0, TCSAFLUSH, &termios);
- read(0, buf, sizeof (buf));
- tcsetattr(0, TCSAFLUSH, &termios_save);
-}
-
-int
+static int
do_save(struct cc_usb *usb)
{
int ret = 0;
return ret;
}
-int
+static int
do_output(char *output, int cur_cal)
{
printf ("Saving calibration value to file \"%s\"\n", output);
return ret;
}
-int
+static int
do_cal(char *tty, int save, char *output)
{
struct cc_usb *usb = NULL;
main (int argc, char **argv)
{
char *device = NULL;
- char *filename;
- Elf *e;
- unsigned int s;
- int i;
int c;
- int tries;
char *tty = NULL;
- int success;
int verbose = 0;
int save = 1;
int ret = 0;
- int expected_size;
char *output = NULL;
while ((c = getopt_long(argc, argv, "vnT:D:o:", options, NULL)) != -1) {
+++ /dev/null
-ao-chaosread
+++ /dev/null
-bin_PROGRAMS=ao-chaosread
-
-AM_CFLAGS=$(LIBUSB_CFLAGS) -Wall -Wextra
-
-ao_chaosread_LDADD=$(LIBUSB_LIBS)
-
-ao_chaosread_SOURCES = ao-chaosread.c
-
-man_MANS = ao-chaosread.1
+++ /dev/null
-.\"
-.\" Copyright © 2016 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-chaosread" ""
-.SH NAME
-ao-chaosread \- read raw noise source from chaoskey
-.SH SYNOPSIS
-.B "ao-chaosread"
-.SH DESCRIPTION
-.I ao-chaosread
-reads ADC values from the noise source on the attached ChaosKey device.
-.SH OPTIONS
-.TP
-\-s serial | --serial serial
-This selects a ChaosKey by serial number instead of using the first
-one found.
-.TP
-\-l length | --length length
-Set the amount of data to read. Suffixes 'k', 'M' and 'G' are
-supported. The default is 1k.
-.TP
-\-i | --infinite
-Read an unlimited amount of data.
-.TP
-\-b | --bytes
-For each 16-bit value read, output bits 1-8 as a byte, don't output
-bit 0 or bits 9-15 at all.
-.TP
-\-c | --cooked
-Read whitened data from the device. The default is to read raw data
-from the noise source.
-.TP
-\-r | --raw
-Read raw data from the noise source. This is the default.
-.TP
-\-f | --flash
-Read the contents of flash memory on the device. This loops through
-flash memory, so you can read the contents more than once, but there's
-no way to reset the pointer back to the start other than making sure
-you read the whole contents.
-.SH USAGE
-.I ao-chaosread
-reads noise data.
-.SH AUTHOR
-Keith Packard
+++ /dev/null
-/*
- * Copyright © 2016 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 <stdio.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <libusb.h>
-#include <getopt.h>
-#include <string.h>
-#include <strings.h>
-
-#define CHAOS_SIZE 64
-
-#define CHAOS_VENDOR 0x1d50
-#define CHAOS_PRODUCT 0x60c6
-
-struct chaoskey {
- libusb_context *ctx;
- libusb_device_handle *handle;
- int kernel_active;
-};
-
-libusb_device_handle *
-chaoskey_match(libusb_device *dev, char *match_serial)
-{
- struct libusb_device_descriptor desc;
- int ret;
- int match_len;
- char *device_serial = NULL;
- libusb_device_handle *handle = NULL;
-
- ret = libusb_get_device_descriptor(dev, &desc);
- if (ret < 0) {
- fprintf(stderr, "failed to get device descriptor: %s\n", libusb_strerror(ret));
- return 0;
- }
-
- if (desc.idVendor != CHAOS_VENDOR)
- return NULL;
- if (desc.idProduct != CHAOS_PRODUCT)
- return NULL;
-
- ret = libusb_open(dev, &handle);
-
- if (match_serial == NULL)
- return handle;
-
- if (ret < 0) {
- fprintf(stderr, "failed to open device: %s\n", libusb_strerror(ret));
- return NULL;
- }
-
- match_len = strlen(match_serial);
- device_serial = malloc(match_len + 2);
-
- if (!device_serial) {
- fprintf(stderr, "malloc failed\n");
- goto out;
- }
-
- ret = libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber, (unsigned char *) device_serial, match_len + 1);
-
- if (ret < 0) {
- fprintf(stderr, "failed to get serial number: %s\n", libusb_strerror(ret));
- goto out;
- }
-
- device_serial[ret] = '\0';
-
- ret = strcmp(device_serial, match_serial);
- free(device_serial);
- if (ret)
- goto out;
-
- return handle;
-
-out:
- if (handle)
- libusb_close(handle);
- return 0;
-}
-
-struct chaoskey *
-chaoskey_open(char *serial)
-{
- struct chaoskey *ck;
- int ret;
- ssize_t num;
- libusb_device **list;
- int d;
-
- ck = calloc(sizeof (struct chaoskey), 1);
- if (!ck)
- goto out;
- ret = libusb_init(&ck->ctx);
- if (ret ) {
- fprintf(stderr, "libusb_init failed: %s\n", libusb_strerror(ret));
- goto out;
- }
-
- num = libusb_get_device_list(ck->ctx, &list);
- if (num < 0) {
- fprintf(stderr, "libusb_get_device_list failed: %s\n", libusb_strerror(num));
- goto out;
- }
-
- for (d = 0; d < num; d++) {
- libusb_device_handle *handle;
-
- handle = chaoskey_match(list[d], serial);
- if (handle) {
- ck->handle = handle;
- break;
- }
- }
-
- libusb_free_device_list(list, 1);
-
- if (!ck->handle) {
- if (serial)
- fprintf (stderr, "No chaoskey matching %s\n", serial);
- else
- fprintf (stderr, "No chaoskey\n");
- goto out;
- }
-
- ck->kernel_active = libusb_kernel_driver_active(ck->handle, 0);
- if (ck->kernel_active) {
- ret = libusb_detach_kernel_driver(ck->handle, 0);
- if (ret)
- goto out;
- }
-
- ret = libusb_claim_interface(ck->handle, 0);
- if (ret)
- goto out;
-
- return ck;
-out:
- if (ck->kernel_active)
- libusb_attach_kernel_driver(ck->handle, 0);
- if (ck->ctx)
- libusb_exit(ck->ctx);
- free(ck);
- return NULL;
-}
-
-void
-chaoskey_close(struct chaoskey *ck)
-{
- libusb_release_interface(ck->handle, 0);
- if (ck->kernel_active)
- libusb_attach_kernel_driver(ck->handle, 0);
- libusb_close(ck->handle);
- libusb_exit(ck->ctx);
- free(ck);
-}
-
-#define COOKED_ENDPOINT 0x85
-#define RAW_ENDPOINT 0x86
-#define FLASH_ENDPOINT 0x87
-
-int
-chaoskey_read(struct chaoskey *ck, int endpoint, void *buffer, int len)
-{
- uint8_t *buf = buffer;
- int total = 0;
-
- while (len) {
- int ret;
- int transferred;
-
- ret = libusb_bulk_transfer(ck->handle, endpoint, buf, len, &transferred, 10000);
- if (ret) {
- if (total)
- return total;
- else {
- errno = EIO;
- return -1;
- }
- }
- len -= transferred;
- buf += transferred;
- total += transferred;
- }
- return total;
-}
-
-static const struct option options[] = {
- { .name = "serial", .has_arg = 1, .val = 's' },
- { .name = "length", .has_arg = 1, .val = 'l' },
- { .name = "infinite", .has_arg = 0, .val = 'i' },
- { .name = "bytes", .has_arg = 0, .val = 'b' },
- { .name = "cooked", .has_arg = 0, .val = 'c' },
- { .name = "raw", .has_arg = 0, .val = 'r' },
- { .name = "flash", .has_arg = 0, .val = 'f' },
- { 0, 0, 0, 0},
-};
-
-static void usage(char *program)
-{
- fprintf(stderr, "usage: %s [--serial=<serial>] [--length=<length>[kMG]] [--infinite] [--bytes] [--cooked] [--raw] [--flash]\n", program);
- exit(1);
-}
-
-int
-main (int argc, char **argv)
-{
- struct chaoskey *ck;
- uint16_t buf[512];
- int got;
- int c;
- char *serial = NULL;
- char *length_string;
- char *length_end;
- unsigned long length = sizeof(buf);
- int this_time;
- int infinite = 0;
- int bytes = 0;
- int endpoint = RAW_ENDPOINT;
-
- while ((c = getopt_long(argc, argv, "s:l:ibcrf", options, NULL)) != -1) {
- switch (c) {
- case 's':
- serial = optarg;
- break;
- case 'l':
- length_string = optarg;
- length = strtoul(length_string, &length_end, 10);
- if (!strcasecmp(length_end, "k"))
- length *= 1024;
- else if (!strcasecmp(length_end, "m"))
- length *= 1024 * 1024;
- else if (!strcasecmp(length_end, "g"))
- length *= 1024 * 1024 * 1024;
- else if (strlen(length_end))
- usage(argv[0]);
- break;
- case 'i':
- infinite = 1;
- break;
- case 'b':
- bytes = 1;
- break;
- case 'c':
- endpoint = COOKED_ENDPOINT;
- break;
- case 'r':
- endpoint = RAW_ENDPOINT;
- break;
- case 'f':
- endpoint = FLASH_ENDPOINT;
- break;
- default:
- usage(argv[0]);
- break;
- }
- }
-
- ck = chaoskey_open(serial);
- if (!ck)
- exit(1);
-
- if (bytes)
- length *= 2;
-
- while (length || infinite) {
- this_time = sizeof(buf);
- if (!infinite && length < sizeof(buf))
- this_time = (int) length;
- got = chaoskey_read(ck, endpoint, buf, this_time);
- if (got < 0) {
- perror("read");
- exit(1);
- }
- if (bytes) {
- int i;
- for (i = 0; i < got / 2; i++)
- putchar((buf[i] >> 1 & 0xff));
- } else {
- int i;
- int ret;
- for (i = 0; i < got; i += ret) {
- ret = write(1, ((char *) buf) + i, got - i);
- if (ret <= 0) {
- perror("write");
- exit(1);
- }
- }
- }
- length -= got;
- }
- exit(0);
-}
bin_PROGRAMS=ao-dbg
-AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
+AM_CFLAGS=$(WARN_CFLAGS) -I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
AO_DBG_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a
man_MANS = ao-dbg.1
return command_error;
length = (int) end - (int) start + 1;
status = ccdbg_read_memory(s51_dbg, start + 0xff00, memory, length);
+ (void) status;
dump_bytes(memory, length, start, "0x%02x ");
return command_success;
}
return command_error;
length = (int) end - (int) start + 1;
status = ccdbg_read_sfr(s51_dbg, start, memory, length);
+ (void) status;
dump_bytes(memory, length, start, "0x%02x ");
return command_success;
}
return command_error;
length = (int) end - (int) start + 1;
status = ccdbg_read_memory(s51_dbg, start, memory, length);
+ (void) status;
dump_bytes(memory, length, start, "0x%04x ");
return command_success;
}
enable_breakpoint(b);
}
-enum command_result
+static enum command_result
set_breakpoint(uint16_t address, int temporary)
{
int b;
- uint8_t status;
for (b = 0; b < CC_NUM_BREAKPOINTS; b++) {
if (breakpoints[b].enabled == 0)
break;
return command_success;
}
-enum command_result
+static enum command_result
clear_breakpoint(uint16_t address, int temporary)
{
int b;
- uint8_t status;
for (b = 0; b < CC_NUM_BREAKPOINTS; b++) {
if (breakpoints[b].enabled != 0 &&
}
-int
+static int
find_breakpoint(uint16_t address)
{
int b;
enum command_result
command_clear (int argc, char **argv)
{
- int b;
uint16_t address;
enum command_result result;
return clear_breakpoint(address, 0);
}
-void
+static void
cc_stopped(uint8_t status)
{
uint16_t pc;
}
}
-uint8_t
+static uint8_t
cc_step(uint16_t pc)
{
int b;
info_breakpoints(int argc, char **argv)
{
int b;
- uint16_t address;
- enum command_result result;
if (argc == 1) {
s51_printf("Num Type Disp Hit Cnt Address What\n");
}
return command_success;
}
-
+ return command_syntax;
}
static enum command_result
exit(1);
}
-void s51_sigint()
+static void
+s51_sigint(int signum)
{
s51_interrupted = 1;
}
int
main(int argc, char **argv)
{
- int flags, opt;
+ int opt;
char *endptr;
while ((opt = getopt_long(argc, argv, "PVvHhmt:X:c:r:Z:s:S:p:T:", options, NULL)) != -1) {
{
struct pollfd input;
int r;
- int c;
input.fd = fileno(s51_input);
input.events = POLLIN;
#define TRUE 1
#endif
-static int
-string_to_int(char *s, int *v)
-{
- char *endptr;
-
- if (isdigit(s[0]) || s[0] == '-' || s[0] == '+') {
- *v = strtol(s, &endptr, 0);
- if (endptr == s)
- return FALSE;
- } else if (*s == '\'') {
- s++;
- if (*s == '\\') {
- s++;
- switch (*s) {
- case 'n':
- *v = '\n';
- break;
- case 't':
- *v = '\t';
- break;
- default:
- *v = (int) *s;
- break;
- }
- } else
- *v = (int) *s;
- s++;
- if (*s != '\'')
- return FALSE;
- }
- else
- return FALSE;
- return TRUE;
-}
-
struct command_function *
command_string_to_function(struct command_function *functions, char *name)
{
#include <ccdbg.h>
#include <cc.h>
+#include <ctype.h>
extern char *s51_prompt;
extern struct ccdbg *s51_dbg;
bin_PROGRAMS=ao-dump-up
-AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS) $(GNOME_CFLAGS)
+AM_CFLAGS=$(WARN_CFLAGS) -I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS) $(GNOME_CFLAGS)
AO_DUMP_LOG_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a
ao_dump_up_DEPENDENCIES = $(AO_DUMP_LOG_LIBS)
[\--tty \fItty-device\fP]
[\-D \fIaltos-device\fP]
[\--device \fIaltos-device\fP]
+[\--wait]
.SH OPTIONS
.TP
\-T tty-device | --tty tty-device
\-D AltOS-device | --device AltOS-device
Search for a connected device. This forces the program to look
for a specific USB device name.
+.TP
+\--wait
+Wait for a device to appear instead of exiting when no device is found.
.SH DESCRIPTION
.I ao-dump-up
downloads a MicroPeak flight log from a connected MicroPeak USB adapter.
#include <unistd.h>
#include <getopt.h>
#include <string.h>
+#include <ctype.h>
#include "cc-usb.h"
#include "cc.h"
exit(1);
}
-static uint8_t
-log_checksum(int d[8])
-{
- uint8_t sum = 0x5a;
- int i;
-
- for (i = 0; i < 8; i++)
- sum += (uint8_t) d[i];
- return -sum;
-}
-
static int get_nonwhite(struct cc_usb *cc, int timeout)
{
int c;
char *tty = NULL;
char *device = NULL;
int c;
- char line[8192];
int nsamples;
int i;
int crc;
bin_PROGRAMS=ao-dumpflash
-AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
+AM_CFLAGS=$(WARN_CFLAGS) -I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
AO_DUMPLOG_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a
ao_dumpflash_DEPENDENCIES = $(AO_DUMPLOG_LIBS)
int c;
char line[8192];
FILE *out;
- char *filename;
int serial_number = 0;
int freq = 434550;
char *call = "N0CALL";
- int flight = 0;
- char cmd;
int block;
int addr;
int received_addr;
int data[8];
- int done;
int i;
- int column;
int remote = 0;
- int any_valid;
- int invalid;
int storage_size = 0;
- char *out_name;
+ char *out_name = NULL;
while ((c = getopt_long(argc, argv, "T:D:F:C:o:R", options, NULL)) != -1) {
switch (c) {
bin_PROGRAMS=ao-dumplog
-AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS) $(GNOME_CFLAGS)
+AM_CFLAGS=$(WARN_CFLAGS) -I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS) $(GNOME_CFLAGS)
AO_DUMPLOG_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a
ao_dumplog_DEPENDENCIES = $(AO_DUMPLOG_LIBS)
bin_PROGRAMS=ao-edit-telem
-AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
+AM_CFLAGS=$(WARN_CFLAGS) -I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
AO_POSTFLIGHT_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a
ao_edit_telem_DEPENDENCIES = $(AO_POSTFLIGHT_LIBS)
static void
dump_saved(void);
-void
+static void
doit(union ao_telemetry_all *telem)
{
double lat, lon;
main (int argc, char **argv)
{
char line[80];
- int c, i, ret;
- char *s;
+ int c, i, ret = 0;
FILE *file;
- int serial;
+
while ((c = getopt_long(argc, argv, "l:L:", options, NULL)) != -1) {
switch (c) {
case 'L':
ret++;
continue;
}
- s = strstr(argv[i], "-serial-");
- if (s)
- serial = atoi(s + 8);
- else
- serial = 0;
while (fgets(line, sizeof (line), file)) {
union ao_telemetry_all telem;
bin_PROGRAMS=ao-eeprom
-AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
+AM_CFLAGS=$(WARN_CFLAGS) -I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
AO_EEPROM_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a
ao_eeprom_DEPENDENCIES = $(AO_EEPROM_LIBS)
-ao_eeprom_LDADD=$(AO_EEPROM_LIBS) $(LIBUSB_LIBS)
+ao_eeprom_LDADD=$(AO_EEPROM_LIBS) -ljson-c -lm
ao_eeprom_SOURCES = ao-eeprom.c
.\"
.TH AO-EEPROM 1 "ao-eeprom" ""
.SH NAME
-ao-eeprom \- Fetch eeprom contents from TeleMetrum device
+ao-eeprom \- Analyze an eeprom log
.SH SYNOPSIS
.B "ao-eeprom"
-[\-T \fItty-device\fP]
-[\--tty \fItty-device\fP]
-[\-D \fIaltos-device\fP]
-[\--device \fIaltos-device\fP]
+[\--raw]
+[\--csum]
+[\--verbose]
+[\--len <record-len>]
+{flight.eeprom} ...
.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.
+\-r | --raw
+This option makes ao-eeprom dump the raw bytes of each
+log record in hex format.
.TP
-\-D AltOS-device | --device AltOS-device
-Search for a connected device. This requires an argument of one of the
-following forms:
-.IP
-TeleMetrum:2
-.br
-TeleMetrum
-.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.
+\-c | --csum
+This option makes ao-eeprom dump records that have checksum errors. By default,
+ao-eeprom skips such records.
+\-v | --verbose
+This option makes ao-eeprom report when records are skipped due to
+checksum errors.
+\-l <record-len> | --len <record-len
+Specify the eeprom record length rather than letting ao-eeprom
+automatically determine it based on the file contents.
.SH DESCRIPTION
.I ao-eeprom
-downloads the eeprom contents from a connected TeleMetrum device.
-.SH USAGE
-.I ao-eeprom
-connects to the specified target device and dumps each block of the
-eeprom to stdout in hexadecimal bytes.
+reads the specified eeprom log and display the contents of each
+record.
.SH AUTHOR
Keith Packard
#include <stdio.h>
#include <stdlib.h>
+#include <stdbool.h>
#include <unistd.h>
#include <getopt.h>
-#include "cc-usb.h"
-#include "cc.h"
-
-#define NUM_BLOCK 512
+#include <ao-eeprom-read.h>
+#include <ao-atmosphere.h>
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 = "csum", .has_arg = 0, .val = 'c' },
+ { .name = "verbose", .has_arg = 0, .val = 'v' },
+ { .name = "len", .has_arg = 1, .val = 'l' },
{ 0, 0, 0, 0},
};
static void usage(char *program)
{
- fprintf(stderr, "usage: %s [--tty <tty-name>] [--device <device-name>\n", program);
+ fprintf(stderr, "usage: %s [--raw] [--csum] [--verbose] [--len <record-len>] {flight.eeprom} ...\n", program);
exit(1);
}
+static bool
+ao_csum_valid(uint8_t *d, int len)
+{
+ uint8_t sum = 0x5a;
+ int i;
+ for (i = 0; i < len; i++)
+ sum += d[i];
+ return sum == 0;
+}
+
+static void
+ao_ms5607(uint32_t pres, uint32_t temp, struct ao_eeprom *eeprom, bool is_ms5611)
+{
+ struct ao_ms5607_sample ms5607_sample = { .pres = pres, .temp = temp };
+ struct ao_ms5607_value ms5607_value;
+
+ ao_ms5607_convert(&ms5607_sample, &ms5607_value,
+ &eeprom->ms5607_prom, is_ms5611);
+ printf(" pres %9u %7.3f kPa %7.1f m temp %9u %6.2f °C",
+ pres,
+ ms5607_value.pres / 1000.0,
+ ao_pressure_to_altitude(ms5607_value.pres),
+ temp,
+ ms5607_value.temp / 100.0);
+}
+
+#define GRAVITY 9.80665
+
+static void
+ao_accel(int16_t accel, struct ao_eeprom *eeprom)
+{
+ double accel_2g = eeprom->config.accel_minus_g - eeprom->config.accel_plus_g;
+ double accel_scale = GRAVITY * 2.0 / accel_2g;
+ printf(" accel %6d %7.2f m/s²",
+ accel, (eeprom->config.accel_plus_g - accel) * accel_scale);
+}
+
+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])
+
+static const char *
+ao_state_name(uint16_t state)
+{
+ if (state < NUM_STATE)
+ return state_names[state];
+ return "UNKNOWN";
+}
+
+static void
+ao_state(uint16_t state, uint16_t reason)
+{
+ printf(" state %5u %s reason %5u",
+ state, ao_state_name(state), reason);
+}
+
+static double
+ao_adc_to_volts(int16_t value, int16_t max_adc, double ref, double r1, double r2)
+{
+ return ref * ((double) value / max_adc) * (r1 + r2) / r2;
+}
+
+static void
+ao_volts(const char *name, int16_t value, int16_t max_adc, double ref, double r1, double r2)
+{
+ printf(" %s %5d",
+ name, value);
+ if (r1 && r2 && ref)
+ printf(" %6.3f V", ao_adc_to_volts(value, max_adc, ref, r1, r2));
+}
+
+static double lb_to_n(double lb)
+{
+ return lb / 0.22480894;
+}
+
+static double psi_to_pa(double psi)
+{
+ return psi * 6894.76;
+}
+
+static double
+ao_volts_to_newtons(double volts)
+{
+ /* this is a total guess */
+ return lb_to_n(volts * 57.88645 * GRAVITY);
+}
+
+static void
+ao_thrust(int16_t value, int16_t max_adc, double ref, double r1, double r2)
+{
+ printf(" thrust %5d", value);
+ if (r1 && r2 && ref) {
+ double volts = ao_adc_to_volts(value, max_adc, ref, r1, r2);
+ printf(" %6.3f V %8.1f N", volts, ao_volts_to_newtons(volts));
+ }
+}
+
+static void
+ao_pressure(int16_t value, int16_t max_adc, double ref, double r1, double r2)
+{
+ printf(" pressure %5d", value);
+ if (r1 && r2 && ref) {
+ double volts = ao_adc_to_volts(value, max_adc, ref, r1, r2);
+ if (volts < 0.5) volts = 0.5;
+ if (volts > 4.5) volts = 4.5;
+
+ double psi = (volts - 0.5) / 4.0 * 2500.0;
+ double pa = psi_to_pa(psi);
+ printf(" %9.3f kPa", pa / 1000.0);
+ }
+}
+
+#if 0
+static uint16_t
+uint16(uint8_t *bytes, int off)
+{
+ return (uint16_t) bytes[off] | (((uint16_t) bytes[off+1]) << 8);
+}
+
+static int16_t
+int16(uint8_t *bytes, int off)
+{
+ return (int16_t) uint16(bytes, off);
+}
+
+static uint32_t
+uint32(uint8_t *bytes, int off)
+{
+ return (uint32_t) bytes[off] | (((uint32_t) bytes[off+1]) << 8) |
+ (((uint32_t) bytes[off+2]) << 16) |
+ (((uint32_t) bytes[off+3]) << 24);
+}
+
+static int32_t
+int32(uint8_t *bytes, int off)
+{
+ return (int32_t) uint32(bytes, off);
+}
+#endif
+
+static uint32_t
+uint24(uint8_t *bytes, int off)
+{
+ return (uint32_t) bytes[off] | (((uint32_t) bytes[off+1]) << 8) |
+ (((uint32_t) bytes[off+2]) << 16);
+}
+
+static int32_t
+int24(uint8_t *bytes, int off)
+{
+ return (int32_t) uint24(bytes, off);
+}
+
int
main (int argc, char **argv)
{
- struct cc_usb *cc;
- int block;
- uint8_t bytes[2 * 32 * (2 + 8)];
- uint8_t *b;
- int i, j;
- uint32_t addr;
- char *tty = NULL;
- char *device = NULL;
- int c;
-
- while ((c = getopt_long(argc, argv, "T:D:", options, NULL)) != -1) {
+ struct ao_eeprom *eeprom;
+ FILE *file;
+ int c;
+ bool raw = false;
+ bool csum = false;
+ bool verbose = false;
+ int arg_len = 0;
+ char *end;
+ int ret = 0;
+ int i;
+
+ while ((c = getopt_long(argc, argv, "rcvl:", options, NULL)) != -1) {
switch (c) {
- case 'T':
- tty = optarg;
+ case 'r':
+ raw = true;
break;
- case 'D':
- device = optarg;
+ case 'c':
+ csum = true;
+ break;
+ case 'v':
+ verbose = true;
+ break;
+ case 'l':
+ arg_len = strtol(optarg, &end, 0);
+ if (!*optarg || *end)
+ usage(argv[0]);
break;
default:
usage(argv[0]);
break;
}
}
- if (!tty)
- tty = cc_usbdevs_find_by_arg(device, "TeleMetrum");
- if (!tty)
- tty = getenv("ALTOS_TTY");
- if (!tty)
- tty="/dev/ttyACM0";
- cc = cc_usb_open(tty);
- if (!cc)
- exit(1);
- for (block = 0; block < NUM_BLOCK; block += 2) {
- cc_queue_read(cc, bytes, sizeof (bytes));
- cc_usb_printf(cc, "e %x\ne %x\n", block, block + 1);
- cc_usb_sync(cc);
- for (i = 0; i < 32 * 2; i++) {
- b = bytes + (i * 10);
- addr = block * 256 + i * 8;
- printf ("%06x", addr);
- for (j = 0; j < 8; j++) {
- printf (" %02x", b[j+2]);
+ for (i = optind; i < argc; i++) {
+ file = fopen(argv[i], "r");
+ if (!file) {
+ perror(argv[i]);
+ ret++;
+ continue;
+ }
+ eeprom = ao_eeprom_read(file);
+ fclose(file);
+ if (!eeprom) {
+ perror(argv[i]);
+ ret++;
+ continue;
+ }
+ int len = 0;
+ bool is_ms5611 = false;
+
+ int64_t current_tick = 0;
+ int64_t first_tick = 0x7fffffffffffffffLL;
+
+ double sense_r1 = 0.0, sense_r2 = 0.0;
+ double batt_r1 = 0.0, batt_r2 = 0.0;
+ double adc_ref = 0.0;
+ int16_t max_adc = 0;
+
+ switch (eeprom->log_format) {
+ case AO_LOG_FORMAT_TELEMEGA_OLD:
+ len = 32;
+ break;
+ case AO_LOG_FORMAT_EASYMINI1:
+ len = 16;
+ max_adc = 32767;
+ if (eeprom->serial_number < 1000)
+ adc_ref = 3.0;
+ else
+ adc_ref = 3.3;
+ batt_r1 = sense_r1 = 100e3;
+ batt_r2 = sense_r2 = 27e3;
+ break;
+ case AO_LOG_FORMAT_TELEMETRUM:
+ len = 16;
+ max_adc = 4095;
+ adc_ref = 3.3;
+ batt_r1 = 5600;
+ batt_r2 = 10000;
+ sense_r1 = 100e3;
+ sense_r2 = 27e3;
+ break;
+ case AO_LOG_FORMAT_TELEMINI2:
+ len = 16;
+ break;
+ case AO_LOG_FORMAT_TELEGPS:
+ len = 32;
+ break;
+ case AO_LOG_FORMAT_TELEMEGA:
+ len = 32;
+ max_adc = 4095;
+ adc_ref = 3.3;
+ batt_r1 = 5600;
+ batt_r2 = 10000;
+ sense_r1 = 100e3;
+ sense_r2 = 27e3;
+ break;
+ case AO_LOG_FORMAT_DETHERM:
+ len = 16;
+ break;
+ case AO_LOG_FORMAT_TELEMINI3:
+ len = 16;
+ max_adc = 4095;
+ adc_ref = 3.3;
+ batt_r1 = 5600;
+ batt_r2 = 10000;
+ sense_r1 = 100e3;
+ sense_r2 = 27e3;
+ break;
+ case AO_LOG_FORMAT_TELEFIRETWO:
+ len = 32;
+ max_adc = 4095;
+ adc_ref = 3.3;
+ sense_r1 = batt_r1 = 5600;
+ sense_r2 = batt_r2 = 10000;
+ break;
+ case AO_LOG_FORMAT_EASYMINI2:
+ len = 16;
+ max_adc = 4095;
+ adc_ref = 3.3;
+ batt_r1 = sense_r1 = 100e3;
+ batt_r2 = sense_r2 = 27e3;
+ break;
+ case AO_LOG_FORMAT_TELEMEGA_3:
+ len = 32;
+ max_adc = 4095;
+ adc_ref = 3.3;
+ batt_r1 = 5600;
+ batt_r2 = 10000;
+ sense_r1 = 100e3;
+ sense_r2 = 27e3;
+ break;
+ case AO_LOG_FORMAT_EASYMEGA_2:
+ len = 32;
+ max_adc = 4095;
+ adc_ref = 3.3;
+ batt_r1 = 5600;
+ batt_r2 = 10000;
+ sense_r1 = 100e3;
+ sense_r2 = 27e3;
+ break;
+ case AO_LOG_FORMAT_TELESTATIC:
+ len = 32;
+ break;
+ case AO_LOG_FORMAT_MICROPEAK2:
+ len = 2;
+ break;
+ }
+ if (arg_len)
+ len = arg_len;
+ if (verbose)
+ printf("config major %d minor %d log format %d total %u len %d\n",
+ eeprom->config.major,
+ eeprom->config.minor,
+ eeprom->log_format,
+ eeprom->len,
+ len);
+
+ uint32_t pos;
+ for (pos = 0; pos < eeprom->len; pos += len) {
+ int i;
+ if (raw) {
+ printf("%9u", pos);
+ for (i = 0; i < len; i++)
+ printf(" %02x", eeprom->data[pos + i]);
+ } else {
+ struct ao_log_mega *log_mega;
+ struct ao_log_mini *log_mini;
+ struct ao_log_metrum *log_metrum;
+ struct ao_log_gps *log_gps;
+ struct ao_log_firetwo *log_firetwo;
+
+ if (!csum && !ao_csum_valid(&eeprom->data[pos], len)) {
+ if (verbose)
+ printf("\tchecksum error at %d\n", pos);
+ continue;
+ }
+
+ struct ao_log_header *log_header = (struct ao_log_header *) &eeprom->data[pos];
+
+ if (first_tick == 0x7fffffffffffffffLL) {
+ current_tick = first_tick = log_header->tick;
+ } else {
+ int16_t diff = (int16_t) (log_header->tick - (uint16_t) current_tick);
+
+ current_tick += diff;
+ }
+ printf("type %c tick %5u %6.2f S", log_header->type, log_header->tick, (current_tick - first_tick) / 100.0);
+
+ switch (eeprom->log_format) {
+ case AO_LOG_FORMAT_TELEMEGA_OLD:
+ case AO_LOG_FORMAT_TELEMEGA:
+ case AO_LOG_FORMAT_TELEMEGA_3:
+ case AO_LOG_FORMAT_EASYMEGA_2:
+ log_mega = (struct ao_log_mega *) &eeprom->data[pos];
+ switch (log_mega->type) {
+ case AO_LOG_FLIGHT:
+ printf(" serial %5u flight %5u ground_accel %6d ground_pres %9u",
+ eeprom->serial_number,
+ log_mega->u.flight.flight,
+ log_mega->u.flight.ground_accel,
+ log_mega->u.flight.ground_pres);
+ printf(" along %6d aross %6d through %6d",
+ log_mega->u.flight.ground_accel_along,
+ log_mega->u.flight.ground_accel_across,
+ log_mega->u.flight.ground_accel_through);
+ printf(" roll %6d pitch %6d yaw %6d",
+ log_mega->u.flight.ground_roll,
+ log_mega->u.flight.ground_pitch,
+ log_mega->u.flight.ground_yaw);
+ break;
+ case AO_LOG_STATE:
+ ao_state(log_mega->u.state.state,
+ log_mega->u.state.reason);
+ break;
+ case AO_LOG_SENSOR:
+ ao_ms5607(log_mega->u.sensor.pres,
+ log_mega->u.sensor.temp,
+ eeprom, is_ms5611);
+ printf(" accel_x %6d accel_y %6d accel_z %6d",
+ log_mega->u.sensor.accel_x,
+ log_mega->u.sensor.accel_y,
+ log_mega->u.sensor.accel_z);
+ printf (" gyro_x %6d gyro_y %6d gyro_z %6d",
+ log_mega->u.sensor.gyro_x,
+ log_mega->u.sensor.gyro_y,
+ log_mega->u.sensor.gyro_z);
+ printf (" mag_x %6d mag_y %6d mag_z %6d",
+ log_mega->u.sensor.mag_x,
+ log_mega->u.sensor.mag_y,
+ log_mega->u.sensor.mag_z);
+ ao_accel(log_mega->u.sensor.accel, eeprom);
+ break;
+ case AO_LOG_TEMP_VOLT:
+ ao_volts("v_batt",
+ log_mega->u.volt.v_batt,
+ max_adc,
+ adc_ref,
+ batt_r1, batt_r2);
+ ao_volts("v_pbatt",
+ log_mega->u.volt.v_pbatt,
+ max_adc,
+ adc_ref,
+ sense_r1, sense_r2);
+ printf(" n_sense %1d",
+ log_mega->u.volt.n_sense);
+ for (i = 0; i < log_mega->u.volt.n_sense; i++) {
+ char name[10];
+ sprintf(name, "sense%d", i);
+ ao_volts(name,
+ log_mega->u.volt.sense[i],
+ max_adc,
+ adc_ref,
+ sense_r1, sense_r2);
+ }
+ printf(" pyro %04x", log_mega->u.volt.pyro);
+ break;
+ case AO_LOG_GPS_TIME:
+ printf(" lat %10.7f ° lon %10.7f ° alt %8d m",
+ log_mega->u.gps.latitude / 10000000.0,
+ log_mega->u.gps.longitude/ 10000000.0,
+ (int32_t) (log_mega->u.gps.altitude_low |
+ (log_mega->u.gps.altitude_high << 16)));
+ printf(" time %02d:%02d:%02d %04d-%02d-%02d flags %02x",
+ log_mega->u.gps.hour,
+ log_mega->u.gps.minute,
+ log_mega->u.gps.second,
+ log_mega->u.gps.year + 2000,
+ log_mega->u.gps.month,
+ log_mega->u.gps.day,
+ log_mega->u.gps.flags);
+ printf(" course %3d ground_speed %5u climb_rate %6d pdop %3d hdop %3d vdop %3d mode %3d",
+ log_mega->u.gps.course,
+ log_mega->u.gps.ground_speed,
+ log_mega->u.gps.climb_rate,
+ log_mega->u.gps.pdop,
+ log_mega->u.gps.hdop,
+ log_mega->u.gps.vdop,
+ log_mega->u.gps.mode);
+ break;
+ case AO_LOG_GPS_SAT:
+ printf(" channels %2d",
+ log_mega->u.gps_sat.channels);
+ for (i = 0; i < 12; i++) {
+ printf(" svid %3d c_n %2d",
+ log_mega->u.gps_sat.sats[i].svid,
+ log_mega->u.gps_sat.sats[i].c_n);
+ }
+ break;
+ }
+ break;
+ case AO_LOG_FORMAT_EASYMINI1:
+ case AO_LOG_FORMAT_EASYMINI2:
+ case AO_LOG_FORMAT_TELEMINI2:
+ case AO_LOG_FORMAT_TELEMINI3:
+ log_mini = (struct ao_log_mini *) &eeprom->data[pos];
+ switch (log_mini->type) {
+ case AO_LOG_FLIGHT:
+ printf(" serial %5u flight %5u ground_pres %9u",
+ eeprom->serial_number,
+ log_mini->u.flight.flight,
+ log_mini->u.flight.ground_pres);
+ break;
+ case AO_LOG_STATE:
+ ao_state(log_mini->u.state.state,
+ log_mini->u.state.reason);
+ break;
+ case AO_LOG_SENSOR:
+ ao_ms5607(int24(log_mini->u.sensor.pres, 0),
+ int24(log_mini->u.sensor.temp, 0),
+ eeprom, is_ms5611);
+ ao_volts("sense_a",
+ log_mini->u.sensor.sense_a, max_adc,
+ adc_ref, sense_r1, sense_r2);
+ ao_volts("sense_m",
+ log_mini->u.sensor.sense_m, max_adc,
+ adc_ref, sense_r1, sense_r2);
+ ao_volts("v_batt",
+ log_mini->u.sensor.v_batt, max_adc,
+ adc_ref, batt_r1, batt_r2);
+ break;
+ } /* */
+ break;
+ case AO_LOG_FORMAT_TELEMETRUM:
+ log_metrum = (struct ao_log_metrum *) &eeprom->data[pos];
+ switch (log_metrum->type) {
+ case AO_LOG_FLIGHT:
+ printf(" serial %5u flight %5u ground_accel %6d ground_pres %9u ground_temp %9u",
+ eeprom->serial_number,
+ log_metrum->u.flight.flight,
+ log_metrum->u.flight.ground_accel,
+ log_metrum->u.flight.ground_pres,
+ log_metrum->u.flight.ground_temp);
+ break;
+ case AO_LOG_SENSOR:
+ ao_ms5607(log_metrum->u.sensor.pres,
+ log_metrum->u.sensor.temp,
+ eeprom, is_ms5611);
+ ao_accel(log_metrum->u.sensor.accel, eeprom);
+ break;
+ case AO_LOG_TEMP_VOLT:
+ ao_volts("v_batt",
+ log_metrum->u.volt.v_batt, max_adc,
+ adc_ref, batt_r1, batt_r2);
+ ao_volts("sense_a",
+ log_metrum->u.volt.sense_a, max_adc,
+ adc_ref, sense_r1, sense_r2);
+ ao_volts("sense_m",
+ log_metrum->u.volt.sense_m, max_adc,
+ adc_ref, sense_r1, sense_r2);
+ break;
+ case AO_LOG_DEPLOY:
+ break;
+ case AO_LOG_STATE:
+ ao_state(log_metrum->u.state.state,
+ log_metrum->u.state.reason);
+ break;
+ case AO_LOG_GPS_TIME:
+ printf(" time %02d:%02d:%02d 20%02d-%02d-%02d flags %02x pdop %3u",
+ log_metrum->u.gps_time.hour,
+ log_metrum->u.gps_time.minute,
+ log_metrum->u.gps_time.second,
+ log_metrum->u.gps_time.year,
+ log_metrum->u.gps_time.month,
+ log_metrum->u.gps_time.day,
+ log_metrum->u.gps_time.flags,
+ log_metrum->u.gps_time.pdop);
+ break;
+ case AO_LOG_GPS_SAT:
+ printf(" channels %2d more %1d",
+ log_metrum->u.gps_sat.channels,
+ log_metrum->u.gps_sat.more);
+ for (i = 0; i < 4; i++) {
+ printf(" svid %3d c_n %2d",
+ log_metrum->u.gps_sat.sats[i].svid,
+ log_metrum->u.gps_sat.sats[i].c_n);
+ }
+ break;
+ case AO_LOG_GPS_POS:
+ printf(" lat %10.7f° lon %10.7f° alt %8d m",
+ log_metrum->u.gps.latitude / 10000000.0,
+ log_metrum->u.gps.longitude/ 10000000.0,
+ (int32_t) (log_metrum->u.gps.altitude_low |
+ (log_metrum->u.gps.altitude_high << 16)));
+ break;
+ default:
+ printf(" unknown");
+ }
+ break;
+ case AO_LOG_FORMAT_TELEFIRETWO:
+ log_firetwo = (struct ao_log_firetwo *) &eeprom->data[pos];
+ switch (log_firetwo->type) {
+ case AO_LOG_FLIGHT:
+ printf(" serial %5u flight %5u",
+ eeprom->serial_number,
+ log_firetwo->u.flight.flight);
+ break;
+ case AO_LOG_STATE:
+ ao_state(log_firetwo->u.state.state,
+ log_firetwo->u.state.reason);
+ break;
+ case AO_LOG_SENSOR:
+ ao_pressure(log_firetwo->u.sensor.pressure,
+ max_adc, adc_ref,
+ sense_r1, sense_r2);
+ ao_thrust(log_firetwo->u.sensor.thrust,
+ max_adc, adc_ref,
+ sense_r1, sense_r2);
+ for (i = 0; i < 4; i++) {
+ char name[20];
+ sprintf(name, "thermistor%d", i);
+ ao_volts(name,
+ log_firetwo->u.sensor.thermistor[i],
+ max_adc, adc_ref,
+ sense_r1, sense_r2);
+ }
+ break;
+ }
+ break;
+ case AO_LOG_FORMAT_TELEGPS:
+ log_gps = (struct ao_log_gps *) &eeprom->data[pos];
+ (void) log_gps;
+ break;
+ case AO_LOG_FORMAT_DETHERM:
+ break;
+ }
}
- printf ("\n");
+ printf("\n");
}
}
- cc_usb_close(cc);
- exit (0);
+ return ret;
}
bin_PROGRAMS=ao-elftohex
-AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
+AM_CFLAGS=$(WARN_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)
bin_PROGRAMS=ao-list
-AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
+AM_CFLAGS=$(WARN_CFLAGS) -I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
AO_LIST_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a
ao_list_DEPENDENCIES = $(AO_LIST_LIBS)
bin_PROGRAMS=ao-load
-AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
+AM_CFLAGS=$(WARN_CFLAGS) -I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
AO_LOAD_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a
ao_load_DEPENDENCIES = $(AO_LOAD_LIBS)
printf (" %02x", data[i]);
printf("\n");
memcpy(image->data + addr - image->address, data, len);
+ return 1;
}
static const struct option options[] = {
main (int argc, char **argv)
{
struct ccdbg *dbg;
- uint8_t status;
- uint16_t pc;
struct ao_hex_file *hex;
struct ao_hex_image *image;
char *filename;
bin_PROGRAMS=ao-makebin
-AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
+AM_CFLAGS=$(WARN_CFLAGS) -I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
AO_ELFTOHEX_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a
ao_makebin_DEPENDENCIES = $(AO_ELFTOHEX_LIBS)
bin_PROGRAMS=ao-mega
-AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
+AM_CFLAGS=$(WARN_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)
bin_PROGRAMS=ao-postflight
-AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS) $(GNOME_CFLAGS) $(PLPLOT_CFLAGS)
+AM_CFLAGS=$(WARN_CFLAGS) -I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS) $(GNOME_CFLAGS) $(PLPLOT_CFLAGS)
AO_POSTFLIGHT_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a
ao_postflight_DEPENDENCIES = $(AO_POSTFLIGHT_LIBS)
bin_PROGRAMS=ao-rawload
-AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
+AM_CFLAGS=$(WARN_CFLAGS) -I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
AO_RAWLOAD_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a
ao_rawload_DEPENDENCIES = $(AO_RAWLOAD_LIBS)
main (int argc, char **argv)
{
struct ccdbg *dbg;
- uint8_t status;
- uint16_t pc;
struct ao_hex_file *hex;
struct ao_hex_image *image;
char *filename;
bin_PROGRAMS=ao-send-telem
-AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
+AM_CFLAGS=$(WARN_CFLAGS) -I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
AO_POSTFLIGHT_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a
ao_send_telem_DEPENDENCIES = $(AO_POSTFLIGHT_LIBS)
static void
send_telem(struct cc_usb *cc, union ao_telemetry_all *telem)
{
- int rssi = (int8_t) telem->generic.rssi / 2 - 74;
int i;
uint8_t *b;
char line[80];
int c, i, ret = 0;
int freq = 434550;
- char *s;
FILE *file;
- int serial;
uint16_t last_tick;
int started;
int realtime = 0;
if (fake) {
union ao_telemetry_all telem;
- uint16_t tick;
int i;
memset(&telem, '\0', sizeof (telem));
bin_PROGRAMS=ao-sky-flash
-AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
+AM_CFLAGS=$(WARN_CFLAGS) -I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
AO_SKY_FLASH_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a
ao_sky_flash_DEPENDENCIES = $(AO_SKY_FLASH_LIBS)
size = ftell(file);
rewind(file);
- sprintf(message, "BINSIZE = %d Checksum = %d Loopnumber = %d ", size, cksum, 1);
+ sprintf(message, "BINSIZE = %ld Checksum = %d Loopnumber = %d ", size, cksum, 1);
ret = skytraq_cmd_wait(fd, message, strlen(message) + 1, "OK", 20000);
if (ret < 0)
#include <stdint.h>
#include <stdarg.h>
#include <getopt.h>
+#include <unistd.h>
#include "cc.h"
static const struct option options[] = {
{ .name = "tty", .has_arg = 1, .val = 'T' },
{ .name = "device", .has_arg = 1, .val = 'D' },
- { .name = "loader", .has_arg = 1, .val = 'l' },
{ .name = "firmware", .has_arg = 1, .val = 'f' },
{ .name = "query", .has_arg = 0, .val = 'q' },
{ .name = "raw", .has_arg = 0, .val = 'r' },
fprintf(stderr,
"usage: %s [--tty <tty-name>]\n"
" [--device <device-name>]\n"
- " [--loader <srec bootloader file>]\n"
" [--firmware <binary firmware file>]\n"
" [--query]\n"
" [--quiet]\n"
exit(1);
}
-int
+static int
skytraq_expect(int fd, uint8_t want, int timeout) {
int c;
return 0;
}
-int
+static int
skytraq_wait_reply(int fd, uint8_t reply, uint8_t *buf, uint8_t reply_len) {
for(;;) {
uint8_t a, b;
- uint8_t cksum_computed, cksum_read;
+ uint8_t cksum_computed;
int len;
switch (skytraq_expect(fd, 0xa0, 10000)) {
case -1:
main(int argc, char **argv)
{
int fd;
- char buf[512];
int ret;
- FILE *input;
- long size;
- unsigned char cksum;
int c;
- char message[1024];
char *tty = NULL;
char *device = NULL;
- char *loader = "srec_115200.bin";
char *file = NULL;
int query = 0;
int raw = 0;
case 'D':
device = optarg;
break;
- case 'l':
- loader = optarg;
- break;
case 'f':
file = optarg;
break;
skytraq_setcomm(int fd, int baudrate);
int
-skytraq_write(int fd, const char *data, int len);
+skytraq_write(int fd, const void *data, int len);
int
skytraq_waitchar(int fd, int timeout);
void
skytraq_flush(int fd);
+int
+skytraq_millis(void);
+
+void
+skytraq_dbg_newline(void);
+
int
skytraq_cmd_wait(int fd, const char *message, int len, const char *status, int timeout);
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-#define _BSD_SOURCE
+#define _DEFAULT_SOURCE 1
#include <termios.h>
#include <unistd.h>
#include <sys/types.h>
#define US_PER_CHAR (1000000 / BPS)
int
-skytraq_write(int fd, const char *data, int len)
+skytraq_write(int fd, const void *d, int len)
{
- const char *d = data;
+ const char *data = d;
int r;
- int us;
skytraq_dbg_printf (0, "%4d: ", len);
if (len < 70)
r = write(fd, data, this_time);
if (r <= 0)
return r;
- us = r * US_PER_CHAR;
usleep(r * US_PER_CHAR);
data += r;
len -= r;
int i;
uint8_t cksum;
- int target_baudrate;
+ int target_baudrate = 0;
switch(baudrate)
{
case 4800:
bin_PROGRAMS=ao-stmload
-AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(STLINK_CFLAGS) $(LIBUSB_CFLAGS)
+AM_CFLAGS=$(WARN_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)
bin_PROGRAMS=ao-telem
-AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
+AM_CFLAGS=$(WARN_CFLAGS) -I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
AO_POSTFLIGHT_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a
ao_telem_DEPENDENCIES = $(AO_POSTFLIGHT_LIBS)
.\"
.TH AO-TELEM 1 "ao-telem" ""
.SH NAME
-ao-telem \- Analyse a flight log (either telemetry or eeprom)
+ao-telem \- Analyze a telemetry log
.SH SYNOPSIS
.B "ao-telem"
-[\-s <summary-file>]
-[\--summary=<summary-file>]
-[\-d <detail-file>]
-[\--detail=<detail-file>]
-[\-r <raw-file>]
-[\--raw=<raw-file>]
-[\-p <plot-file>]
-[\--plot=<plot-file>]
-[\-g <gps-file]
-[\--gps=<gps-file]
-[\-k <kml-file]
-[\--kml=<kml-file]
-{flight.eeprom|flight.telem}
+[\--crc]
+{flight.telem} ...
+.SH OPTIONS
+.TP
+\-c | --crc
+This option makes ao-telem analyze records with CRC errors. By
+default, these records are skipped.
.SH DESCRIPTION
.I ao-telem
-reads the specified flight log and produces several different kinds of
-output.
-.IP Summary
-By default, summary information is shown on stdout. With the --summary
-option, it can be redirected to a file.
-.IP Detail
-When requested with the --detail option, a filtered version of the
-flight position, speed and acceleration are written to the specified
-file.
-.IP Raw
-The --raw option writes the unfiltered, but converted acceleration
-and height data to the specified file.
-.IP Plot
-The --plot option writes plots of height, speed and acceleration to
-the specified file in .svg format
-.IP GPS
-The --gps option writes the recorded GPS data to the specified file in
-three columns.
-.IP KML
-The --kml option writes the recorded GPS data to the specified file in
-Keyhole Markup Language format, which can be displayed in Googleearth.
+reads the specified telemetry log and display the contents of each
+record.
.SH AUTHOR
Keith Packard
static void usage(char *program)
{
- fprintf(stderr, "usage: %s\n"
- "\t{flight-log} ...\n", program);
+ fprintf(stderr, "usage: %s [--crc] {flight.telem} ...\n",program);
exit(1);
}
main (int argc, char **argv)
{
char line[80];
- int c, i, ret;
- char *s;
+ int c, i, ret = 0;
FILE *file;
- int serial;
int ignore_crc = 0;
while ((c = getopt_long(argc, argv, "c", options, NULL)) != -1) {
switch (c) {
ret++;
continue;
}
- s = strstr(argv[i], "-serial-");
- if (s)
- serial = atoi(s + 8);
- else
- serial = 0;
while (fgets(line, sizeof (line), file)) {
union ao_telemetry_all telem;
char call[AO_MAX_CALLSIGN+1];
memcpy(version, telem.configuration.version, AO_MAX_VERSION);
call[AO_MAX_CALLSIGN] = '\0';
version[AO_MAX_CALLSIGN] = '\0';
- printf ("device %3d flight %5d config %3d.%03d delay %2d main %4d",
+ printf ("device %3d flight %5d config %3d.%03d delay %2d main %4d log_max %5d",
telem.configuration.device,
telem.configuration.flight,
telem.configuration.config_major,
(telem.location.flags & (1 << 6)) ? ",date" : "",
(telem.location.flags & (1 << 7)) ? ",course" : "");
printf (" alt %5d lat %12.7f lon %12.7f",
- telem.location.altitude,
+ AO_TELEMETRY_LOCATION_ALTITUDE(&telem.location),
telem.location.latitude / 1e7,
telem.location.longitude / 1e7);
if ((telem.location.flags & (1 << 6)) != 0) {
bin_PROGRAMS=ao-test-baro
-AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
+AM_CFLAGS=$(WARN_CFLAGS) -I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
ao_test_baro_DEPENDENCIES = $(top_builddir)/ao-tools/lib/libao-tools.a
exit(1);
}
-void
+static void
done(struct cc_usb *cc, int code)
{
/* cc_usb_printf(cc, "a\n"); */
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;
-}
-
-static int
-starts_with(char *whole, char *prefix)
-{
- int whole_len = strlen(whole);
- int prefix_len = strlen(prefix);
-
- if (prefix_len > whole_len)
- return 0;
- return strncmp(whole, prefix, prefix_len) == 0;
-}
-
static char **
tok(char *line) {
char **strs = malloc (sizeof (char *)), *str;
}
}
-char **
+static char **
find_baro(struct baro *b, char *word0) {
- int i;
for (;b; b = b->next)
if (b->strs[0] && !strcmp(b->strs[0], word0))
return b->strs;
return NULL;
}
-int
+static int
do_baro(struct cc_usb *usb) {
struct baro *b = baro(usb);
char **temp = find_baro(b, "Temperature:");
main (int argc, char **argv)
{
char *device = NULL;
- char *filename;
- Elf *e;
- unsigned int s;
- int i;
int c;
- int tries;
struct cc_usb *cc = NULL;
char *tty = NULL;
- int success;
int verbose = 0;
int ret = 0;
bin_PROGRAMS=ao-test-flash
-AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
+AM_CFLAGS=$(WARN_CFLAGS) -I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
ao_test_flash_DEPENDENCIES = $(top_builddir)/ao-tools/lib/libao-tools.a
exit(1);
}
-void
+static void
done(struct cc_usb *cc, int code)
{
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;
-}
-
-static int
-starts_with(char *whole, char *prefix)
-{
- int whole_len = strlen(whole);
- int prefix_len = strlen(prefix);
-
- if (prefix_len > whole_len)
- return 0;
- return strncmp(whole, prefix, prefix_len) == 0;
-}
-
static char **
tok(char *line) {
char **strs = malloc (sizeof (char *)), *str;
}
}
-char **
+static char **
find_flash(struct flash *b, char *word0) {
- int i;
for (;b; b = b->next) {
if (strstr(b->line, word0))
return b->strs;
return NULL;
}
-int
+static int
do_flash(struct cc_usb *usb, int expected_size) {
struct flash *b = flash(usb);
char **size = find_flash(b, "Storage size:");
main (int argc, char **argv)
{
char *device = NULL;
- char *filename;
- Elf *e;
- unsigned int s;
- int i;
int c;
- int tries;
struct cc_usb *cc = NULL;
char *tty = NULL;
- int success;
int verbose = 0;
int ret = 0;
- int expected_size;
while ((c = getopt_long(argc, argv, "rT:D:c:s:v:", options, NULL)) != -1) {
switch (c) {
bin_PROGRAMS=ao-test-gps
-AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
+AM_CFLAGS=$(WARN_CFLAGS) -I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
ao_test_gps_DEPENDENCIES = $(top_builddir)/ao-tools/lib/libao-tools.a
exit(1);
}
-void
+static void
done(struct cc_usb *cc, int code)
{
/* cc_usb_printf(cc, "a\n"); */
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;
-}
-
-static int
-starts_with(char *whole, char *prefix)
-{
- int whole_len = strlen(whole);
- int prefix_len = strlen(prefix);
-
- if (prefix_len > whole_len)
- return 0;
- return strncmp(whole, prefix, prefix_len) == 0;
-}
-
static char **
tok(char *line) {
char **strs = malloc (sizeof (char *)), *str;
}
}
-char **
+static char **
find_gps(struct gps *b, char *word0) {
- int i;
for (;b; b = b->next)
if (b->strs[0] && !strcmp(b->strs[0], word0))
return b->strs;
return NULL;
}
-int
+static int
do_gps(struct cc_usb *usb) {
int count = 0;
main (int argc, char **argv)
{
char *device = NULL;
- char *filename;
- Elf *e;
- unsigned int s;
- int i;
int c;
- int tries;
struct cc_usb *cc = NULL;
char *tty = NULL;
- int success;
int verbose = 0;
int ret = 0;
bin_PROGRAMS=ao-test-igniter
-AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
+AM_CFLAGS=$(WARN_CFLAGS) -I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
ao_test_igniter_DEPENDENCIES = $(top_builddir)/ao-tools/lib/libao-tools.a
exit(1);
}
-void
+static void
done(struct cc_usb *cc, int code)
{
/* cc_usb_printf(cc, "a\n"); */
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;
-}
-
-static int
-starts_with(char *whole, char *prefix)
-{
- int whole_len = strlen(whole);
- int prefix_len = strlen(prefix);
-
- if (prefix_len > whole_len)
- return 0;
- return strncmp(whole, prefix, prefix_len) == 0;
-}
-
struct igniter {
struct igniter *next;
char name[512];
cc_usb_getline(usb, line, sizeof (line));
if (strstr(line, "software-version"))
break;
- if (sscanf(line, "Igniter: %s Status: %s", &name, &status) == 2) {
+ if (sscanf(line, "Igniter: %s Status: %s", name, status) == 2) {
struct igniter *i = malloc (sizeof (struct igniter));
strcpy(i->name, name);
strcpy(i->status, status);
for (; i; i = i->next)
if (strcmp(i->name, name) == 0)
return i;
+ return NULL;
}
static int
struct igniter *this = find_igniter(all, name);
if (!this) {
struct igniter *i;
- printf("no igniter %s found in");
+ printf("no igniter %s found in", name);
for (i = all; i; i = i->next)
printf(" %s", i->name);
printf("\n");
main (int argc, char **argv)
{
char *device = NULL;
- char *filename;
- Elf *e;
- unsigned int s;
int i;
int c;
- int tries;
struct cc_usb *cc = NULL;
char *tty = NULL;
- int success;
int verbose = 0;
int ret = 0;
bin_PROGRAMS=ao-usbload
-AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
+AM_CFLAGS=$(WARN_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)
exit(1);
}
-void
+static void
done(struct cc_usb *cc, int code)
{
/* cc_usb_printf(cc, "a\n"); */
return len;
}
-int
+static int
putucs4(uint32_t c, FILE *file)
{
char d;
{
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;
bin_PROGRAMS=ao-usbtrng
-AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
+AM_CFLAGS=$(WARN_CFLAGS) -I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
ao_usbtrng_DEPENDENCIES = $(top_builddir)/ao-tools/lib/libao-tools.a
exit(1);
}
-void
+static void
done(struct cc_usb *cc, int code)
{
cc_usb_close(cc);
main (int argc, char **argv)
{
char *device = NULL;
- char *filename;
int i;
int c;
struct cc_usb *cc = NULL;
AO_VIEW_CFLAGS=-I$(top_srcdir)/ao-tools/lib
AO_VIEW_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a
-AM_CFLAGS=$(AO_VIEW_CFLAGS) $(GNOME_CFLAGS) $(ALSA_CFLAGS) -I$(top_srcdir)/src -DAOVIEW_VERSION=\"$(VERSION)\" @FLITE_INCS@
+AM_CFLAGS=$(WARN_CFLAGS) $(AO_VIEW_CFLAGS) $(GNOME_CFLAGS) $(ALSA_CFLAGS) -I$(top_srcdir)/src -DAOVIEW_VERSION=\"$(VERSION)\" @FLITE_INCS@
bin_PROGRAMS=ao-view
chbevl.c \
mconf.h \
cephes.h \
+ ao-atmosphere.c \
+ ao-atmosphere.h \
ao-hex.c \
ao-hex.h \
ao-editaltos.c \
ao-dfu.h \
ao-selfload.c \
ao-selfload.h \
+ ao-eeprom-read.c \
+ ao-eeprom-read.h \
+ ao-ms5607-convert.c \
+ ao-ms5607.h \
ao-verbose.c \
ao-verbose.h
--- /dev/null
+/*
+ * Copyright © 2019 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.
+ */
+
+#include <math.h>
+#include "ao-atmosphere.h"
+
+#define GRAVITY 9.80665
+
+/*
+ * Pressure Sensor Model, version 1.1
+ *
+ * written by Holly Grimes
+ *
+ * Uses the International Standard Atmosphere as described in
+ * "A Quick Derivation relating altitude to air pressure" (version 1.03)
+ * from the Portland State Aerospace Society, except that the atmosphere
+ * is divided into layers with each layer having a different lapse rate.
+ *
+ * Lapse rate data for each layer was obtained from Wikipedia on Sept. 1, 2007
+ * at site <http://en.wikipedia.org/wiki/International_Standard_Atmosphere
+ *
+ * Height measurements use the local tangent plane. The postive z-direction is up.
+ *
+ * All measurements are given in SI units (Kelvin, Pascal, meter, meters/second^2).
+ * The lapse rate is given in Kelvin/meter, the gas constant for air is given
+ * in Joules/(kilogram-Kelvin).
+ */
+
+#define GRAVITATIONAL_ACCELERATION (-GRAVITY)
+#define AIR_GAS_CONSTANT 287.053
+#define NUMBER_OF_LAYERS 7
+#define MAXIMUM_ALTITUDE 84852.0
+#define MINIMUM_PRESSURE 0.3734
+#define LAYER0_BASE_TEMPERATURE 288.15
+#define LAYER0_BASE_PRESSURE 101325
+
+ /* lapse rate and base altitude for each layer in the atmosphere */
+static const double lapse_rate[] = {
+ -0.0065, 0.0, 0.001, 0.0028, 0.0, -0.0028, -0.002
+};
+
+static const double base_altitude[] = {
+ 0, 11000, 20000, 32000, 47000, 51000, 71000
+};
+
+/* outputs atmospheric pressure associated with the given altitude.
+ * altitudes are measured with respect to the mean sea level
+ */
+double
+ao_altitude_to_pressure(double altitude)
+{
+ double base_temperature = LAYER0_BASE_TEMPERATURE;
+ double base_pressure = LAYER0_BASE_PRESSURE;
+
+ double pressure;
+ double base; /* base for function to determine pressure */
+ double exponent; /* exponent for function to determine pressure */
+ int layer_number; /* identifies layer in the atmosphere */
+ double delta_z; /* difference between two altitudes */
+
+ if (altitude > MAXIMUM_ALTITUDE) /* FIX ME: use sensor data to improve model */
+ return 0;
+
+ /* calculate the base temperature and pressure for the atmospheric layer
+ associated with the inputted altitude */
+ for(layer_number = 0; layer_number < NUMBER_OF_LAYERS - 1 && altitude > base_altitude[layer_number + 1]; layer_number++) {
+ delta_z = base_altitude[layer_number + 1] - base_altitude[layer_number];
+ if (lapse_rate[layer_number] == 0.0) {
+ exponent = GRAVITATIONAL_ACCELERATION * delta_z
+ / AIR_GAS_CONSTANT / base_temperature;
+ base_pressure *= exp(exponent);
+ }
+ else {
+ base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0;
+ exponent = GRAVITATIONAL_ACCELERATION /
+ (AIR_GAS_CONSTANT * lapse_rate[layer_number]);
+ base_pressure *= pow(base, exponent);
+ }
+ base_temperature += delta_z * lapse_rate[layer_number];
+ }
+
+ /* calculate the pressure at the inputted altitude */
+ delta_z = altitude - base_altitude[layer_number];
+ if (lapse_rate[layer_number] == 0.0) {
+ exponent = GRAVITATIONAL_ACCELERATION * delta_z
+ / AIR_GAS_CONSTANT / base_temperature;
+ pressure = base_pressure * exp(exponent);
+ }
+ else {
+ base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0;
+ exponent = GRAVITATIONAL_ACCELERATION /
+ (AIR_GAS_CONSTANT * lapse_rate[layer_number]);
+ pressure = base_pressure * pow(base, exponent);
+ }
+
+ return pressure;
+}
+
+
+/* outputs the altitude associated with the given pressure. the altitude
+ returned is measured with respect to the mean sea level */
+double
+ao_pressure_to_altitude(double pressure)
+{
+
+ double next_base_temperature = LAYER0_BASE_TEMPERATURE;
+ double next_base_pressure = LAYER0_BASE_PRESSURE;
+
+ double altitude;
+ double base_pressure;
+ double base_temperature;
+ double base; /* base for function to determine base pressure of next layer */
+ double exponent; /* exponent for function to determine base pressure
+ of next layer */
+ double coefficient;
+ int layer_number; /* identifies layer in the atmosphere */
+ int delta_z; /* difference between two altitudes */
+
+ if (pressure < 0) /* illegal pressure */
+ return -1;
+ if (pressure < MINIMUM_PRESSURE) /* FIX ME: use sensor data to improve model */
+ return MAXIMUM_ALTITUDE;
+
+ /* calculate the base temperature and pressure for the atmospheric layer
+ associated with the inputted pressure. */
+ layer_number = -1;
+ do {
+ layer_number++;
+ base_pressure = next_base_pressure;
+ base_temperature = next_base_temperature;
+ delta_z = base_altitude[layer_number + 1] - base_altitude[layer_number];
+ if (lapse_rate[layer_number] == 0.0) {
+ exponent = GRAVITATIONAL_ACCELERATION * delta_z
+ / AIR_GAS_CONSTANT / base_temperature;
+ next_base_pressure *= exp(exponent);
+ }
+ else {
+ base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0;
+ exponent = GRAVITATIONAL_ACCELERATION /
+ (AIR_GAS_CONSTANT * lapse_rate[layer_number]);
+ next_base_pressure *= pow(base, exponent);
+ }
+ next_base_temperature += delta_z * lapse_rate[layer_number];
+ }
+ while(layer_number < NUMBER_OF_LAYERS - 1 && pressure < next_base_pressure);
+
+ /* calculate the altitude associated with the inputted pressure */
+ if (lapse_rate[layer_number] == 0.0) {
+ coefficient = (AIR_GAS_CONSTANT / GRAVITATIONAL_ACCELERATION)
+ * base_temperature;
+ altitude = base_altitude[layer_number]
+ + coefficient * log(pressure / base_pressure);
+ }
+ else {
+ base = pressure / base_pressure;
+ exponent = AIR_GAS_CONSTANT * lapse_rate[layer_number]
+ / GRAVITATIONAL_ACCELERATION;
+ coefficient = base_temperature / lapse_rate[layer_number];
+ altitude = base_altitude[layer_number]
+ + coefficient * (pow(base, exponent) - 1);
+ }
+
+ return altitude;
+}
--- /dev/null
+/*
+ * Copyright © 2019 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.
+ */
+
+#ifndef _AO_ATMOSPHERE_H_
+#define _AO_ATMOSPHERE_H_
+
+double
+ao_altitude_to_pressure(double altitude);
+
+double
+ao_pressure_to_altitude(double pressure);
+
+#endif /* _AO_ATMOSPHERE_H_ */
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;
--- /dev/null
+/*
+ * Copyright © 2017 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.
+ */
+
+#include "ao-eeprom-read.h"
+#include <json-c/json.h>
+#include <string.h>
+#include <errno.h>
+
+static struct json_object *
+ao_eeprom_read_config(FILE *file)
+{
+ char line[1024];
+ struct json_tokener *tok;
+ struct json_object *obj = NULL;
+ enum json_tokener_error err;
+
+ tok = json_tokener_new();
+ if (!tok)
+ goto fail_tok;
+
+ for (;;) {
+ if (fgets(line, sizeof(line), file) == NULL)
+ goto fail_read;
+ obj = json_tokener_parse_ex(tok, line, strlen(line));
+ err = json_tokener_get_error(tok);
+ if (err == json_tokener_success)
+ break;
+ if (err != json_tokener_continue)
+ goto fail_read;
+ }
+ json_tokener_free(tok);
+ return obj;
+fail_read:
+ json_tokener_free(tok);
+fail_tok:
+ return NULL;
+}
+
+static int
+ao_eeprom_read_byte(FILE *file)
+{
+ int byte;
+ if (fscanf(file, "%x", &byte) != 1)
+ return EOF;
+ return byte;
+}
+
+static int
+ao_eeprom_read_data(FILE *file, struct ao_eeprom *eeprom)
+{
+ uint8_t *data = NULL, *ndata;
+ int len = 0;
+ int size = 0;
+ int byte;
+
+ data = malloc(size = 64);
+ if (!data)
+ goto fail_alloc;
+ while ((byte = ao_eeprom_read_byte(file)) != EOF) {
+ if (len == size) {
+ ndata = realloc(data, size *= 2);
+ if (!ndata)
+ goto fail_realloc;
+ data = ndata;
+ }
+ data[len++] = (uint8_t) byte;
+ }
+ eeprom->data = data;
+ eeprom->len = len;
+ return 1;
+fail_realloc:
+ free(data);
+fail_alloc:
+ return 0;
+}
+
+static int
+ao_json_get_int(struct json_object *obj, const char *key, int def)
+{
+ struct json_object *value;
+ int i;
+
+ if (!json_object_object_get_ex(obj, key, &value))
+ return def;
+ errno = 0;
+ i = (int) json_object_get_int(value);
+ if (errno != 0)
+ return def;
+ return i;
+}
+
+static const char *
+ao_json_get_string(struct json_object *obj, const char *key, const char *def)
+{
+ struct json_object *value;
+ const char *str;
+
+ if (!json_object_object_get_ex(obj, key, &value))
+ return def;
+ errno = 0;
+ str = json_object_get_string(value);
+ if (errno)
+ return def;
+ if (!str)
+ return def;
+ return str;
+}
+
+static int
+ao_eeprom_get_pyro(struct ao_config *config, struct json_object *obj)
+{
+ struct json_object *pyros;
+ struct json_object *pyro;
+ int i, p;
+
+ if (!json_object_object_get_ex(obj, "pyros", &pyros))
+ return 1;
+
+ if (json_object_get_type(pyros) != json_type_array)
+ return 0;
+
+ for (i = 0; i < json_object_array_length(pyros); i++) {
+ pyro = json_object_array_get_idx(pyros, i);
+ if (pyro) {
+ p = ao_json_get_int(pyro, "channel", -1);
+ if (0 <= p && p < AO_PYRO_NUM) {
+ config->pyro[p].flags = ao_json_get_int(pyro, "flags", 0);
+ config->pyro[p].accel_less = ao_json_get_int(pyro, "accel_less", 0);
+ config->pyro[p].accel_greater = ao_json_get_int(pyro, "accel_greater", 0);
+ config->pyro[p].speed_less = ao_json_get_int(pyro, "speed_less", 0);
+ config->pyro[p].speed_greater = ao_json_get_int(pyro, "speed_greater", 0);
+ config->pyro[p].height_less = ao_json_get_int(pyro, "height_less", 0);
+ config->pyro[p].height_greater = ao_json_get_int(pyro, "height_greater", 0);
+ config->pyro[p].orient_less = ao_json_get_int(pyro, "orient_less", 0);
+ config->pyro[p].orient_greater = ao_json_get_int(pyro, "orient_greater", 0);
+ config->pyro[p].time_less = ao_json_get_int(pyro, "time_less", 0);
+ config->pyro[p].time_greater = ao_json_get_int(pyro, "time_greater", 0);
+ config->pyro[p].delay = ao_json_get_int(pyro, "delay", 0);
+ config->pyro[p].state_less = ao_json_get_int(pyro, "state_less", 0);
+ config->pyro[p].state_greater_or_equal = ao_json_get_int(pyro, "state_greater_or_equal", 0);
+ config->pyro[p].motor = ao_json_get_int(pyro, "motor", 0);
+ }
+ }
+ }
+ return 1;
+}
+
+static int
+ao_eeprom_get_ms5607(struct ao_ms5607_prom *ms5607_prom, struct json_object *obj)
+{
+ struct json_object *ms5607;
+
+ if (!json_object_object_get_ex(obj, "ms5607", &ms5607))
+ return 1;
+
+ if (json_object_get_type(ms5607) != json_type_object)
+ return 0;
+
+ ms5607_prom->reserved = ao_json_get_int(ms5607, "reserved", 0);
+ ms5607_prom->sens = ao_json_get_int(ms5607, "sens", 0);
+ ms5607_prom->off = ao_json_get_int(ms5607, "off", 0);
+ ms5607_prom->tcs = ao_json_get_int(ms5607, "tcs", 0);
+ ms5607_prom->tco = ao_json_get_int(ms5607, "tco", 0);
+ ms5607_prom->tref = ao_json_get_int(ms5607, "tref", 0);
+ ms5607_prom->tempsens = ao_json_get_int(ms5607, "tempsens", 0);
+ ms5607_prom->crc = ao_json_get_int(ms5607, "crc", 0);
+ return 1;
+}
+
+static int
+ao_eeprom_get_config(struct ao_eeprom *ao_eeprom, struct json_object *obj)
+{
+ struct ao_config *config = &ao_eeprom->config;
+ const char *s;
+
+ if (json_object_get_type(obj) != json_type_object)
+ return 0;
+
+ ao_eeprom->log_format = ao_json_get_int(obj, "log_format", 0);
+ ao_eeprom->serial_number = ao_json_get_int(obj, "serial", 0);
+
+ config->major = ao_json_get_int(obj, "config_major", 0);
+ config->minor = ao_json_get_int(obj, "config_minor", 0);
+ if (config->major == 0 || config->minor == 0)
+ return 0;
+
+ config->main_deploy = ao_json_get_int(obj, "main_deploy", 250);
+ config->accel_plus_g = ao_json_get_int(obj, "accel_cal_plus", 0);
+
+ s = ao_json_get_string(obj, "callsign", "N0CALL");
+ strncpy(config->callsign, s, sizeof(config->callsign)-1);
+
+ config->apogee_delay = ao_json_get_int(obj, "apogee_delay", 0);
+ config->accel_minus_g = ao_json_get_int(obj, "accel_cal_minus", 0);
+ config->radio_cal = ao_json_get_int(obj, "radio_calibration", 0);
+ config->flight_log_max = ao_json_get_int(obj, "flight_log_max", 0);
+ config->ignite_mode = ao_json_get_int(obj, "ignite_mode", 0);
+ config->pad_orientation = ao_json_get_int(obj, "pad_orientation", 0);
+ config->radio_setting = ao_json_get_int(obj, "radio_setting", 0);
+ config->radio_enable = ao_json_get_int(obj, "radio_enable", 1);
+ config->frequency = ao_json_get_int(obj, "frequency", 434550);
+ config->apogee_lockout = ao_json_get_int(obj, "apogee_lockout", 0);
+ if (!ao_eeprom_get_pyro(config, obj))
+ return 0;
+ config->ignite_mode = ao_json_get_int(obj, "ignite_mode", 0);
+ config->ignite_mode = ao_json_get_int(obj, "ignite_mode", 0);
+ config->ignite_mode = ao_json_get_int(obj, "ignite_mode", 0);
+ config->ignite_mode = ao_json_get_int(obj, "ignite_mode", 0);
+ config->ignite_mode = ao_json_get_int(obj, "ignite_mode", 0);
+ config->ignite_mode = ao_json_get_int(obj, "ignite_mode", 0);
+
+ if (!ao_eeprom_get_ms5607(&ao_eeprom->ms5607_prom, obj))
+ return 0;
+
+ return 1;
+}
+
+struct ao_eeprom *
+ao_eeprom_read(FILE *file)
+{
+ struct ao_eeprom *ao_eeprom;
+ struct json_object *obj;
+ int ret;
+
+ ao_eeprom = calloc(1, sizeof (struct ao_eeprom));
+ if (!ao_eeprom)
+ goto fail_ao_eeprom;
+
+ obj = ao_eeprom_read_config(file);
+ if (!obj)
+ goto fail_config;
+
+ ret = ao_eeprom_get_config(ao_eeprom, obj);
+ json_object_put(obj);
+ if (!ret)
+ goto fail_config;
+
+ if (!ao_eeprom_read_data(file, ao_eeprom))
+ goto fail_data;
+
+ return ao_eeprom;
+fail_data:
+fail_config:
+ free(ao_eeprom);
+fail_ao_eeprom:
+ return NULL;
+}
--- /dev/null
+/*
+ * Copyright © 2017 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.
+ */
+
+#ifndef _AO_EEPROM_READ_H_
+#define _AO_EEPROM_READ_H_
+
+#include <stdint.h>
+#include <stdio.h>
+#include <ao-ms5607.h>
+
+#define AO_MAX_CALLSIGN 8
+#define AO_AES_LEN 16
+#define AO_PYRO_NUM 8
+
+/* required functions from the underlying log system */
+
+#define AO_LOG_FORMAT_UNKNOWN 0 /* unknown; altosui will have to guess */
+#define AO_LOG_FORMAT_FULL 1 /* 8 byte typed log records */
+#define AO_LOG_FORMAT_TINY 2 /* two byte state/baro records */
+#define AO_LOG_FORMAT_TELEMETRY 3 /* 32 byte ao_telemetry records */
+#define AO_LOG_FORMAT_TELESCIENCE 4 /* 32 byte typed telescience records */
+#define AO_LOG_FORMAT_TELEMEGA_OLD 5 /* 32 byte typed telemega records */
+#define AO_LOG_FORMAT_EASYMINI1 6 /* 16-byte MS5607 baro only, 3.0V supply */
+#define AO_LOG_FORMAT_TELEMETRUM 7 /* 16-byte typed telemetrum records */
+#define AO_LOG_FORMAT_TELEMINI2 8 /* 16-byte MS5607 baro only, 3.3V supply, cc1111 SoC */
+#define AO_LOG_FORMAT_TELEGPS 9 /* 32 byte telegps records */
+#define AO_LOG_FORMAT_TELEMEGA 10 /* 32 byte typed telemega records with 32 bit gyro cal */
+#define AO_LOG_FORMAT_DETHERM 11 /* 16-byte MS5607 baro only, no ADC */
+#define AO_LOG_FORMAT_TELEMINI3 12 /* 16-byte MS5607 baro only, 3.3V supply, stm32f042 SoC */
+#define AO_LOG_FORMAT_TELEFIRETWO 13 /* 32-byte test stand data */
+#define AO_LOG_FORMAT_EASYMINI2 14 /* 16-byte MS5607 baro only, 3.3V supply, stm32f042 SoC */
+#define AO_LOG_FORMAT_TELEMEGA_3 15 /* 32 byte typed telemega records with 32 bit gyro cal and mpu9250 */
+#define AO_LOG_FORMAT_EASYMEGA_2 16 /* 32 byte typed telemega records with 32 bit gyro cal, mpu9250 rotated 90° and adxl375 */
+#define AO_LOG_FORMAT_TELESTATIC 17 /* 32 byte typed telestatic records */
+#define AO_LOG_FORMAT_MICROPEAK2 18 /* 2-byte baro values with header */
+#define AO_LOG_FORMAT_NONE 127 /* No log at all */
+
+enum ao_pyro_flag {
+ ao_pyro_none = 0x00000000,
+
+ ao_pyro_accel_less = 0x00000001,
+ ao_pyro_accel_greater = 0x00000002,
+
+ ao_pyro_speed_less = 0x00000004,
+ ao_pyro_speed_greater = 0x00000008,
+
+ ao_pyro_height_less = 0x00000010,
+ ao_pyro_height_greater = 0x00000020,
+
+ ao_pyro_orient_less = 0x00000040,
+ ao_pyro_orient_greater = 0x00000080,
+
+ ao_pyro_time_less = 0x00000100,
+ ao_pyro_time_greater = 0x00000200,
+
+ ao_pyro_ascending = 0x00000400,
+ ao_pyro_descending = 0x00000800,
+
+ ao_pyro_after_motor = 0x00001000,
+
+ ao_pyro_delay = 0x00002000,
+
+ ao_pyro_state_less = 0x00004000,
+ ao_pyro_state_greater_or_equal = 0x00008000,
+};
+
+struct ao_pyro {
+ enum ao_pyro_flag flags;
+ int16_t accel_less, accel_greater;
+ int16_t speed_less, speed_greater;
+ int16_t height_less, height_greater;
+ int16_t orient_less, orient_greater;
+ int16_t time_less, time_greater;
+ int16_t delay;
+ uint8_t state_less, state_greater_or_equal;
+ int16_t motor;
+ uint16_t delay_done;
+ uint8_t _unused; /* was 'fired' */
+};
+
+struct ao_config {
+ uint8_t major;
+ uint8_t minor;
+ uint16_t main_deploy;
+ int16_t accel_plus_g; /* changed for minor version 2 */
+ uint8_t _legacy_radio_channel;
+ char callsign[AO_MAX_CALLSIGN + 1];
+ uint8_t apogee_delay; /* minor version 1 */
+ int16_t accel_minus_g; /* minor version 2 */
+ uint32_t radio_cal; /* minor version 3 */
+ uint32_t flight_log_max; /* minor version 4 */
+ uint8_t ignite_mode; /* minor version 5 */
+ uint8_t pad_orientation; /* minor version 6 */
+ uint32_t radio_setting; /* minor version 7 */
+ uint8_t radio_enable; /* minor version 8 */
+ uint8_t aes_key[AO_AES_LEN]; /* minor version 9 */
+ uint32_t frequency; /* minor version 10 */
+ uint16_t apogee_lockout; /* minor version 11 */
+ struct ao_pyro pyro[AO_PYRO_NUM]; /* minor version 12 */
+ uint16_t aprs_interval; /* minor version 13 */
+ uint8_t radio_power; /* minor version 14 */
+ uint8_t radio_amp; /* minor version 14 */
+ int16_t accel_zero_along; /* minor version 15 */
+ int16_t accel_zero_across; /* minor version 15 */
+ int16_t accel_zero_through; /* minor version 15 */
+ uint8_t mid_beep; /* minor version 16 */
+ uint16_t tracker_motion; /* minor version 17 */
+ uint8_t tracker_interval; /* minor version 17 */
+ uint16_t pyro_time; /* minor version 18 */
+ uint8_t aprs_ssid; /* minor version 19 */
+ uint8_t radio_rate; /* minor version 20 */
+ uint32_t send_frequency; /* minor version 21 */
+ uint8_t aprs_format; /* minor version 22 */
+ uint8_t pad_box; /* minor version 22 */
+ uint8_t pad_idle; /* minor version 23 */
+};
+
+/*
+ * ao_log_big.c
+ */
+
+/*
+ * The data log is recorded in the eeprom as a sequence
+ * of data packets.
+ *
+ * Each packet starts with a 4-byte header that has the
+ * packet type, the packet checksum and the tick count. Then
+ * they all contain 2 16 bit values which hold packet-specific
+ * data.
+ *
+ * For each flight, the first packet
+ * is FLIGHT packet, indicating the serial number of the
+ * device and a unique number marking the number of flights
+ * recorded by this device.
+ *
+ * During flight, data from the accelerometer and barometer
+ * are recorded in SENSOR packets, using the raw 16-bit values
+ * read from the A/D converter.
+ *
+ * Also during flight, but at a lower rate, the deployment
+ * sensors are recorded in DEPLOY packets. The goal here is to
+ * detect failure in the deployment circuits.
+ *
+ * STATE packets hold state transitions as the flight computer
+ * transitions through different stages of the flight.
+ */
+#define AO_LOG_FLIGHT 'F'
+#define AO_LOG_SENSOR 'A'
+#define AO_LOG_TEMP_VOLT 'T'
+#define AO_LOG_DEPLOY 'D'
+#define AO_LOG_STATE 'S'
+#define AO_LOG_GPS_TIME 'G'
+#define AO_LOG_GPS_LAT 'N'
+#define AO_LOG_GPS_LON 'W'
+#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)
+
+/* Common header in all log formats */
+struct ao_log_header {
+ char type; /* 0 */
+ uint8_t csum; /* 1 */
+ uint16_t tick; /* 2 */
+};
+
+struct ao_log_record {
+ char type; /* 0 */
+ uint8_t csum; /* 1 */
+ uint16_t tick; /* 2 */
+ union {
+ struct {
+ int16_t ground_accel; /* 4 */
+ uint16_t flight; /* 6 */
+ } flight;
+ struct {
+ int16_t accel; /* 4 */
+ int16_t pres; /* 6 */
+ } sensor;
+ struct {
+ int16_t temp;
+ int16_t v_batt;
+ } temp_volt;
+ struct {
+ int16_t drogue;
+ int16_t main;
+ } deploy;
+ struct {
+ uint16_t state;
+ uint16_t reason;
+ } state;
+ struct {
+ uint8_t hour;
+ uint8_t minute;
+ uint8_t second;
+ uint8_t flags;
+ } gps_time;
+ int32_t gps_latitude;
+ int32_t gps_longitude;
+ struct {
+ uint16_t altitude_low;
+ int16_t altitude_high;
+ } gps_altitude;
+ struct {
+ uint16_t svid;
+ uint8_t unused;
+ uint8_t c_n;
+ } gps_sat;
+ struct {
+ uint8_t year;
+ uint8_t month;
+ uint8_t day;
+ uint8_t extra;
+ } gps_date;
+ struct {
+ uint16_t d0;
+ uint16_t d1;
+ } anon;
+ } u;
+};
+
+struct ao_log_mega {
+ 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 */
+ int16_t ground_accel_along; /* 12 */
+ int16_t ground_accel_across; /* 14 */
+ int16_t ground_accel_through; /* 16 */
+ int16_t pad_18; /* 18 */
+ int32_t ground_roll; /* 20 */
+ int32_t ground_pitch; /* 24 */
+ int32_t ground_yaw; /* 28 */
+ } flight; /* 32 */
+ struct {
+ uint16_t flight; /* 4 */
+ int16_t ground_accel; /* 6 */
+ uint32_t ground_pres; /* 8 */
+ int16_t ground_accel_along; /* 12 */
+ int16_t ground_accel_across; /* 14 */
+ int16_t ground_accel_through; /* 16 */
+ int16_t ground_roll; /* 18 */
+ int16_t ground_pitch; /* 20 */
+ int16_t ground_yaw; /* 22 */
+ } flight_old; /* 24 */
+ /* AO_LOG_STATE */
+ struct {
+ uint16_t state;
+ uint16_t reason;
+ } state;
+ /* AO_LOG_SENSOR */
+ struct {
+ uint32_t pres; /* 4 */
+ uint32_t temp; /* 8 */
+ int16_t accel_x; /* 12 */
+ int16_t accel_y; /* 14 */
+ int16_t accel_z; /* 16 */
+ int16_t gyro_x; /* 18 */
+ int16_t gyro_y; /* 20 */
+ int16_t gyro_z; /* 22 */
+ int16_t mag_x; /* 24 */
+ int16_t mag_z; /* 26 */
+ int16_t mag_y; /* 28 */
+ int16_t accel; /* 30 */
+ } sensor; /* 32 */
+ /* AO_LOG_TEMP_VOLT */
+ struct {
+ int16_t v_batt; /* 4 */
+ int16_t v_pbatt; /* 6 */
+ int16_t n_sense; /* 8 */
+ int16_t sense[10]; /* 10 */
+ uint16_t pyro; /* 30 */
+ } volt; /* 32 */
+ /* AO_LOG_GPS_TIME */
+ struct {
+ int32_t latitude; /* 4 */
+ int32_t longitude; /* 8 */
+ uint16_t altitude_low; /* 12 */
+ uint8_t hour; /* 14 */
+ uint8_t minute; /* 15 */
+ uint8_t second; /* 16 */
+ uint8_t flags; /* 17 */
+ uint8_t year; /* 18 */
+ uint8_t month; /* 19 */
+ uint8_t day; /* 20 */
+ 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 */
+ int16_t altitude_high; /* 30 */
+ } gps; /* 32 */
+ /* AO_LOG_GPS_SAT */
+ struct {
+ uint16_t channels; /* 4 */
+ struct {
+ uint8_t svid;
+ uint8_t c_n;
+ } sats[12]; /* 6 */
+ } gps_sat; /* 30 */
+ } u;
+};
+
+#define AO_LOG_MEGA_GPS_ALTITUDE(l) ((int32_t) ((l)->u.gps.altitude_high << 16) | ((l)->u.gps.altitude_low))
+#define AO_LOG_MEGA_SET_GPS_ALTITUDE(l,a) (((l)->u.gps.mode |= AO_GPS_MODE_ALTITUDE_24), \
+ ((l)->u.gps.altitude_high = (a) >> 16), \
+ (l)->u.gps.altitude_low = (a))
+
+struct ao_log_firetwo {
+ char type; /* 0 */
+ uint8_t csum; /* 1 */
+ uint16_t tick; /* 2 */
+ union { /* 4 */
+ /* AO_LOG_FLIGHT */
+ struct {
+ uint16_t flight; /* 4 */
+ } flight; /* 6 */
+ /* AO_LOG_STATE */
+ struct {
+ uint16_t state; /* 4 */
+ uint16_t reason; /* 6 */
+ } state; /* 8 */
+ /* AO_LOG_SENSOR */
+ struct {
+ uint16_t pressure; /* 4 */
+ uint16_t thrust; /* 6 */
+ uint16_t thermistor[4]; /* 8 */
+ } sensor; /* 24 */
+ uint8_t align[28]; /* 4 */
+ } u; /* 32 */
+};
+
+struct ao_log_telestatic {
+ char type; /* 0 */
+ uint8_t csum; /* 1 */
+ uint16_t tick; /* 2 */
+ union { /* 4 */
+ /* AO_LOG_FLIGHT */
+ struct {
+ uint16_t flight; /* 4 */
+ } flight; /* 6 */
+ /* AO_LOG_STATE */
+ struct {
+ uint16_t state; /* 4 */
+ uint16_t reason; /* 6 */
+ } state; /* 8 */
+ /* AO_LOG_SENSOR */
+ struct {
+ uint32_t pressure; /* 4 */
+ uint32_t pressure2; /* 8 */
+ uint32_t thrust; /* 12 */
+ uint32_t mass; /* 16 */
+ uint16_t t_low; /* 20 */
+ uint16_t t_high[4]; /* 22 */
+ } sensor; /* 30 */
+ uint8_t align[28]; /* 4 */
+ } u; /* 32 */
+};
+
+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 */
+ uint16_t altitude_low; /* 12 */
+ int16_t altitude_high; /* 14 */
+ } gps; /* 16 */
+ /* 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 pdop; /* 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)
+
+struct ao_log_gps {
+ char type; /* 0 */
+ uint8_t csum; /* 1 */
+ uint16_t tick; /* 2 */
+ union { /* 4 */
+ /* AO_LOG_FLIGHT */
+ struct {
+ uint16_t flight; /* 4 */
+ int16_t start_altitude; /* 6 */
+ int32_t start_latitude; /* 8 */
+ int32_t start_longitude; /* 12 */
+ } flight; /* 16 */
+ /* AO_LOG_GPS_TIME */
+ struct {
+ int32_t latitude; /* 4 */
+ int32_t longitude; /* 8 */
+ uint16_t altitude_low; /* 12 */
+ uint8_t hour; /* 14 */
+ uint8_t minute; /* 15 */
+ uint8_t second; /* 16 */
+ uint8_t flags; /* 17 */
+ uint8_t year; /* 18 */
+ uint8_t month; /* 19 */
+ uint8_t day; /* 20 */
+ 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 */
+ int16_t altitude_high; /* 30 */
+ } gps; /* 31 */
+ /* AO_LOG_GPS_SAT */
+ struct {
+ uint16_t channels; /* 4 */
+ struct {
+ uint8_t svid;
+ uint8_t c_n;
+ } sats[12]; /* 6 */
+ } gps_sat; /* 30 */
+ } u;
+};
+
+struct ao_eeprom {
+ struct ao_config config;
+ struct ao_ms5607_prom ms5607_prom;
+ int log_format;
+ uint16_t serial_number;
+ uint8_t *data;
+ uint32_t len;
+};
+
+struct ao_eeprom *ao_eeprom_read(FILE *file);
+
+struct ao_eeprom *ao_eeprom_read_old(FILE *file);
+
+void ao_eeprom_free_data(struct ao_eeprom *ao_eeprom);
+
+#endif /* _AO_EEPROM_READ_H_ */
struct ao_hex_record *record = NULL;
enum ao_hex_read_state state = read_marker;
char c;
- int nhexbytes;
- uint32_t hex;
- uint32_t ndata;
+ int nhexbytes = 0;
+ uint32_t hex = 0;
+ uint32_t ndata = 0;
uint8_t checksum;
while (state != read_done) {
free(image);
}
-uint32_t min(uint32_t a, uint32_t b) { return a < b ? a : b; }
-uint32_t max(uint32_t a, uint32_t b) { return a > b ? a : b; }
+static uint32_t min(uint32_t a, uint32_t b) { return a < b ? a : b; }
+static uint32_t max(uint32_t a, uint32_t b) { return a > b ? a : b; }
struct ao_hex_image *
ao_hex_image_cat(struct ao_hex_image *a, struct ao_hex_image *b)
--- /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; 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 <ao-ms5607.h>
+
+void
+ao_ms5607_convert(struct ao_ms5607_sample *sample, struct ao_ms5607_value *value,
+ struct ao_ms5607_prom *prom, bool is_ms5611)
+{
+ int32_t dT;
+ int32_t TEMP;
+ int64_t OFF;
+ int64_t SENS;
+
+ dT = sample->temp - ((int32_t) prom->tref << 8);
+
+ TEMP = 2000 + (((int64_t) dT * prom->tempsens) >> 23);
+
+ if (is_ms5611) {
+ OFF = ((int64_t) prom->off << 16) + (((int64_t) prom->tco * dT) >> 7);
+ SENS = ((int64_t) prom->sens << 15) + (((int64_t) prom->tcs * dT) >> 8);
+ } else {
+ OFF = ((int64_t) prom->off << 17) + (((int64_t) prom->tco * dT) >> 6);
+ SENS = ((int64_t) prom->sens << 16) + (((int64_t) prom->tcs * dT) >> 7);
+ }
+
+ if (TEMP < 2000) {
+ int32_t T2 = ((int64_t) dT * (int64_t) dT) >> 31;
+ 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) {
+ int32_t TEMPP = TEMP + 1500;
+ /* 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;
+ SENS -= SENS2;
+ }
+
+ value->pres = ((((int64_t) sample->pres * SENS) >> 21) - OFF) >> 15;
+ value->temp = TEMP;
+}
--- /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; 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.
+ */
+
+#ifndef _AO_MS5607_H_
+#define _AO_MS5607_H_
+
+#include <stdint.h>
+#include <stdbool.h>
+
+struct ao_ms5607_prom {
+ uint16_t reserved;
+ uint16_t sens;
+ uint16_t off;
+ uint16_t tcs;
+ uint16_t tco;
+ uint16_t tref;
+ uint16_t tempsens;
+ uint16_t crc;
+};
+
+struct ao_ms5607_sample {
+ uint32_t pres; /* raw 24 bit sensor */
+ uint32_t temp; /* raw 24 bit sensor */
+};
+
+struct ao_ms5607_value {
+ int32_t pres; /* in Pa * 10 */
+ int32_t temp; /* in °C * 100 */
+};
+
+void
+ao_ms5607_convert(struct ao_ms5607_sample *sample, struct ao_ms5607_value *value,
+ struct ao_ms5607_prom *prom, bool is_ms5611);
+
+#endif /* _AO_MS5607_H_ */
* 2.82V * 2047 / 3.3 counts/V = 1749 counts/115 kPa
*/
-static const double counts_per_kPa = 27 * 2047 / 3300;
-static const double counts_at_101_3kPa = 1674.0;
-
double
cc_barometer_to_pressure(double count)
{
{
struct cc_flightraw *f;
char line[8192];
- double ground_pres;
- int ground_pres_count;
+ double ground_pres = 0.0;
+ int ground_pres_count = 0;
f = calloc(1, sizeof (struct cc_flightraw));
if (!f)
cc_flight_cook(struct cc_flightraw *raw)
{
struct cc_flightcooked *cooked;
- double flight_start;
- double flight_stop;
+ double flight_start = 0;
+ double flight_stop = 0;
int start_set = 0;
int stop_set = 0;
int i;
#define AO_GPS_MODE_MANUAL 'M'
#define AO_GPS_MODE_SIMULATED 'S'
+#define AO_GPS_MODE_ALTITUDE_24 (1 << 0) /* reports 24-bits of altitude */
+
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) */
+ int16_t altitude_low; /* 6 GPS reported altitude (m) */
int32_t latitude; /* 8 latitude (degrees * 10⁷) */
int32_t longitude; /* 12 longitude (degrees * 10⁷) */
uint8_t year; /* 16 (- 2000) */
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 */
+ int8_t altitude_high; /* 31 */
/* 32 */
};
+typedef int32_t gps_alt_t;
+#define AO_TELEMETRY_LOCATION_ALTITUDE(l) \
+ ((l)->altitude_low | (((l)->mode & AO_GPS_MODE_ALTITUDE_24) ? \
+ ((gps_alt_t) (l)->altitude_high << 16) : 0))
+
#define AO_TELEMETRY_SATELLITE 0x06
struct ao_telemetry_satellite_info {
uint8_t c_n_1;
};
+#define AO_TELEMETRY_SATELLITE_MAX_SAT 12
+
+
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 */
+ struct ao_telemetry_satellite_info sats[AO_TELEMETRY_SATELLITE_MAX_SAT]; /* 6 */
uint8_t unused[2]; /* 30 */
/* 32 */
};
int16_t gyro_z; /* 24 */
int16_t mag_x; /* 26 */
- int16_t mag_y; /* 28 */
int16_t mag_z; /* 30 */
+ int16_t mag_y; /* 28 */
/* 32 */
};
uint16_t serial; /* 0 */
uint16_t tick; /* 2 */
uint8_t type; /* 4 */
+ uint8_t pad5[3]; /* 5 */
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 */
+ uint8_t pad18[14]; /* 18 */
/* 32 */
};
#define AO_TELEMETRY_MINI 0x10
+#define AO_TELEMETRY_MINI3 0x11
struct ao_telemetry_mini {
uint16_t serial; /* 0 */
struct dirent **namelist;
int interface;
int num_interfaces;
- char endpoint_base[20];
+ char endpoint_base[64];
char *endpoint_full;
char *tty_dir;
int ntty;
dnl Process this file with autoconf to create configure.
AC_PREREQ(2.57)
-AC_INIT([altos], 1.9)
+AC_INIT([altos], 1.9.1)
ANDROID_VERSION=18
AC_CONFIG_SRCDIR([src/kernel/ao.h])
AM_INIT_AUTOMAKE([foreign dist-bzip2])
AM_MAINTAINER_MODE
-RELEASE_DATE=2018-12-31
+RELEASE_DATE=2019-12-05
AC_SUBST(RELEASE_DATE)
VERSION_DASH=`echo $VERSION | sed 's/\./-/g'`
AC_SUBST(JCOMMON)
-AC_ARG_WITH(jvm, AS_HELP_STRING([--with-jvm-include=PATH],
- [Set jvm include path for jni builds (default searches in /usr/lib/jvm)]),
- [JVM_INCLUDE=$withval], [JVM_INCLUDE=auto])
+AC_ARG_WITH(jvm, AS_HELP_STRING([--with-jvm=PATH],
+ [Set jvm path for java builds (default searches in /usr/lib/jvm)]),
+ [JVM=$withval], [JVM=auto])
-if test "x$JVM_INCLUDE" = "xauto"; then
- AC_MSG_CHECKING([JVM include files])
- for jvm in default-java java-6-openjdk java-6-sun; do
- if test "x$JVM_INCLUDE" = "xauto"; then
+if test "x$JVM" = "xauto"; then
+ AC_MSG_CHECKING([JVM])
+ for jvm in default-java java-6-openjdk java-7-openjdk java-8-openjdk java-9-openjdk java-10-openjdk java-11-openjdk java-12-openjdk java-13-openjdk java-6-sun java-8-openjdk-amd64; do
+ if test "x$JVM" = "xauto"; then
INCLUDE="/usr/lib/jvm/$jvm/include"
if test -f "$INCLUDE"/jni.h; then
- JVM_INCLUDE="$INCLUDE"
+ JVM=/usr/lib/jvm/"$jvm"
fi
fi
done
- if test "x$JVM_INCLUDE" = "xauto"; then
- AC_MSG_ERROR([no JVM include files found])
+ if test "x$JVM" = "xauto"; then
+ AC_MSG_ERROR([no JVM files found])
fi
- AC_MSG_RESULT([$JVM_INCLUDE])
+ AC_MSG_RESULT([$JVM])
fi
+AC_ARG_WITH(java-version, AS_HELP_STRING([--with-java-version=7],
+ [Set java language compatibility version (default is 7)]),
+ [JAVA_VERSION=$withval], [JAVA_VERSION=7])
+
+JAVAC="$JVM"/bin/javac
+JAVA="$JVM"/bin/java
+JVM_INCLUDE="$JVM"/include
+JAVAC_VERSION_FLAGS="-target 1.$JAVA_VERSION -source 1.$JAVA_VERSION"
+
+AC_SUBST(JAVAC)
+AC_SUBST(JAVA)
+AC_SUBST(JVM)
AC_SUBST(JVM_INCLUDE)
+AC_SUBST(JAVAC_VERSION_FLAGS)
+
AC_ARG_WITH(android, AS_HELP_STRING([--with-android=PATH],
[Set android SDK path (default searches in a variety of places)]),
HAVE_GOOGLE_KEY="no"
fi
+WARN_CFLAGS="-Wall -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wnested-externs"
+AC_SUBST(WARN_CFLAGS)
+
AC_ARG_ENABLE(faketime, AS_HELP_STRING([--enable-faketime],
[Use faketime program to ensure pdf files are reproducible (default=no)]),
[FAKETIME=$enableval], [FAKETIME=no])
fi
AM_CONDITIONAL([ASCIIDOCTOR_PDF], [test x$HAVE_ASCIIDOCTOR_PDF != xno])
+AC_ARG_WITH([strip-nondeterminism],
+ [AS_HELP_STRING([--with-strip-nondeterminism],
+ [Name of non-deterministic build data stripping tool])],
+ [],
+ [with_strip_nondeterminism=auto])
+
+if test "x$with_strip_nondeterminism" != "xno"; then
+ if test "x$with_strip_nondeterminism" = "xauto"; then
+ with_strip_nondeterminism="strip-nondeterminism"
+ AC_CHECK_PROG([HAVE_STRIP_NONDETERMINISM],[$with_strip_nondeterminism], yes, no)
+ else
+ HAVE_STRIP_NONDETERMINISM=yes
+ fi
+else
+ HAVE_STRIP_NONDETERMINISM=no
+fi
+AM_CONDITIONAL([STRIP_NONDETERMINISM], [test x$HAVE_STRIP_NONDETERMINISM != xno])
+AC_SUBST(STRIP_NONDETERMINISM, "$with_strip_nondeterminism")
+
PKG_CHECK_MODULES([JANSSON], [jansson])
AC_ARG_WITH([readline],
telegps/telegps-windows.nsi
altosdroid/Makefile
altosdroid/local.properties
-altosdroid/AndroidManifest.xml
+altosdroid/app/src/main/AndroidManifest.xml
ao-tools/Makefile
ao-tools/lib/Makefile
ao-tools/ao-rawload/Makefile
ao-tools/ao-cal-freq/Makefile
ao-tools/ao-test-gps/Makefile
ao-tools/ao-usbtrng/Makefile
-ao-tools/ao-chaosread/Makefile
ao-tools/ao-makebin/Makefile
ao-utils/Makefile
map-server/Makefile
map-server/altos-mapd/Makefile
map-server/altos-map/Makefile
map-server/altos-mapj/Makefile
-src/Version
])
echo ""
echo " Newlib-nano support.........: ${NEWLIB_NANO}"
echo " i386 and amd64 libaltos.....: ${MULTI_ARCH}"
echo " install shared mime info....: ${INSTALL_SHARED_MIME_INFO}"
+echo " Strip jar timestamps........: ${STRIP_NONDETERMINISM}"
echo ""
echo " Java"
echo " freetts.....................: ${FREETTS}"
endif
RELNOTES_INC=\
+ release-notes-1.9.1.inc \
release-notes-1.9.inc \
release-notes-1.8.7.inc \
release-notes-1.8.6.inc \
ADOC_FILES=$(TXT_FILES:.txt=.adoc) $(INC_FILES:.inc=.adoc)
+TELELAUNCH_TXT_FILES=altusmetrum.txt
+
+TELELAUNCH_INC_FILES=\
+ header.inc \
+ telelaunch-acknowledgements.inc \
+ telelaunch-intro.inc \
+ telelaunch-configuration.inc \
+ telelaunch-operation.inc \
+ telelaunch-specs.inc \
+ telelaunch-updating-firmware.inc \
+ telelaunch-cables.inc \
+ telelaunch-troubleshooting.inc
+
+TELELAUNCH_ADOC_FILES=$(TELELAUNCH_TXT_FILES:.txt=.adoc) $(TELELAUNCH_INC_FILES:.inc=.adoc)
+
TELEGPS_INC_FILES=\
telegps-dedication.inc \
telegps-quick-start.inc \
AM_HTML=am.html
-PUBLISH_HTML=altusmetrum.html micropeak.html telegps.html easymini.html $(ONEFILE_HTML_FILES)
+PUBLISH_HTML=altusmetrum.html micropeak.html telegps.html easymini.html telelaunch.html $(ONEFILE_HTML_FILES)
HTML=$(PUBLISH_HTML) $(RELNOTES_HTML)
if ASCIIDOCTOR_PDF
-PDF=altusmetrum.pdf micropeak.pdf telegps.pdf easymini.pdf $(ONEFILE_PDF_FILES) \
+PDF=altusmetrum.pdf micropeak.pdf telegps.pdf easymini.pdf telelaunch.pdf $(ONEFILE_PDF_FILES) \
$(OUTLINE_PDF_FILES)
endif
altusmetrum.pdf altusmetrum.html: $(ADOC_FILES) $(IMAGES)
+telelaunch.pdf telelaunch.html: $(TELELAUNCH_ADOC_FILES) $(IMAGES)
+
telegps.html telegps.pdf: $(TELEGPS_ADOC_FILES) $(IMAGES)
micropeak.pdf micropeak.html: $(MICROPEAK_ADOC_FILES) $(IMAGES)
scp -p $(ICONS) keithp.com:~keithp/public_html/altos/images/icons
clean:
- rm -f am.html $(HTML) $(PDF) $(ADOC_FILES) $(TELEGPS_ADOC_FILES) $(MICROPEAK_ADOC_FILES)
+ rm -f am.html $(HTML) $(PDF) $(ADOC_FILES) $(TELEGPS_ADOC_FILES) $(MICROPEAK_ADOC_FILES) $(TELELAUNCH_ADOC_FILES)
distclean: clean
rm -f $(HTML) $(PDF)
easymini-release-notes.inc
telegps-release-notes.inc
+* Update version in main docs
+
+ altusmetrum.txt
+ easymini.txt
+ micropeak.txt
+ telegps.txt
+ telemetry.txt
+
* Add release-notes-${version}.inc to git
* Make sure new hardware specs are documented in specs.inc
.Flight Map
image::graph-map.png[width=400]
- 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.
+ Shows a satellite image of the flight area
+ overlaid with the path of the flight. The
+ flight path will have different colored
+ sections for each state of the flight (just
+ like the Site Map in Monitor Flight mode):
+ white for pad, red for boost, pink for fast,
+ yellow for coast, light blue for drogue, dark
+ blue for main, and black for landed.
+
+ The red concentric circles mark the launch
+ pad, the black concentric circles mark the
+ landing location. Data for the point along the
+ along the flight path nearest the cursor will
+ be displayed at the bottom of the window. This
+ data includes flight time (so you can
+ correlate data in the graph window), latitude,
+ longitude, height above ground and vertical
+ speed. The selected point will be highlighted
+ with concentric circles in the same color as
+ the flight path at that point.
+
endif::gps[]
=== Export Data
programming).
endif::telemetrum,telemini[]
ifdef::telemega,easymega,telemetrum[]
- TeleMega, EasyMega, TeleMetrum v2,
- EasyMini and TeleDongle v3 are all
+ TeleMega, EasyMega, TeleMetrum v2 or newer,
+ EasyMini, TeleBT v3 or newer and TeleDongle v3
+ or newer are all
endif::telemega,easymega,telemetrum[]
ifndef::telemega,easymega,telemetrum[]
EasyMini is
content: '{page-number}'
literal:
font_family: DejaVu Sans Mono
+code:
+ font_family: DejaVu Sans Mono
= The Altus Metrum System: An Owner's Manual for Altus Metrum Rocketry Electronics
Keith Packard <keithp@keithp.com>; Bdale Garbee <bdale@gag.com>; Bob Finch; Anthony Towns
:title-logo-image: image:../themes/background.png[]
-:revnumber: v1.9
-:revdate: 31 Dec 2018
+:revnumber: v1.9.1
+:revdate: 5 Dec 2019
:icons:
:icontype: svg
-:revremark: Add EasyMega v2.0 support
-:copyright: Bdale Garbee and Keith Packard 2018
+:copyright: Bdale Garbee and Keith Packard 2019
:doctype: book
:numbered:
:stylesheet: am.css
transmission is disabled.
ifdef::altusmetrum[]
This option is
- available on TeleMetrum v2 and TeleMega
+ available on TeleMetrum v2 or newer and TeleMega
boards. TeleMetrum v1 boards cannot transmit
APRS packets.
endif::altusmetrum[]
[appendix]
== Release Notes
+ :leveloffset: 2
+ include::release-notes-1.9.1.adoc[]
+
+ <<<<
+ :leveloffset: 2
+ include::release-notes-1.9.adoc[]
+
+ <<<<
+ :leveloffset: 2
+ include::release-notes-1.8.7.adoc[]
+
+ <<<<
:leveloffset: 2
include::release-notes-1.8.6.adoc[]
= EasyMini Owner's Manual
Keith Packard <keithp@keithp.com>; Bdale Garbee <bdale@gag.com>
:title-logo-image: image:../themes/background.png[]
-:revnumber: v1.8.7
-:revdate: 8 Oct 2018
-:copyright: Bdale Garbee and Keith Packard 2018
+:revnumber: v1.9.1
+:revdate: 5 Dec 2019
+:copyright: Bdale Garbee and Keith Packard 2019
:doctype: book
:numbered:
:toc:
|TeleMetrum v1.0 |8 |1MB |20
|TeleMetrum v1.1 v1.2 |8 |2MB |40
|TeleMetrum v2.0 |16 |8MB |80
+ |TeleMetrum v3.0 |16 |8MB |80
endif::telemetrum[]
ifdef::telemini[]
|TeleMini v1.0 |2 |5kB |4
for storing flight log data.
ifdef::telemetrum,telemega,easymega[]
- TeleMetrum v2.0, TeleMega and EasyMega
+ TeleMetrum v2 or newer, TeleMega and EasyMega
store configuration data in a bit of eeprom available within
the processor chip, leaving that space available in flash for
more flight data.
together. That will slightly under-estimate the storage (in
bytes) needed for the flight.
ifdef::telemetrum[]
- For instance, a TeleMetrum v2.0 flight spending
+ For instance, a TeleMetrum v2 or newer 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.
to trickle charge. It can take several hours to fully recharge a
deeply discharged battery.
- TeleMetrum v2.0, TeleMega and EasyMega 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.
+ TeleMetrum v2 or newer, TeleMega and EasyMega 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.
====
endif::telemetrum,telemega,easymega[]
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. The latest version
- of TeleMetrum, v2.0, has all of the same features but with
+ support optional capabilities in the future. The later versions
+ of TeleMetrum, v2 and newer, have all of the same features but with
improved sensors and radio to offer increased performance.
Our second device was TeleMini, a dual deploy altimeter with
= MicroPeak Owner's Manual
Keith Packard <keithp@keithp.com>; Bdale Garbee <bdale@gag.com>
-:revnumber: v1.8.7
-:revdate: 8 Oct 2018
-:copyright: Bdale Garbee and Keith Packard 2018
+:revnumber: v1.9.1
+:revdate: 5 Dec 2019
+:copyright: Bdale Garbee and Keith Packard 2019
:stylesheet: am.css
:linkcss:
:toc:
these applications, change in one application
will affect the other.
+== Protecting MicroPeak from Sunlight
+
+ The MS5607 barometric sensor is sensitive to direct light. When light
+ shines through the holes in the cover to the components inside, the
+ reported pressure can vary wildly from the actual pressure. This
+ causes the reported altitude to have errors of thousands of
+ feet.
+
+ MicroPeak should be installed in an opaque compartment in the airframe
+ and not subjected to sunlight. Alternatively, a small piece of
+ adhesive-backed open-cell foam can be attached to the device so that
+ it covers the barometric sensor and protects it from direct light.
+
+ Here's what happens when MicroPeak is exposed to sunlight. At apogee,
+ I exposed MicroPeak to varying amounts of sunlight and you can see the
+ wild swings in altitude resulting from that:
+
+ .MicroPeak in Sunlight
+ image::micropeak-flight-nofoam.png[width=430]
+
+ You can carefully cutting a piece of adhesive-backed open-cell foam
+ and attach it to MicroPeak. It's important to press the adhesive to
+ the circuit board and not to the top of the barometric sensor or the
+ sensor may become blocked and not operate at all. Once you've attached
+ the foam, you should test MicroPeak on the ground to make sure it's
+ still working.
+
+ .MicroPeak with Foam
+ image::micropeak-foam.jpg[width=430]
+
+ That MicroPeak was in the same barometric chamber as the one which
+ generated the above results and the resulting flight data looks
+ correct:
+
+ .MicroPeak in Sunlight with Foam
+ image::micropeak-flight-foam.png[width=430]
+
[appendix]
== Handling Precautions
sensor out of direct sunlight.
The barometric sensor sampling ports 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.
+ "breathe", both by not being covered by solid 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.
+
+ One good solution is to use a small rectangle of Poron
+ 50-30031-12X12P or equivalent to cover the sensor. This is an
+ open cell foam in 1/32" thickness with an adhesive backing. It
+ seems to do a good job of blocking sun while still allowing
+ airflow to and from the sensor internals.
As with all other rocketry electronics, Altus Metrum
altimeters must be protected from exposure to corrosive motor
--- /dev/null
+= Release Notes for Version 1.9.1
+include::release-head.adoc[]
+:doctype: article
+
+ Version 1.9.1
+
+ == AltOS
+
+ * Add support for TeleMetrum v3.0
+
+ * Fix accel cal value when changing EasyMega v2.0 pad orientation
+
+ * Correct EasyMega v2.0 magnetometer data axes
+
+ * Fix EasyMega v2.0 idle monitor display of IMU data
+
+ * Report all sensor failures at power-up time.
+
+ == AltosUI, TeleGPS, MicroPeak
+
+ * Display error message when attempting to graph unknown format file.
+
+ * Make it possible to disable APRS once enabled.
+
+ * Display some data for point near cursor in map tab.
+
+ * Support upgrading devices from pre-1.8 firmware
+
+ * Wait for Windows to prepare new devices during firmware
+ upgrade. This should avoid the “COMxx: open failed” message.
[appendix]
== Release Notes
+ :leveloffset: 2
+ include::release-notes-1.9.1.adoc[]
+
+ <<<<
:leveloffset: 2
include::release-notes-1.9.adoc[]
|40mW
|3.7V
+ |TeleMetrum v3.0
+ |MS5607 30km (100k')
+ |ADXL375 200g
+ |uBlox Max-8Q
+ |-
+ |8MB
+ |40mW
+ |3.7V
+
endif::telemetrum[]
ifdef::telemini[]
|TeleMini v1.0
endif::radio[]
ifdef::gps+radio[]
- :aprsdevices: TeleMetrum v2.0 and TeleMega
+ :aprsdevices: TeleMetrum v2 and newer and TeleMega
:configure_section: _configure_altimeter
include::aprs-operation.adoc[]
endif::gps+radio[]
[appendix]
== Release Notes
+ :leveloffset: 2
+ include::release-notes-1.9.1.adoc[]
+
+ <<<<
+ :leveloffset: 2
+ include::release-notes-1.9.adoc[]
+
+ <<<<
+ :leveloffset: 2
+ include::release-notes-1.8.7.adoc[]
+
+ <<<<
:leveloffset: 2
include::release-notes-1.8.6.adoc[]
onboard flash before it fills up. TeleGPS will still
report telemetry even if memory is full, so the only
thing you will lose is the on-board data log.
-
+
+ === LEDs
+
+ TeleGPS v1.0 has a dual greed/red LED along the edge
+ towards the USB connector end of the board. This
+ indicates battery charging status while connected to
+ power over USB. When the red LED is lit, the battery
+ is charging. Once the battery is fully charged, the
+ red LED goes out and the green LED turns on. If both
+ LEDs are lit, something is probably wrong with the battery.
+
+ TeleGPS v2.0 has the same green/red battery charging
+ status LED and adds another green LED along the same
+ edge, towards end of the board with the 70cm
+ antenna. This green LED indicates GPS lock status — it
+ blinks once every three seconds when the GPS receiver
+ is locked and tracking position.
+
=== Installation
The battery connectors are a standard 2-pin JST
= TeleGPS Owner's Manual
Keith Packard <keithp@keithp.com>; Bdale Garbee <bdale@gag.com>
:title-logo-image: image:../themes/background.png[]
-:revnumber: v1.8.7
-:revdate: 8 Oct 2018
-:revremark: Fix TeleBT v4.0 RF calibration to factory value when reflashing. Fix map images. Fix Mac OS X support.
-:copyright: Bdale Garbee and Keith Packard 2018
+:revnumber: v1.9.1
+:revdate: 5 Dec 2019
+:copyright: Bdale Garbee and Keith Packard 2019
:stylesheet: am.css
:linkcss:
:toc:
--- /dev/null
+[dedication]
+== Acknowledgments
+
+ Our profound thanks to Terry Lee for major contributions to making
+ the TeleLaunch system something we could actually package and sell!
+
+ Tripoli Colorado, Oregon Rocketry, New River Valley Rocketry, and
+ the National Association of Rocketry helped instigate this work,
+ and/or were early adopters of TeleLaunch. We learned a lot working
+ with each organization. Thank you!
+
+ Thanks also to our friends in the Kloudbusters, both for helping
+ us understand what it takes to run truly great large-scale launches,
+ and for providing some completely deserved, scathing feedback on
+ an early prototype of TeleLCO.
+
+ Have fun using these products, and we hope to meet all of you
+ out on a rocket flight line somewhere.
+
+ [verse]
+ Bdale Garbee, KB0G
+ NAR #87103, TRA #12201
+
+ [verse]
+ Keith Packard, KD7SQG
+ NAR #88757, TRA #12200
--- /dev/null
+[appendix]
+== Making Pad Cables
+
+ Pad cables can be made from standard AC extension cords and alligator
+ clips...
--- /dev/null
+== Configuration
+
+ There are three things you need to configure identically in each unit
+ that is part of a TeleLaunch system for wireless communications to
+ succeed. Those are the operating frequency, the callsign, and a key
+ for the AES encryption algorithm. Additionally, each TeleFire unit
+ also needs to be configured with a unique bank number.
+
+ Please note that these values must match exactly, or the system will
+ not operate as expected. That means the callsign needs to have the
+ same choices of upper or lower case, no trailing spaces, etc. And
+ the operating frequency and AES key must match.
+
+ === Connecting to a Unit
+
+ Configuring each unit of a TeleLaunch system requires use of
+ a micro USB cable, and a computer with a suitable terminal
+ emulation program. Connect a suitable cable, open your
+ favoriate terminal emulation program, and power up the unit.
+ By pressing <enter> you should see a command prompt.
+
+ === TeleLCO
+
+ The USB connector on TeleLCO is accessible without
+ opening the lid of the Pelican box. Look for the
+ blue dust cap over the connector under the handle.
+
+ === TeleFireEight
+
+ The USB connector on TeleFireEight is located on the
+ circuit board. To access it, open the box and flip
+ the lid up. you should be able to spot a vertical
+ micro USB connector on the board near the DIP switch.
+
+ [WARNING]
+ Please take care when closing the TeleFireEight lid
+ not to pinch any wires.
+
+ === Operating Frequency
+
+ The TeleLaunch system supports operation over much of the
+ "70cm" Amateur Radio band, with the filters optimized for a
+ center frequency of 435 MHz. For each system, a single
+ operating frequency should be selected and programmed into
+ each unit.
+
+ The default frequency for units leaving the factory is
+ 435.750 MHz. Since Altus Metrum flight computers operate
+ by default on 10 100khz channels from 434.550 to 435.450 MHz,
+ we chose this frequency to be far enough away from flight
+ computers to avoid any interference, but still close enough
+ to the radio subsystem design center frequency for great
+ performance.
+
+ To configure the frequency, use your terminal emulator to
+ issue two commands. First, use 'c F xxxxxx' where the xxxxxx
+ is replaced with the desired operating frequency in kHz. Then
+ use the 'c w' command to save this value into non-volatile
+ memory. For example, the default 435.750 MHz would be
+ configured using
+
+ c f 435750 +
+ c w
+
+
+ === Callsign
+
+ In the US, you need an
+ link:http://www.altusmetrum.org/Radio/[amateur radio license]
+ or other authorization to legally operate the radio
+ transmitters that are part of TeleLaunch.
+
+ The default callsign shipped from the factory is "N0CALL",
+ which is not a valid callsign and meant to humorously point
+ out that the callsign hasn't been configured yet.
+
+ Individual owners of a TeleLaunch system should use their
+ own callsign.
+
+ Club owners of a TeleLaunch system should pick the callsign
+ of one club member who is willing to be designated as the
+ control operator of the system. Under FCC Part 97 rules,
+ being the control operator does not mean you have to be LCO
+ all the time, it just means taking responsibility for ensuring
+ the system is being operated in compliance with the rules.
+
+ To configure the callsign, use your terminal emulator to
+ issue two commands. First, use 'c c callsign' to set the
+ callsign, then use 'c w' to write to non-volatile memory.
+ For example, to set the default N0CALL, the commands would
+ be
+
+ c c N0CALL +
+ c w
+
+ === AES Key
+
+ For safety, TeleLaunch uses cryptographic checksums to help
+ prevent interference, intentional or un-intentional. This
+ means each system must have a shared AES encryption key
+ identically configured into each unit.
+
+ The key size required is 128 bits, which must be expressed
+ as a 32-digit hexadecimal number.
+
+ To configure the AES key, use 'c a key' followed by 'c w'
+ to write the key to non-volatile memory. For example, to
+ configure your system with a key that is the answer to life,
+ the universe, and everything, the commands would be
+
+ c a 00000000000000000000000000000042 +
+ c w
+
+ === Bank Number
+
+ Each TeleFire unit needs to be configured with a bank number,
+ and bank numbers should be unique within a given system. For
+ most systems with 8 or fewer banks, just use the DIP switch
+ on the circuit board inside the TeleFire unit to select the
+ desired bank. Only one switch should be turned on. Switch
+ one means bank one, etc.
+
+ To allow systems to have more than 8 banks, if all the DIP
+ switches are "off", the unit will use the bank configured in
+ non-volatile memory.
+
+ To configure the bank number, use 'c B bank' followed by
+ 'c w' to write to non-volatile memory. For example, to
+ set the bank to 42, the commands would be:
+
+ c B 42 +
+ c w
+
--- /dev/null
+== Introduction and Overview
+
+Welcome to the Altus Metrum community! Our circuits and software reflect
+our passion for both hobby rocketry and Free Software. We hope their
+capabilities and performance will delight you in every way, but by
+releasing all of our hardware and software designs under open licenses,
+we also hope to empower you to take as active a role in our collective
+future as you wish!
+
+Thank you for your interest in TeleLaunch, a wireless control system for
+launching hobby rockets. Each TeleLaunch system contains at least two units,
+a launch control box (TeleLCO) and one or more launch initiation boxes
+(TeleFire). In this manual, we hope to provide all the information required
+to configure and successfully operate a TeleLaunch system.
+
+Unlike other Altus Metrum products, that are usually provided as circuit
+boards that the user must arrange to mount and wire up, all products in the
+TeleLaunch system are sold as fully packaged, almost-ready-to-use units. This
+means that with only minimal one-time configuration of each unit, a TeleLaunch
+system can be made ready for use very quickly.
+
+Because documentation is just as prone as software to contain "bugs", and
+can always be improved... If you have questions that aren't answered in this
+manual, or just need a little help figuring things out, we strongly suggest
+joining the Altus Metrum user email list, which you can do by visiting
+https://lists.gag.com/mailman/listinfo/altusmetrum.
+
--- /dev/null
+== Operation
+
+ Operating a TeleLaunch system is pretty easy, and we hope fairly
+ intuitive for anyone who has ever launched rockets before. Basic
+ instructions are printed on a decal inside the lid of each TeleLCO
+ unit, which early customers (before this manual was even written)
+ reported were sufficient to successfully use the system.
+
+ The remainder of this section assumes the system has already been
+ properly configured with callsign, AES key, and bank numbers for each
+ TeleFire box.
+
+ === Charging Batteries
+
+ TeleLCO has an internal Lithium Polymer battery that is
+ charged over USB. A weather-tight micro USB connector is
+ installed with a blue cap under the handle. This position
+ was chosen so that TeleLCO can be charged while the lid is
+ closed and standing handle-up. Attach a micro USB cable
+ to a computer or other source of USB power. There are two
+ charge indicators on the panel that will illuminate during
+ charging, red for charge in progress and green for charge
+ complete.
+
+ TeleFire has an internal sealed lead acid 12V battery, and
+ is provided with an external AC charger. Connect this charger
+ to the PowerPole connector on the back face of the box to
+ charge the battery. Other sources of charging current for
+ a nominal 12V sealed battery may be used. The charge
+ connector can also be used to attach an external battery if
+ needed.
+
+ === Setting Up
+
+ Each unit in the TeleLaunch system needs a suitable antenna
+ attached. A typical configuration would involve the provided
+ omni-directional antenna or optional directional antenna aimed
+ at the field mounted on a pole attached to TeleLCO at the
+ launch control station, and the provided rubber whip antennas
+ on each TeleFire box.
+
+ If deploying the system in rough terrain, on a field with
+ dense vegetation, or at great distances (some away cells), you
+ may need a better antenna or at least to mount the antenna
+ higher off the ground. All units in the TeleLaunch system
+ have tri-color RF signal strength indicators. A system should
+ show green on all units during normal operation. An occasional
+ dip to amber is ok, but frequent amber or any red indicates a
+ need to improve the antenna situation.
+
+ Antenna made for use near 435 Mhz in the ham radio "70cm band"
+ should work, and there are many online sources of information
+ on making inexpensive, highly effective antennas at home.
+
+ The TeleLCO unit should be placed on a table at the Launch
+ Control position. It can be helpful for the LCO (the human(s)
+ too, not just the electronics!) to be provided with some
+ shade, but the use of reflective LCDs for the digit
+ displays and ultri-bright LEDs make TeleLCO operation
+ reasonable even in direct sunlight.
+
+ Each TeleFire box should be placed in proximity to the launch
+ rails it will service. Whip clips made from AC power cords
+ (not provided) should be attached to TeleFire and routed to
+ each launch rail. The pyro output on each channel is
+ connected to the "line" and "neutral" pins on the outlet,
+ while the ground pin is attached to chassis ground.
+
+ === Turning System On
+
+ Turn on all TeleFire pad boxes in the system. At power-on,
+ all LEDs will turn on briefly so you can verify they're all
+ working. The radio signal strength indicators will show red
+ until TeleLCO is turned on.
+
+ Turn on TeleLCO. All LCD segments and LEDs will turn on
+ briefly so you can verify they're all working. An exception
+ are the two battery charger LEDs, which only illuminate when
+ the battery is charging. The LCD displays will then briefly
+ display the internal battery voltage, which should be at least
+ 3.9V for normal operation. TeleLCO then scans to locate all
+ TeleFire boxes that are in range and configured for the same
+ frequency, callsign, and AES key. During this process, the
+ Bank LCD diplays will appear to be counting up from 1 to 99.
+ When the search is complete, the Pad display will show the
+ number of TeleFire devices found. TeleLCO beeps when ready.
+
+ === Launch One Rocket
+
+ Switch the TeleFire to 'Safe' and confirm it is silent.
+
+ Put a rocket on a launch rail / rod, and connect whip clips
+ from a pad output on a TeleFire unit to the motor igniter.
+ Verify igniter continuity using the LED associated with that
+ output. Green is good.
+
+ Switch the TeleFire unit from 'Safe' to 'Arm', at which point
+ it will start "chirping" to indicate that it is "armed and
+ dangerous". Move to the TeleLCO at a safe distance away.
+
+ Ensure the TeleLCO blue Drag Race switch is on Normal and
+ the blue Drag Race LED is extinguished.
+
+ Select the desired TeleFire unit by pushing the TeleLCO
+ selector knob until the "Bank" LED is lit, then rotating the
+ knob until the
+ desired box is selected. Then push the knob until the Pad
+ LED is lit and rotate the knob until the desired pad is
+ selected. Verify the Remote Armed LED is lit, and that the
+ selected pad's Igniter Continuity LED is lit.
+
+ Perform range safety checks.
+
+ Move the TeleLCO SAFE/ARM switch to ARM. This will cause
+ the selected TeleFire unit's strobe to start flashing and
+ siren to become more insistent.
+
+ Perform count-down.
+
+ Depress the LAUNCH button and hold until the rocket launches.
+
+ Move the TeleLCO SAFE/ARM switch back to SAFE.
+
+ === Launch A Multi-Rocket "Drag Race"
+
+ To enable drag race mode, move the TeleLCO blue switch to
+ Drag Race. The blue Drag Race LED should illuminate.
+
+ Select pads to include in the drag race by using the same
+ process as for a single rocket to select each Bank and Pad,
+ then press Add/Remove to toggle the currently selected pad
+ in the race. The continuity LEDs blink ON/off for selected,
+ and on/OFF for deselected (long ON means in the race).
+
+ A drag race can be configured to include pads on multiple
+ TeleFire boxes, but the blinking continuity indicators to
+ show which pads are included can only indicate the currently
+ selected bank.
+
+ Verify remotes are ready and armed by using the Remote Armed
+ and Igniter Continuity LEDs.
+
+ Perform range safety checks.
+
+ Move the TeleLCO SAFE/ARM switch to ARM. This will cause
+ the selected TeleFire units strobes to start flashing and
+ sirens to become more insistent.
+
+ Perform count-down.
+
+ Depress the LAUNCH button and hold until rockets launch.
+
+ Move the TeleLCO SAFE/ARM switch back to SAFE.
+
+ Move Drag Race switch back to Normal.
+
+ Note that if there is a mis-fire in a drag race and you want
+ to fix igniters and try again, the current drag configuration
+ is preserved as long as you stay in Drag Race mode. So you
+ can SAFE the system, fix igniters, and try again before leaving
+ Drag Race mode if desired.
--- /dev/null
+== Specifications
+
+ The TeleLaunch system can handle up to 99 banks with each bank
+ having up to 8 pads, for a total of 792 pads.
+
+ Each unit in the TeleLaunch system is water-resistant, but is not
+ intended to be directly immersed in water. Brief rain showers during
+ a launch should pose no problem, but it's recommended to cover units
+ or bring them inside when not in use or during extended periods of
+ bad weather.
+
+ TeleLCO uses an internal single-cell 2Ah Lithium Polymer battery,
+ which is sufficient for multiple days of typical operation. This
+ battery is charged over USB.
+
+ TeleFire uses an internal sealed lead-acid 12V battery, which is
+ charged by an external charger attached through the PowerPole
+ connector on the rear panel.
+
+ Pyro initiation uses the 12V sealed lead-acid battery. Current
+ to any pad can exceed 30A, and with typical igniters every pad on
+ a TeleFire can be successfully included in a drag race. The system
+ controls current flow to prevent damage, and has a self-resetting
+ circuit breaker for ultimate protection should something go badly
+ wrong.
+
+ TeleLaunch uses AES encryption with a shared key between each unit
+ in the system to ensure the integrity of safe launch operations.
+
+ The TeleLaunch system uses radio frequency communications in the
+ vicinity of 435 Mhz. A US amateur radio license or equivalent
+ authorization is required to legally use the system. The operating
+ frequency should be chosen to avoid conflict with other devices, or
+ put differently, nothing else should be operating on the same
+ frequency while TeleLaunch is in use.
+
--- /dev/null
+[appendix]
+== Troubleshooting
+
+ === TeleFire Fails to Arm
+
+ If turning the TeleLCO key switch from "SAFE" to "ARM" does
+ not cause the selected TeleFire box to start flashing and
+ sounding its siren, the most likely cause is that the
+ TeleFire box was left with the local safe/arm switch in the
+ safe position. The Remote Arm LED on TeleLCO shows the state
+ of the safe/arm switch on the currently selected TeleFire box
+ and can be used to confirm this situation.
+
+ Note that in a cross-bank drag race configuration, any TeleFire
+ boxes involved in the drag race that are fully armed will
+ launch, while any TeleFire boxes involved in the drag race
+ that are not fully armed will not launch. Pay attention to
+ make sure all involved TeleFire boxes are flashing their
+ strobe lights and sounding their sirens before launch to
+ ensure all desired rockets will actually participate in such
+ a drag race.
+
+ === Radio Signal Strength
+
+ Each unit in the TeleLaunch system has a debugging feature
+ that can be used to view the actual received radio signal
+ strength of each packet. To use this feature, connect to the
+ desired unit (TeleLCO is probably the most useful place to
+ start) with a laptop and terminal program as explained in the
+ configuration section of the manual. Then, you can enable
+ debug tracing using 'D 1' command.
+
+ Debug mode is fairly chatty, but each time the TeleLCO unit
+ queries the currently selected TeleFire unit for igniter
+ status, the return packet will print out the RSSI value.
+ RSSI is "received signal strength indicated" and is expressed
+ in decibel units relative to a milliwatt, or "dBm".
+
+ Observing the RSSI is a great way to compare antennas, antenna
+ mounting arrangements, and so forth with more granularity than
+ provided by the red/amber/green operational LED indicators.
+
+ The system is good down to below -100dBm, and it takes about
+ 6dB to double the range. So a reading of -80dBm means that you
+ could extend the distance between the units by a factor of
+ 10 before losing the link. Note, however, that real world
+ range is affected by terrain, vegetation, etc. And you really
+ don't ever want to be operating close to the minimum signal
+ threshold! Keep the RF signal indicators green with good
+ antenna choices and installations for maximum satisfaction.
--- /dev/null
+== Updating Firmware
+
+ The firmware for each unit can be updated over USB. More details
+ will be forthcoming if/when a firmware update is required.
--- /dev/null
+= TeleLaunch: The Altus Metrum Wireless Launch Control System
+Bdale Garbee <bdale@gag.com>
+:title-logo-image: image:../themes/background.png[]
+:revnumber: v0.1
+:revdate: 16 Feb 2019
+:icons:
+:icontype: svg
+:revremark: initial draft
+:copyright: Bdale Garbee 2019
+:doctype: book
+:numbered:
+:stylesheet: am.css
+:linkcss:
+:toc:
+:telelaunch: 1
+:application: TeleLaunch
+:pdf-stylesdir: .
+:pdf-style: altusmetrum
+:pdf-fontsdir: fonts
+
+ include::header.adoc[]
+
+ include::telelaunch-acknowledgements.adoc[]
+
+ include::telelaunch-intro.adoc[]
+
+ include::telelaunch-configuration.adoc[]
+
+ include::telelaunch-operation.adoc[]
+
+ include::telelaunch-specs.adoc[]
+
+ include::telelaunch-updating-firmware.adoc[]
+
+ include::telelaunch-cables.adoc[]
+
+ include::telelaunch-troubleshooting.adoc[]
+
bay for TeleMetrum should have at least 10 inches of interior length.
There are two generations of the TeleMetrum design. The
- major changes in the v2 generation are:
+ major changes after v1 generation are:
* uBlox GPS chip certified for altitude records
= AltOS Telemetry
Keith Packard <keithp@keithp.com>; Bdale Garbee <bdale@gag.com>
-:revnumber: v1.8.7
-:revdate: 8 Oct 2018
-:copyright: Bdale Garbee and Keith Packard 2018
+:revnumber: v1.9.1
+:revdate: 5 Dec 2019
+:copyright: Bdale Garbee and Keith Packard 2019
:stylesheet: am.css
:linkcss:
:doctype: article
|32
|====
- === TeleMetrum v2 Sensor Data
+ === TeleMetrum v2 and newer Sensor Data
.TeleMetrum v2 Packet Type
[options="border",cols="1,3"]
|0x0B |TeleMetrum v2 Calibration Data
|====
- TeleMetrum v2 has higher resolution barometric data than
+ TeleMetrum v2 and newer have higher resolution barometric data than
TeleMetrum v1, and so the constant calibration data is
split out into a separate packet.
- TeleMetrum v2 Sensor Data packets are transmitted once per second on the
+ TeleMetrum v2 and newer Sensor Data packets are transmitted once per second on the
ground, 10 times per second during ascent and once per second
during descent and landing
- TeleMetrum v2 Calibration Data packets are always transmitted once per second.
+ TeleMetrum v2 and newer Calibration Data packets are always transmitted once per second.
- .TeleMetrum v2 Sensor Packet Contents
+ .TeleMetrum v2 and newer Sensor Packet Contents
[options="border",cols="2,3,3,9"]
|====
|Offset |Data Type |Name |Description
|32
|====
- .TeleMetrum v2 Calibration Data Packet Contents
+ .TeleMetrum v2 and newer Calibration Data Packet Contents
[options="border",cols="2,3,3,9"]
|====
|Offset |Data Type |Name |Description
|CC1111
|10mW transceiver with integrated SoC
- |TeleDongle v0.2, TeleBT v1.0, TeleMetrum v1.x, TeleMini
+ |TeleDongle v0.2, TeleBT v1.0, TeleMetrum v1.x, TeleMini v1
|CC1120
|35mW transceiver with SW FEC
- |TeleMetrum v2, TeleMega
+ |TeleMetrum v2, TeleMega v1
|CC1200
|35mW transceiver with HW FEC
- |TeleDongle v3.0, TeleBT v3.0
+ |TeleMetrum v3, TeleMega v2, TeleDongle v3.0, TeleMini v3, TeleBT v3.0, TeleGPS v2
|CC115L
|14mW transmitter with SW FEC
- |TeleGPS
+ |TeleGPS v1
|====
== Updating Device Firmware
ifdef::telemega[]
- TeleMega, TeleMetrum v2, EasyMega, EasyMini and TeleDongle v3
+ TeleMega, TeleMetrum v2 and newer, EasyMega, EasyMini and TeleDongle v3
are all
endif::telemega[]
ifndef::telemega[]
ifdef::telemega[]
- === Updating TeleMega, TeleMetrum v2, EasyMega, EasyMini or TeleDongle v3 Firmware
+ === Updating TeleMega, TeleMetrum v2 or newer, EasyMega, EasyMini, TeleDongle v3 or TeleBT v3 Firmware
endif::telemega[]
ifndef::telemega[]
endif::easymega[]
ifdef::telemetrum[]
- TeleMetrum v2::
+ TeleMetrum v2 and newer::
Connect pin 6 and pin 1 of the companion
connector. Pin 1 can be identified by the square pad
the one on the other end of the row.
endif::easymini[]
+ TeleGPS v1::
+
+ Connect pin 32 on the CPU to ground. Pin 32 is the
+ right-most pin on the bottom edge of the CPU when the
+ board is oriented with the USB and battery connectors
+ to the right.
+
+ TeleGPS v2::
+
+ Connect together pins 1 and 5 of the Debug connector.
+ Pin 1 is the pin with the square pad around the hole.
+
ifdef::telemetrum[]
TeleDongle v3::
of the board. Ground is available on the capacitor
next to it, on the end towards the USB wires.
+ TeleBT v3::
+
+ Connect pin 4 on the CPU to 3.3V, which can be done by
+ connecting pin 1 to pin 4. Pin 1 is the left pin on
+ the lower edge of the chip when the unit is oriented
+ such that the SMA is at the top.
+
TeleBT v4::
Connect pin 30 on the CPU to ground. Pin 30 is the 6th
*.icns
*.build
*.exe
+*led.png
+*on.png
+*off.png
+*led.svg
+*on.svg
+*off.svg
windows-stub.o: windows-stub.c
$(MINGCC32) -c $(MINGFLAGS) windows-stub.c
+
+altosdroid.png: altosdroid.svg
+ rsvg-convert -a -b white -h 480 altosdroid.svg | pngtopnm | pnmpad -white -width 512 -height 512 | pnmtopng > $@
--- /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:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ id="svg2"
+ width="194.5914"
+ height="245.27174"
+ version="1.0"
+ sodipodi:version="0.32"
+ inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
+ sodipodi:docname="altosdroid.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ inkscape:export-filename="/home/keithp/src/cc1111/altus-logo/bottom.png"
+ inkscape:export-xdpi="119.89881"
+ inkscape:export-ydpi="119.89881">
+ <metadata
+ id="metadata14">
+ <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></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs12">
+ <linearGradient
+ id="linearGradient3165">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop3167" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop3169" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3177">
+ <stop
+ style="stop-color:#da7000;stop-opacity:1;"
+ offset="0"
+ id="stop3179" />
+ <stop
+ id="stop3447"
+ offset="0.24528302"
+ style="stop-color:#a63852;stop-opacity:1;" />
+ <stop
+ style="stop-color:#7200a4;stop-opacity:1;"
+ offset="1"
+ id="stop3181" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3169">
+ <stop
+ style="stop-color:#ff8a00;stop-opacity:1;"
+ offset="0"
+ id="stop3171" />
+ <stop
+ id="stop3445"
+ offset="0.71698111"
+ style="stop-color:#c24573;stop-opacity:0.98039216;" />
+ <stop
+ style="stop-color:#8500e7;stop-opacity:0.96078432;"
+ offset="1"
+ id="stop3173" />
+ </linearGradient>
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 121 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="191 : 121 : 1"
+ inkscape:persp3d-origin="95.5 : 80.666667 : 1"
+ id="perspective16" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3169"
+ id="radialGradient3175"
+ cx="951.68713"
+ cy="2305.2668"
+ fx="951.68713"
+ fy="2305.2668"
+ r="951.68701"
+ gradientTransform="matrix(1,0,0,1.2664529,0,-321.14689)"
+ gradientUnits="userSpaceOnUse" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3165"
+ id="radialGradient3171"
+ cx="951.68713"
+ cy="1205.2668"
+ fx="951.68713"
+ fy="1205.2668"
+ r="951.68701"
+ gradientTransform="matrix(1,0,0,1.2664529,0,-321.14689)"
+ gradientUnits="userSpaceOnUse" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3169"
+ id="radialGradient3020"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1,0,0,1.2664529,0,-321.14689)"
+ cx="951.68713"
+ cy="2305.2668"
+ fx="951.68713"
+ fy="2305.2668"
+ r="951.68701" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3165"
+ id="radialGradient3022"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1,0,0,1.2664529,0,-321.14689)"
+ cx="951.68713"
+ cy="1205.2668"
+ fx="951.68713"
+ fy="1205.2668"
+ r="951.68701" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3169"
+ id="radialGradient3024"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1,0,0,1.2664529,0,-321.14689)"
+ cx="951.68713"
+ cy="2305.2668"
+ fx="951.68713"
+ fy="2305.2668"
+ r="951.68701" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3165"
+ id="radialGradient3026"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1,0,0,1.2664529,0,-321.14689)"
+ cx="951.68713"
+ cy="1205.2668"
+ fx="951.68713"
+ fy="1205.2668"
+ r="951.68701" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3169"
+ id="radialGradient3028"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1,0,0,1.2664529,0,-321.14689)"
+ cx="951.68713"
+ cy="2305.2668"
+ fx="951.68713"
+ fy="2305.2668"
+ r="951.68701" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3165"
+ id="radialGradient3030"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1,0,0,1.2664529,0,-321.14689)"
+ cx="951.68713"
+ cy="1205.2668"
+ fx="951.68713"
+ fy="1205.2668"
+ r="951.68701" />
+ <filter
+ id="filter3005"
+ inkscape:label="Drop Shadow"
+ style="color-interpolation-filters:sRGB">
+ <feFlood
+ id="feFlood3007"
+ flood-opacity="0.604"
+ flood-color="rgb(0,0,0)"
+ result="flood" />
+ <feComposite
+ id="feComposite3009"
+ in2="SourceGraphic"
+ in="flood"
+ operator="in"
+ result="composite1" />
+ <feGaussianBlur
+ id="feGaussianBlur3011"
+ stdDeviation="80"
+ result="blur" />
+ <feOffset
+ id="feOffset3013"
+ dx="100"
+ dy="100"
+ result="offset" />
+ <feComposite
+ id="feComposite3015"
+ in2="offset"
+ in="SourceGraphic"
+ operator="over"
+ result="composite2" />
+ </filter>
+ </defs>
+ <sodipodi:namedview
+ inkscape:cy="21.690273"
+ inkscape:cx="35.762591"
+ inkscape:zoom="1.629332"
+ inkscape:window-height="1177"
+ inkscape:window-width="1462"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0.0"
+ guidetolerance="10.0"
+ gridtolerance="10.0"
+ objecttolerance="10.0"
+ borderopacity="1.0"
+ bordercolor="#666666"
+ pagecolor="#ffffff"
+ id="base"
+ showgrid="false"
+ inkscape:window-x="266"
+ inkscape:window-y="43"
+ inkscape:current-layer="svg2"
+ inkscape:window-maximized="0"
+ fit-margin-top="2"
+ fit-margin-left="2"
+ fit-margin-right="2"
+ fit-margin-bottom="2" />
+ <g
+ transform="matrix(0.1,0,0,0.1,2.1269908,2.1683864)"
+ id="g3"
+ style="fill:url(#radialGradient3175);fill-opacity:1;stroke:url(#radialGradient3171);stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none">
+ <g
+ transform="translate(20.61545,-27.69425)"
+ style="fill:url(#radialGradient3028);fill-opacity:1;fill-rule:evenodd;stroke:url(#radialGradient3030);stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none"
+ id="g5">
+ <path
+ d="m 931.07168,1164.597 248.86992,-331.80265 416.1687,1338.32935 286.6484,267.1042 H 1362.3363 L 1092.0566,2176.0098 V 1142.9471 L 931.07168,1249.6289 770.08676,1142.9471 v 1033.0627 l -270.2797,262.2181 h -520.4224 l 286.6484,-267.1042 416.1687,-1338.32935 z"
+ id="path7"
+ style="fill:url(#radialGradient3020);fill-opacity:1;stroke:url(#radialGradient3022);stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none"
+ inkscape:connector-curvature="0" />
+ <path
+ d="m 931.07168,27.69425 224.03682,720.46517 -63.341,76.00913 -160.69582,-337.84165 -160.69582,337.84165 -63.341,-76.00913 z"
+ id="path9"
+ style="fill:url(#radialGradient3024);fill-opacity:1;stroke:url(#radialGradient3026);stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+</svg>
cjnitest
cjnitest32
cjnitest64
+btletest
libaltos.swig
swig_bindings/
-JAVAC=javac
AM_CFLAGS=-DLINUX -DPOSIX_TTY -I$(JVM_INCLUDE) -I$(JVM_INCLUDE)/linux
-AM_JAVACFLAGS=-target 1.6 -encoding UTF-8 -Xlint:deprecation -source 6
+AM_JAVACFLAGS=$(JAVAC_VERSION_FLAGS) -encoding UTF-8 -Xlint:deprecation -Xlint:unchecked
altoslibdir=$(libdir)/altos
JAVAROOT=classes
-AM_JAVACFLAGS=-target 1.6 -encoding UTF-8 -Xlint:deprecation -Xlint:unchecked -source 6
+AM_JAVACFLAGS=$(JAVAC_VERSION_FLAGS) -encoding UTF-8 -Xlint:deprecation -Xlint:unchecked
altoslibdir=$(libdir)/altos
$(JAR): classaltosmapd.stamp Manifest.txt $(ALTOSLIB_CLASS)
jar cfm $@ Manifest.txt \
-C classes altosmapd
+if STRIP_NONDETERMINISM
+ $(STRIP_NONDETERMINISM) $@
+endif
altosmapddir=$(datadir)/java
$(FATJAR): classaltosmapd.stamp Manifest-fat.txt $(ALTOSLIB_CLASS)
jar cfm $@ Manifest-fat.txt \
-C classes altosmapd
+if STRIP_NONDETERMINISM
+ $(STRIP_NONDETERMINISM) $@
+endif
altos-mapd: Makefile
echo "#!/bin/sh" > $@
JAVAROOT=classes
-AM_JAVACFLAGS=-target 1.6 -encoding UTF-8 -Xlint:deprecation -Xlint:unchecked -source 6
+AM_JAVACFLAGS=$(JAVAC_VERSION_FLAGS) -encoding UTF-8 -Xlint:deprecation -Xlint:unchecked
altoslibdir=$(libdir)/altos
$(JAR): classaltosmap.stamp Manifest.txt $(ALTOSLIB_CLASS)
jar cfm $@ Manifest.txt \
-C classes altosmap
+if STRIP_NONDETERMINISM
+ $(STRIP_NONDETERMINISM) $@
+endif
altosmapdir=$(datadir)/java
$(FATJAR): classaltosmap.stamp Manifest-fat.txt $(ALTOSLIB_CLASS)
jar cfm $@ Manifest-fat.txt \
-C classes altosmap
+if STRIP_NONDETERMINISM
+ $(STRIP_NONDETERMINISM) $@
+endif
altos-mapj: Makefile
echo "#!/bin/sh" > $@
JAVAROOT=classes
-AM_JAVACFLAGS=-target 1.6 -encoding UTF-8 -Xlint:deprecation -Xlint:unchecked -source 6
+AM_JAVACFLAGS=$(JAVAC_VERSION_FLAGS) -encoding UTF-8 -Xlint:deprecation -Xlint:unchecked
man_MANS=micropeak.1
$(ICONJAR) \
-C classes org \
-C ../libaltos libaltosJNI
+if STRIP_NONDETERMINISM
+ $(STRIP_NONDETERMINISM) $@
+endif
$(FATJAR): classmicropeak.stamp Manifest-fat.txt $(ALTOSLIB_CLASS) $(ALTOSUILIB_CLASS) $(JFREECHART_CLASS) $(JCOMMON_CLASS) $(JAVA_ICONS)
jar cfm $@ Manifest-fat.txt \
$(ICONJAR) \
-C classes org \
-C ../libaltos libaltosJNI
+if STRIP_NONDETERMINISM
+ $(STRIP_NONDETERMINISM) $@
+endif
classaltosui.stamp: $(ALTOSLIB_CLASS) $(ALTOSUILIB_CLASS)
AVR_CC=@AVR_CC@
AVR_OBJCOPY=@AVR_OBJCOPY@
HAVE_AVR_CC=@HAVE_AVR_CC@
+
+VERSION=@VERSION@
vpath load_csv.5c kalman
vpath matrix.5c kalman
-include Version
TOPDIR=.
+
include Makedefs
ARMM3DIRS=\
telebt-v3.0 telebt-v3.0/flash-loader \
telebt-v4.0 telebt-v4.0/flash-loader \
telelcotwo-v0.1 telelcotwo-v0.1/flash-loader \
+ telefireone-v1.0 telefireone-v1.0/flash-loader \
telefiretwo-v0.1 telefiretwo-v0.1/flash-loader \
- telefireeight-v1.0 telefireeight-v1.0/flash-loader
+ telefireeight-v1.0 telefireeight-v1.0/flash-loader \
+ telefireeight-v2.0 telefireeight-v2.0/flash-loader
ARMM0DIRS=\
easymini-v1.0 easymini-v1.0/flash-loader \
micropeak-v2.0 micropeak-v2.0/flash-loader
AVRDIRS=\
- micropeak microkite
+ micropeak microkite microsplash
SUBDIRS=
--- /dev/null
+include $(TOPDIR)/Makedefs
+
+AO_VPATH=$(TOPDIR)/product:$(TOPDIR)/drivers:$(TOPDIR)/kernel:$(TOPDIR)/util:$(TOPDIR)/kalman:$(TOPDIR)/aes:$(TOPDIR)/math:$(TOPDIR)/draw:$(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
+
+WARN_FLAGS=-Wall -Wextra -Werror -Wcast-align \
+ -Wpointer-arith \
+ -Wstrict-prototypes \
+ -Wmissing-prototypes \
+ -Wmissing-declarations \
+ -Wnested-externs \
+ -Wshadow \
+ -Warray-bounds=2
+
+OPT=-Os
+
+NEWLIB_PRINTF_CFLAGS = -DNEWLIB_INTEGER_PRINTF_SCANF
+
+NEWLIB_CFLAGS= \
+ -ffreestanding -nostdlib \
+ -isystem $(NEWLIB_NANO)/arm-none-eabi/include \
+ $(NEWLIB_PRINTF_CFLAGS)
+
+AO_CFLAGS=\
+ -std=gnu99 \
+ -I. -I$(TOPDIR) -I$(TOPDIR)/kernel -I$(TOPDIR)/drivers \
+ -I$(TOPDIR)/math -I$(TOPDIR)/draw -I$(TOPDIR)/product $(WARN_FLAGS) $(OPT) -g
+
+NICKLE=nickle
+ELFTOHEX=$(TOPDIR)/../ao-tools/ao-elftohex/ao-elftohex
+
+.SUFFIXES: .elf .ihx
+
+.elf.ihx:
+ $(ELFTOHEX) --output=$@ $*.elf
+
+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 $@ $<
+
+.DEFAULT_GOAL=all
+
+ao_product.h: ao-make-product.5c $(TOPDIR)/Makedefs
+ $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@
+
+++ /dev/null
-VERSION=@VERSION@
--- /dev/null
+include $(TOPDIR)/avr/Makefile-avr.defs
+
+vpath % $(TOPDIR)/attiny:$(AO_VPATH)
+
+MCU=attiny85
+DUDECPUTYPE=t85
+#PROGRAMMER=stk500v2 -P usb
+LOADSLOW=-i 32 -B 32
+LOADARG=-p $(DUDECPUTYPE) -c $(PROGRAMMER) -e -U flash:w:
+
+ATTINY_CFLAGS = -mmcu=$(MCU) -mcall-prologues -DATTINY \
+ -I$(TOPDIR)/attiny $(AO_CFLAGS)
\ No newline at end of file
--- /dev/null
+include $(TOPDIR)/attiny/Makefile-attiny.defs
#define AO_LED_TYPE uint8_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))
ao_wakeup((void *) &ao_tick_count);
}
-uint16_t
+AO_TICK_TYPE
ao_time(void)
{
uint16_t r;
void
ao_exti_setup_port(uint8_t pin, uint8_t mode, void (*callback)(void))
{
+ (void) mode;
pcint_callback = callback;
pcint_mask = (1 << pin);
ao_exti_disable(PORTB, pin);
PRODUCT_DEF=-DAVR_DEMO
IDPRODUCT=0x000a
CFLAGS = $(PRODUCT_DEF) -I. -I../avr -I../kernel -I..
-CFLAGS += -g -mmcu=$(MCU) -Wall -Wstrict-prototypes -Os -mcall-prologues
+CFLAGS += -mmcu=$(MCU) -Wall -Wstrict-prototypes -mcall-prologues
NICKLE=nickle
--- /dev/null
+ifndef TOPDIR
+TOPDIR=..
+endif
+
+include $(TOPDIR)/Makefile.defs
+
+CC=$(AVR_CC)
+OBJCOPY=$(AVR_OBJCOPY)
+LDSCRIPTS=/usr/lib/avr/lib/ldscripts
+
+PROGRAMMER=usbtiny
+LOADCMD=avrdude
TOPDIR=..
endif
-ifndef VERSION
-include $(TOPDIR)/Version
-endif
-
-include $(TOPDIR)/Makedefs
+include $(TOPDIR)/Makefile.defs
CC=$(AVR_CC)
OBJCOPY=$(AVR_OBJCOPY)
#define ao_arch_task_globals uint8_t ao_cpu_sleep_disable;
-#define ao_arch_task_members\
- uint8_t *sp; /* saved stack pointer */
-
-#define ao_arch_init_stack(task, start) do { \
- uint8_t *sp = task->stack + AO_STACK_SIZE - 1; \
- uint16_t a = (uint16_t) start; \
- int i; \
- \
- /* Return address */ \
- AVR_PUSH8(sp, a); \
- AVR_PUSH8(sp, (a >> 8)); \
- \
- /* Clear register values */ \
- i = 32; \
- while (i--) \
- AVR_PUSH8(sp, 0); \
- \
- /* SREG with interrupts enabled */ \
- AVR_PUSH8(sp, 0x80); \
- task->sp = sp; \
-} while (0);
+#define ao_arch_init_stack(task, start) \
+ do { \
+ uint8_t *sp = task->stack8 + AO_STACK_SIZE - 1; \
+ uint16_t a = (uint16_t) start; \
+ int i; \
+ \
+ /* Return address */ \
+ AVR_PUSH8(sp, a); \
+ AVR_PUSH8(sp, (a >> 8)); \
+ \
+ /* Clear register values */ \
+ i = 32; \
+ while (i--) \
+ AVR_PUSH8(sp, 0); \
+ \
+ /* SREG with interrupts enabled */ \
+ AVR_PUSH8(sp, 0x80); \
+ task->sp8 = sp; \
+ } while (0);
#define ao_arch_save_regs() do { \
asm("push r31" "\n\t" "push r30"); \
uint8_t sp_l, sp_h; \
asm("in %0,__SP_L__" : "=&r" (sp_l) ); \
asm("in %0,__SP_H__" : "=&r" (sp_h) ); \
- ao_cur_task->sp = (uint8_t *) ((uint16_t) sp_l | ((uint16_t) sp_h << 8)); \
+ ao_cur_task->sp8 = (uint8_t *) ((uint16_t) sp_l | ((uint16_t) sp_h << 8)); \
} while (0)
#define ao_arch_isr_stack() /* nothing */
#define ao_arch_restore_stack() do { \
uint8_t sp_l, sp_h; \
- sp_l = (uint16_t) ao_cur_task->sp; \
- sp_h = ((uint16_t) ao_cur_task->sp) >> 8; \
+ sp_l = (uint16_t) ao_cur_task->sp8; \
+ sp_h = ((uint16_t) ao_cur_task->sp8) >> 8; \
asm("out __SP_H__,%0" : : "r" (sp_h) ); \
asm("out __SP_L__,%0" : : "r" (sp_l) ); \
asm("pop r0" "\n\t" \
IDVENDOR=0x1d50
IDPRODUCT=0x60c6
-CFLAGS = $(PRODUCT_DEF) $(STMF0_CFLAGS) -g -Os
+CFLAGS = $(PRODUCT_DEF) $(STMF0_CFLAGS)
PROGNAME=chaoskey-v0.1
PROG=$(PROGNAME)-$(VERSION).elf
IDVENDOR=0x1d50
IDPRODUCT=0x60c6
-CFLAGS = $(PRODUCT_DEF) $(STMF0_CFLAGS) -g -Os
+CFLAGS = $(PRODUCT_DEF) $(STMF0_CFLAGS)
PROGNAME=chaoskey-v1.0
PROG=$(PROGNAME)-$(VERSION).elf
all: $(PROG) $(HEX) $(BIN)
$(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 -V $(IDVENDOR) -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) -o $@
+ $(call quiet,CC) $(LDFLAGS) -o $(PROG) $(OBJ) $(LIBS)
$(OBJ): $(INC)
#include <ao_trng_send.h>
#include <ao_flash_readout.h>
-void main(void)
+int
+main(void)
{
ao_led_init();
ao_clock_init();
AO_CFLAGS=-I. -I../stm -I../kernel -I../drivers -I../draw -I../scheme -I.. -I/local/newlib-mini/arm-none-eabi/include
LIBS=-lc -lm -lgcc
-CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF) -Os -g
+CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF)
SRC=$(ALTOS_SRC) ao_cortexelf.c
PRODUCT_DEF=-DDETHERM_V_1_0
IDPRODUCT=0x0013
-CFLAGS = $(PRODUCT_DEF) $(STMF0_CFLAGS) -g -Os
+CFLAGS = $(PRODUCT_DEF) $(STMF0_CFLAGS)
PROGNAME=detherm-v1.0
PROG=$(PROGNAME)-$(VERSION).elf
ao_ee_flush_internal();
ao_ee_block = block;
}
- ao_xmemcpy(ao_ee_data + (uint16_t) (pos & 0xff), buf, len);
+ memcpy(ao_ee_data + (uint16_t) (pos & 0xff), buf, len);
ao_ee_block_dirty = 1;
} ao_mutex_put(&ao_ee_mutex);
return 1;
/* Transfer the data */
ao_mutex_get(&ao_ee_mutex); {
ao_ee_fill(block);
- ao_xmemcpy(buf, ao_ee_data + (uint16_t) (pos & 0xff), len);
+ memcpy(buf, ao_ee_data + (uint16_t) (pos & 0xff), len);
} ao_mutex_put(&ao_ee_mutex);
return 1;
}
ao_mutex_get(&ao_ee_mutex); {
ao_ee_flush_internal();
ao_ee_block = (uint16_t) (pos >> EE_BLOCK_SHIFT);
- ao_xmemset(ao_ee_data, 0xff, EE_BLOCK_SIZE);
+ memset(ao_ee_data, 0xff, EE_BLOCK_SIZE);
ao_ee_block_dirty = 1;
} ao_mutex_put(&ao_ee_mutex);
return 1;
--- /dev/null
+/*
+ * Copyright © 2019 Bdale Garbee <bdale@gag.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.
+ */
+
+#include <ao.h>
+#include <ao_exti.h>
+#include "ao_ads124s0x.h"
+
+#define DEBUG_LOW 1
+#define DEBUG_HIGH 2
+
+#define DEBUG 0
+
+#if DEBUG
+#define PRINTD(l, ...) do { if (DEBUG & (l)) { printf ("\r%5u %s: ", ao_tick_count, __func__); printf(__VA_ARGS__); flush(); } } while(0)
+#else
+#define PRINTD(l,...)
+#endif
+
+struct ao_ads124s0x_sample ao_ads124s0x_current;
+uint8_t nextchan = 0;
+uint8_t ao_ads124s0x_drdy;
+
+static void
+ao_ads124s0x_start(void) {
+ ao_spi_get_bit(AO_ADS124S0X_SPI_CS_PORT,
+ AO_ADS124S0X_SPI_CS_PIN,
+ AO_ADS124S0X_SPI_BUS,
+ AO_ADS124S0X_SPI_SPEED);
+}
+
+static void
+ao_ads124s0x_stop(void) {
+ ao_spi_put_bit(AO_ADS124S0X_SPI_CS_PORT,
+ AO_ADS124S0X_SPI_CS_PIN,
+ AO_ADS124S0X_SPI_BUS);
+}
+
+static uint8_t
+ao_ads124s0x_reg_read(uint8_t addr)
+{
+ uint8_t d[3];
+
+ d[0] = addr | AO_ADS124S0X_RREG;
+ d[1] = 0;
+ d[2] = 0;
+ ao_ads124s0x_start();
+ ao_spi_duplex(d, d, 3, AO_ADS124S0X_SPI_BUS);
+ ao_ads124s0x_stop();
+
+ PRINTD(DEBUG_LOW, "read %x = %x\n", addr, d[0]);
+
+ return d[2];
+}
+
+/*
+static void
+ao_ads124s0x_reg_write(uint8_t addr, uint8_t value)
+{
+ uint8_t d[3];
+
+ PRINTD(DEBUG_LOW, "write %x %x\n", addr, value);
+ d[0] = addr | AO_ADS124S0X_WREG;
+ d[1] = 0;
+ d[2] = value;
+ ao_ads124s0x_start();
+ ao_spi_send(d, 3, AO_ADS124S0X_SPI_BUS);
+ ao_ads124s0x_stop();
+
+}
+*/
+
+static void
+ao_ads124s0x_isr(void)
+{
+ ao_ads124s0x_drdy = 1;
+ ao_wakeup(&ao_ads124s0x_drdy);
+}
+
+static void
+ao_ads124s0x_setup(void)
+{
+ uint8_t d[20];
+
+ ao_delay(1);
+
+ ao_gpio_set(AO_ADS124S0X_RESET_PORT, AO_ADS124S0X_RESET_PIN, 1);
+
+ ao_delay(1);
+
+ uint8_t devid = ao_ads124s0x_reg_read(AO_ADS124S0X_ID);
+ if ((devid & 7) != AO_ADS124S0X_ID_ADS124S06)
+ ao_panic(AO_PANIC_SELF_TEST_ADS124S0X);
+
+ ao_exti_setup(AO_ADS124S0X_DRDY_PORT, AO_ADS124S0X_DRDY_PIN,
+ AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_HIGH,
+ ao_ads124s0x_isr);
+
+ /* run converter at 4ksps so we can scan 4 channels at 1ksps using
+ full duplex ala datasheet section 9.5.4.3 */
+
+ d[0] = AO_ADS124S0X_INPMUX | AO_ADS124S0X_WREG;
+ d[1] = 8; /* write 8 registers starting with INPMUX */
+ d[2] = 0x0c; /* input mux AIN0 relative to AINCOM */
+ d[3] = 0x00; /* default first conversion delay, pga disabled */
+ d[4] = 0x1e; /* gchop disabled, internal clock, continuous
+ conversion, low-latency filter, 4000 SPS */
+ d[5] = 0x00; /* ref monitor disabled, ref buffers bypassed, ref
+ set to REFP0/REFN0, internal reference off */
+ d[6] = 0x00; /* pga otuput rail, low side power switch, excitation
+ current source all off */
+ d[7] = 0xff; /* idac1 and idac2 disconnected */
+ d[8] = 0x00; /* all vbias disconnected */
+ d[9] = 0x10; /* sys monitor off, spi timeout disabled, crc disabled,
+ prepending status byte disabled */
+ ao_ads124s0x_start();
+ ao_spi_send(d, 10, AO_ADS124S0X_SPI_BUS);
+ ao_ads124s0x_stop();
+
+ /* start conversions */
+
+ d[0] = AO_ADS124S0X_START;
+ ao_ads124s0x_start();
+ ao_spi_send(d, 1, AO_ADS124S0X_SPI_BUS);
+ ao_ads124s0x_stop();
+}
+
+static void
+ao_ads124s0x(void)
+{
+ uint8_t d[3], curchan;
+
+ ao_ads124s0x_setup();
+
+ ao_exti_enable(AO_ADS124S0X_DRDY_PORT, AO_ADS124S0X_DRDY_PIN);
+
+ for (;;) {
+ ao_arch_block_interrupts();
+ ao_ads124s0x_drdy = 0;
+ while (ao_ads124s0x_drdy == 0)
+ ao_sleep(&ao_ads124s0x_drdy);
+ ao_arch_release_interrupts();
+
+ curchan = nextchan;
+ nextchan = (nextchan + 1) % AO_ADS124S0X_CHANNELS;
+
+ d[0] = AO_ADS124S0X_INPMUX | AO_ADS124S0X_WREG;
+ d[1] = 1;
+ d[2] = nextchan << 4 | 0x0c; ; /* relative to AINCOM */
+ ao_ads124s0x_start();
+ ao_spi_duplex(d, d, 3, AO_ADS124S0X_SPI_BUS);
+ ao_ads124s0x_stop();
+
+ ao_ads124s0x_current.ain[curchan] =
+ d[0] << 16 | d[1] << 8 | d[2];
+
+ // FIXME
+ // If nextchan == 0, we have a complete set of inputs
+ // and we need to log them somewhere
+
+ ao_ads124s0x_drdy = 0;
+ }
+}
+
+static struct ao_task ao_ads124s0x_task;
+
+static void
+ao_ads124s0x_dump(void)
+{
+ static int done;
+
+ if (!done) {
+ done = 1;
+ ao_add_task(&ao_ads124s0x_task, ao_ads124s0x, "ads124s0x");
+ }
+
+ printf ("ADS124S0X value %d %d %d %d\n",
+ ao_ads124s0x_current.ain[0],
+ ao_ads124s0x_current.ain[1],
+ ao_ads124s0x_current.ain[2],
+ ao_ads124s0x_current.ain[3]);
+}
+
+const struct ao_cmds ao_ads124s0x_cmds[] = {
+ { ao_ads124s0x_dump, "I\0Display ADS124S0X data" },
+ { 0, NULL },
+};
+
+void
+ao_ads124s0x_init(void)
+{
+ ao_cmd_register(ao_ads124s0x_cmds);
+
+ ao_enable_output(AO_ADS124S0X_RESET_PORT, AO_ADS124S0X_RESET_PIN, 0);
+
+ ao_spi_init_cs(AO_ADS124S0X_SPI_CS_PORT,
+ (1 << AO_ADS124S0X_SPI_CS_PIN));
+
+// ao_add_task(&ao_ads124s0x_task, ao_ads124s0x, "ads124s0x");
+}
--- /dev/null
+/*
+ * Copyright © 2019 Bdale Garbee <bdale@gag.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.
+ */
+
+#ifndef _AO_ADS124S0X_H_
+#define _AO_ADS124S0X_H_
+
+/* control commands */
+#define AO_ADS124S0X_NOP 0x00
+#define AO_ADS124S0X_WAKEUP 0x02
+#define AO_ADS124S0X_POWERDOWN 0x04
+#define AO_ADS124S0X_RESET 0x06
+#define AO_ADS124S0X_START 0x08
+#define AO_ADS124S0X_STOP 0x0a
+
+/* calibration commands */
+#define AO_ADS124S0X_SYOCAL 0x16
+#define AO_ADS124S0X_SYGCAL 0x17
+#define AO_ADS124S0X_SFOCAL 0x19
+
+/* data read command */
+#define AO_ADS124S0X_RDATA 0x12
+
+/* register read and write commands */
+#define AO_ADS124S0X_RREG 0x20
+#define AO_ADS124S0X_WREG 0x40
+
+/* configuration register map */
+#define AO_ADS124S0X_ID 0x00
+#define AO_ADS124S0X_ID_ADS124S08 0x00
+#define AO_ADS124S0X_ID_ADS124S06 0x01
+#define AO_ADS124S0X_STATUS 0x01
+#define AO_ADS124S0X_INPMUX 0x02
+#define AO_ADS124S0X_PGA 0x03
+#define AO_ADS124S0X_DATARATE 0x04
+#define AO_ADS124S0X_REF 0x05
+#define AO_ADS124S0X_IDACMAG 0x06
+#define AO_ADS124S0X_IDACMUX 0x07
+#define AO_ADS124S0X_VBIAS 0x08
+#define AO_ADS124S0X_SYS 0x09
+#define AO_ADS124S0X_OFCAL0 0x0a
+#define AO_ADS124S0X_OFCAL1 0x0b
+#define AO_ADS124S0X_OFCAL2 0x0c
+#define AO_ADS124S0X_FSCAL0 0x0d
+#define AO_ADS124S0X_FSCAL1 0x0e
+#define AO_ADS124S0X_FSCAL2 0x0f
+#define AO_ADS124S0X_GPIODAT 0x10
+#define AO_ADS124S0X_GPIOCON 0x11
+
+struct ao_ads124s0x_sample {
+ int32_t ain[AO_ADS124S0X_CHANNELS];
+};
+
+extern struct ao_ads124s0x_sample ao_ads124s0x_current;
+
+void
+ao_ads124s0x_init(void);
+
+#endif /* _AO_ADS124S0X_H_ */
--- /dev/null
+/*
+ * Copyright © 2019 Bdale Garbee <bdale@gag.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.
+ */
+
+#ifndef _AO_ADS131A0X_H_
+#define _AO_ADS131A0X_H_
+
+/* control commands */
+#define AO_ADS131A0X_NOP 0x00
+#define AO_ADS131A0X_WAKEUP 0x02
+#define AO_ADS131A0X_POWERDOWN 0x04
+#define AO_ADS131A0X_RESET 0x06
+#define AO_ADS131A0X_START 0x08
+#define AO_ADS131A0X_STOP 0x0a
+
+/* calibration commands */
+#define AO_ADS131A0X_SYOCAL 0x16
+#define AO_ADS131A0X_SYGCAL 0x17
+#define AO_ADS131A0X_SFOCAL 0x19
+
+/* data read command */
+#define AO_ADS131A0X_RDATA 0x12
+
+/* register read and write commands */
+#define AO_ADS131A0X_RREG 0x20
+#define AO_ADS131A0X_WREG 0x40
+
+/* configuration register map */
+#define AO_ADS131A0X_ID 0x00
+#define AO_ADS131A0X_ID_ADS131A08 0x00
+#define AO_ADS131A0X_ID_ADS131A06 0x01
+#define AO_ADS131A0X_STATUS 0x01
+#define AO_ADS131A0X_INPMUX 0x02
+#define AO_ADS131A0X_PGA 0x03
+#define AO_ADS131A0X_DATARATE 0x04
+#define AO_ADS131A0X_REF 0x05
+#define AO_ADS131A0X_IDACMAG 0x06
+#define AO_ADS131A0X_IDACMUX 0x07
+#define AO_ADS131A0X_VBIAS 0x08
+#define AO_ADS131A0X_SYS 0x09
+#define AO_ADS131A0X_OFCAL0 0x0a
+#define AO_ADS131A0X_OFCAL1 0x0b
+#define AO_ADS131A0X_OFCAL2 0x0c
+#define AO_ADS131A0X_FSCAL0 0x0d
+#define AO_ADS131A0X_FSCAL1 0x0e
+#define AO_ADS131A0X_FSCAL2 0x0f
+#define AO_ADS131A0X_GPIODAT 0x10
+#define AO_ADS131A0X_GPIOCON 0x11
+
+struct ao_ads131a0x_sample {
+ int32_t ain[AO_ADS131A0X_CHANNELS];
+};
+
+extern struct ao_ads131a0x_sample ao_ads131a0x_current;
+
+void
+ao_ads131a0x_init(void);
+
+#endif /* _AO_ADS131A0X_H_ */
uint8_t devid = ao_adxl375_reg_read(AO_ADXL375_DEVID);
if (devid != AO_ADXL375_DEVID_ID)
- ao_sensor_errors = 1;
+ AO_SENSOR_ERROR(AO_DATA_ADXL375);
/* Set the data rate */
ao_adxl375_reg_write(AO_ADXL375_BW_RATE,
self_test_value = z_change;
if (z_change < MIN_SELF_TEST)
- ao_sensor_errors = 1;
+ AO_SENSOR_ERROR(AO_DATA_ADXL375);
/* This check is commented out as maximum self test is unreliable
if (z_change > MAX_SELF_TEST)
- ao_sensor_errors = 1;
+ AO_SENSOR_ERROR(AO_DATA_ADXL375);
*/
int16_t apogee = ao_ignite_decivolt(AO_SENSE_DROGUE(&packet));
#endif
#ifdef AO_SENSE_MAIN
- int16_t main = ao_ignite_decivolt(AO_SENSE_MAIN(&packet));
+ int16_t main_value = ao_ignite_decivolt(AO_SENSE_MAIN(&packet));
#endif
return sprintf((char *) buf,
apogee%10
#endif
#ifdef AO_SENSE_MAIN
- , main/10,
- main%10
+ , main_value/10,
+ main_value%10
#endif
, ao_serial_number
);
ao_flash_flush_internal();
ao_flash_block = block;
}
- ao_xmemcpy(ao_flash_data + (uint16_t) (pos & ao_flash_block_mask),
+ memcpy(ao_flash_data + (uint16_t) (pos & ao_flash_block_mask),
buf,
len);
ao_flash_block_dirty = 1;
/* Transfer the data */
ao_mutex_get(&ao_flash_mutex); {
ao_flash_fill(block);
- ao_xmemcpy(buf,
+ memcpy(buf,
ao_flash_data + (uint16_t) (pos & ao_flash_block_mask),
len);
} ao_mutex_put(&ao_flash_mutex);
ao_mutex_get(&ao_flash_mutex); {
ao_flash_flush_internal();
ao_flash_block = (uint16_t) (pos >> ao_flash_block_shift);
- ao_xmemset(ao_flash_data, 0xff, ao_flash_block_size);
+ memset(ao_flash_data, 0xff, ao_flash_block_size);
ao_flash_block_dirty = 1;
} ao_mutex_put(&ao_flash_mutex);
return 1;
--- /dev/null
+/*
+ * Copyright © 2019 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 <ao.h>
+#include <ao_bmx160.h>
+#include <ao_exti.h>
+
+static uint8_t ao_bmx160_configured;
+
+#define ao_bmx160_spi_get() ao_spi_get(AO_BMX160_SPI_BUS, AO_SPI_SPEED_8MHz)
+#define ao_bmx160_spi_put() ao_spi_put(AO_BMX160_SPI_BUS)
+
+#define ao_bmx160_spi_start() ao_spi_set_cs(AO_BMX160_SPI_CS_PORT, \
+ (1 << AO_BMX160_SPI_CS_PIN))
+
+#define ao_bmx160_spi_end() ao_spi_clr_cs(AO_BMX160_SPI_CS_PORT, \
+ (1 << AO_BMX160_SPI_CS_PIN))
+
+static void
+_ao_bmx160_reg_write(uint8_t addr, uint8_t value)
+{
+ uint8_t d[2] = { addr, value };
+ ao_bmx160_spi_start();
+ ao_spi_send(d, 2, AO_BMX160_SPI_BUS);
+ ao_bmx160_spi_end();
+}
+
+static void
+_ao_bmx160_read(uint8_t addr, void *data, uint8_t len)
+{
+ addr |= 0x80;
+ ao_bmx160_spi_start();
+ ao_spi_send(&addr, 1, AO_BMX160_SPI_BUS);
+ ao_spi_recv(data, len, AO_BMX160_SPI_BUS);
+ ao_bmx160_spi_end();
+}
+
+static uint8_t
+_ao_bmx160_reg_read(uint8_t addr)
+{
+ uint8_t value;
+ addr |= 0x80;
+ ao_bmx160_spi_start();
+ ao_spi_send(&addr, 1, AO_BMX160_SPI_BUS);
+ ao_spi_recv(&value, 1, AO_BMX160_SPI_BUS);
+ ao_bmx160_spi_end();
+ return value;
+}
+
+static void
+_ao_bmx160_cmd(uint8_t cmd)
+{
+ _ao_bmx160_reg_write(BMX160_CMD, cmd);
+ ao_delay(AO_MS_TO_TICKS(100));
+}
+
+static void
+_ao_bmx160_mag_setup(void)
+{
+ _ao_bmx160_reg_write(BMX160_MAG_IF_0, 0x80);
+}
+
+static void
+_ao_bmm150_wait_manual(void)
+{
+ while (_ao_bmx160_reg_read(BMX160_STATUS) & (1 << BMX160_STATUS_MAG_MAN_OP))
+ ;
+}
+
+static void
+_ao_bmm150_reg_write(uint8_t addr, uint8_t data)
+{
+ _ao_bmx160_reg_write(BMX160_MAG_IF_3, data);
+ _ao_bmx160_reg_write(BMX160_MAG_IF_2, addr);
+ _ao_bmm150_wait_manual();
+}
+
+#if BMX160_TEST
+static uint8_t
+_ao_bmm150_reg_read(uint8_t addr)
+{
+ _ao_bmx160_reg_write(BMX160_MAG_IF_1, addr);
+ _ao_bmm150_wait_manual();
+ return _ao_bmx160_reg_read(BMX160_DATA_0);
+}
+#endif
+
+static void
+_ao_bmx160_sample(struct ao_bmx160_sample *sample)
+{
+ _ao_bmx160_read(BMX160_MAG_X_0_7, sample, sizeof (*sample));
+#if __BYTE_ORDER != __LITTLE_ENDIAN
+ int i = sizeof (*sample) / 2;
+ uint16_t *d = (uint16_t *) sample;
+
+ /* byte swap */
+ while (i--) {
+ uint16_t t = *d;
+ *d++ = (t >> 8) | (t << 8);
+ }
+#endif
+}
+
+#define G 981 /* in cm/s² */
+
+#if 0
+static int16_t /* cm/s² */
+ao_bmx160_accel(int16_t v)
+{
+ return (int16_t) ((v * (int32_t) (16.0 * 980.665 + 0.5)) / 32767);
+}
+
+static int16_t /* deg*10/s */
+ao_bmx160_gyro(int16_t v)
+{
+ return (int16_t) ((v * (int32_t) 20000) / 32767);
+}
+
+static uint8_t
+ao_bmx160_accel_check(int16_t normal, int16_t test)
+{
+ int16_t diff = test - normal;
+
+ if (diff < BMX160_ST_ACCEL(16) / 4) {
+ return 1;
+ }
+ if (diff > BMX160_ST_ACCEL(16) * 4) {
+ return 1;
+ }
+ return 0;
+}
+
+static uint8_t
+ao_bmx160_gyro_check(int16_t normal, int16_t test)
+{
+ int16_t diff = test - normal;
+
+ if (diff < 0)
+ diff = -diff;
+ if (diff < BMX160_ST_GYRO(2000) / 4) {
+ return 1;
+ }
+ if (diff > BMX160_ST_GYRO(2000) * 4) {
+ return 1;
+ }
+ return 0;
+}
+#endif
+
+static void
+_ao_bmx160_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_bmx160_reg_read(BMX160_CHIPID) == BMX160_CHIPID_BMX160)
+ break;
+ }
+ if (i == 30)
+ ao_panic(AO_PANIC_SELF_TEST_BMX160);
+}
+
+#define ST_TRIES 10
+#define MAG_TRIES 10
+
+static void
+_ao_bmx160_setup(void)
+{
+ if (ao_bmx160_configured)
+ return;
+
+ /* Make sure the chip is responding */
+ _ao_bmx160_wait_alive();
+
+ /* Reboot */
+ _ao_bmx160_cmd(BMX160_CMD_SOFTRESET);
+
+ /* Force SPI mode */
+ _ao_bmx160_reg_write(BMX160_NV_CONF, 1 << BMX160_NV_CONF_SPI_EN);
+
+ /* Configure accelerometer:
+ *
+ * undersampling disabled
+ * normal filter
+ * 200Hz sampling rate
+ * 16g range
+ *
+ * This yields a 3dB cutoff frequency of 80Hz
+ */
+ _ao_bmx160_reg_write(BMX160_ACC_CONF,
+ (0 << BMX160_ACC_CONF_ACC_US) |
+ (BMX160_ACC_CONF_ACC_BWP_NORMAL << BMX160_ACC_CONF_ACC_BWP) |
+ (BMX160_ACC_CONF_ACC_ODR_200 << BMX160_ACC_CONF_ACC_ODR));
+ _ao_bmx160_reg_write(BMX160_ACC_RANGE,
+ BMX160_ACC_RANGE_16G);
+
+ /* Configure gyro:
+ *
+ * 200Hz sampling rate
+ * Normal filter mode
+ * ±2000°/s
+ */
+ _ao_bmx160_reg_write(BMX160_GYR_CONF,
+ (BMX160_GYR_CONF_GYR_BWP_NORMAL << BMX160_GYR_CONF_GYR_BWP) |
+ (BMX160_GYR_CONF_GYR_ODR_200 << BMX160_GYR_CONF_GYR_ODR));
+ _ao_bmx160_reg_write(BMX160_GYR_RANGE,
+ BMX160_GYR_RANGE_2000);
+
+
+ /* Configure magnetometer:
+ *
+ * 30Hz sampling rate
+ * power on
+ * axes enabled
+ */
+ _ao_bmx160_cmd(BMX160_CMD_MAG_IF_SET_PMU_MODE(BMX160_PMU_STATUS_MAG_IF_PMU_STATUS_NORMAL));
+
+ /* Enter setup mode */
+ _ao_bmx160_mag_setup();
+
+ /* Place in suspend mode to reboot the chip */
+ _ao_bmm150_reg_write(BMM150_POWER_MODE,
+ (0 << BMM150_POWER_MODE_POWER_CONTROL));
+
+ /* Power on */
+ _ao_bmm150_reg_write(BMM150_POWER_MODE,
+ (1 << BMM150_POWER_MODE_POWER_CONTROL));
+
+ /* Set data rate and place in sleep mode */
+ _ao_bmm150_reg_write(BMM150_CONTROL,
+ (BMM150_CONTROL_DATA_RATE_30 << BMM150_CONTROL_DATA_RATE) |
+ (BMM150_CONTROL_OP_MODE_SLEEP << BMM150_CONTROL_OP_MODE));
+
+ /* enable all axes (should already be enabled) */
+ _ao_bmm150_reg_write(BMM150_INT_CONF,
+ (0 << BMM150_INT_CONF_X_DISABLE) |
+ (0 << BMM150_INT_CONF_Y_DISABLE) |
+ (0 << BMM150_INT_CONF_Z_DISABLE));
+
+ /* Set repetition values (?) */
+ _ao_bmm150_reg_write(BMM150_REPXY, BMM150_REPXY_VALUE(9));
+ _ao_bmm150_reg_write(BMM150_REPZ, BMM150_REPZ_VALUE(15));
+
+ /* To get data out of the magnetometer, set the control op mode to 'forced', then read
+ * from the data registers
+ */
+ _ao_bmx160_reg_write(BMX160_MAG_IF_3, (BMM150_CONTROL_OP_MODE_FORCED << BMM150_CONTROL_OP_MODE));
+ _ao_bmx160_reg_write(BMX160_MAG_IF_2, BMM150_CONTROL);
+ _ao_bmx160_reg_write(BMX160_MAG_IF_1, BMM150_DATA_X_0_4);
+
+ /* Set data rate to 200Hz */
+ _ao_bmx160_reg_write(BMX160_MAG_CONF,
+ (BMX160_MAG_CONF_MAG_ODR_200 << BMX160_MAG_CONF_MAG_ODR));
+
+ /* Put magnetometer interface back into 'normal mode'
+ */
+ _ao_bmx160_reg_write(BMX160_MAG_IF_0,
+ (0 << BMX160_MAG_IF_0_MAG_MANUAL_EN) |
+ (0 << BMX160_MAG_IF_0_MAG_OFFSET) |
+ (0 << BMX160_MAG_IF_0_MAG_RD_BURST));
+
+ /* Enable acc and gyr
+ */
+
+ _ao_bmx160_cmd(BMX160_CMD_ACC_SET_PMU_MODE(BMX160_PMU_STATUS_ACC_PMU_STATUS_NORMAL));
+ _ao_bmx160_cmd(BMX160_CMD_GYR_SET_PMU_MODE(BMX160_PMU_STATUS_GYR_PMU_STATUS_NORMAL));
+ ao_bmx160_configured = 1;
+}
+
+struct ao_bmx160_sample ao_bmx160_current;
+
+static void
+ao_bmx160(void)
+{
+ struct ao_bmx160_sample sample;
+
+ /* ao_bmx160_init already grabbed the SPI bus and mutex */
+ _ao_bmx160_setup();
+ ao_bmx160_spi_put();
+ for (;;)
+ {
+ ao_bmx160_spi_get();
+ _ao_bmx160_sample(&sample);
+ ao_bmx160_spi_put();
+ ao_arch_block_interrupts();
+ ao_bmx160_current = sample;
+ AO_DATA_PRESENT(AO_DATA_BMX160);
+ AO_DATA_WAIT();
+ ao_arch_release_interrupts();
+ }
+}
+
+static struct ao_task ao_bmx160_task;
+
+static void
+ao_bmx160_show(void)
+{
+ printf ("Accel: %7d %7d %7d Gyro: %7d %7d %7d Mag: %7d %7d %7d\n",
+ ao_bmx160_current.acc_x,
+ ao_bmx160_current.acc_y,
+ ao_bmx160_current.acc_z,
+ ao_bmx160_current.gyr_x,
+ ao_bmx160_current.gyr_y,
+ ao_bmx160_current.gyr_z,
+ ao_bmx160_current.mag_x,
+ ao_bmx160_current.mag_y,
+ ao_bmx160_current.mag_z);
+}
+
+#if BMX160_TEST
+
+static void
+ao_bmx160_read(void)
+{
+ uint8_t addr;
+ uint8_t val;
+
+ addr = ao_cmd_hex();
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+ ao_bmx160_spi_get();
+ val = _ao_bmx160_reg_read(addr);
+ ao_bmx160_spi_put();
+ printf("Addr %02x val %02x\n", addr, val);
+}
+
+static void
+ao_bmx160_write(void)
+{
+ uint8_t addr;
+ uint8_t val;
+
+ addr = ao_cmd_hex();
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+ val = ao_cmd_hex();
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+ printf("Addr %02x val %02x\n", addr, val);
+ ao_bmx160_spi_get();
+ _ao_bmx160_reg_write(addr, val);
+ ao_bmx160_spi_put();
+}
+
+static void
+ao_bmm150_read(void)
+{
+ uint8_t addr;
+ uint8_t val;
+
+ addr = ao_cmd_hex();
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+ ao_bmx160_spi_get();
+ val = _ao_bmm150_reg_read(addr);
+ ao_bmx160_spi_put();
+ printf("Addr %02x val %02x\n", addr, val);
+}
+
+static void
+ao_bmm150_write(void)
+{
+ uint8_t addr;
+ uint8_t val;
+
+ addr = ao_cmd_hex();
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+ val = ao_cmd_hex();
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+ printf("Addr %02x val %02x\n", addr, val);
+ ao_bmx160_spi_get();
+ _ao_bmm150_reg_write(addr, val);
+ ao_bmx160_spi_put();
+}
+
+#endif /* BMX160_TEST */
+
+static const struct ao_cmds ao_bmx160_cmds[] = {
+ { ao_bmx160_show, "I\0Show BMX160 status" },
+#if BMX160_TEST
+ { ao_bmx160_read, "R <addr>\0Read BMX160 register" },
+ { ao_bmx160_write, "W <addr> <val>\0Write BMX160 register" },
+ { ao_bmm150_read, "M <addr>\0Read BMM150 register" },
+ { ao_bmm150_write, "N <addr> <val>\0Write BMM150 register" },
+#endif
+ { 0, NULL }
+};
+
+void
+ao_bmx160_init(void)
+{
+ ao_add_task(&ao_bmx160_task, ao_bmx160, "bmx160");
+
+ ao_spi_init_cs(AO_BMX160_SPI_CS_PORT, (1 << AO_BMX160_SPI_CS_PIN));
+
+ /* Pretend to be the bmx160 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_bmx160_task;
+ ao_bmx160_spi_get();
+ ao_cur_task = NULL;
+ ao_cmd_register(&ao_bmx160_cmds[0]);
+}
--- /dev/null
+/*
+ * Copyright © 2019 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.
+ */
+
+#ifndef _AO_BMX160_H_
+#define _AO_BMX160_H_
+
+#include <math.h>
+
+struct ao_bmx160_sample {
+ int16_t mag_x;
+ int16_t mag_y;
+ int16_t mag_z;
+ int16_t rhall;
+ int16_t gyr_x;
+ int16_t gyr_y;
+ int16_t gyr_z;
+ int16_t acc_x;
+ int16_t acc_y;
+ int16_t acc_z;
+};
+
+extern struct ao_bmx160_sample ao_bmx160_current;
+
+struct ao_bmx160_offset {
+ int8_t off_acc_x;
+ int8_t off_acc_y;
+ int8_t off_acc_z;
+ int8_t off_gyr_x;
+ int8_t off_gyr_y;
+ int8_t off_gyr_z;
+ uint8_t offset_6;
+};
+
+void
+ao_bmx160_init(void);
+
+#define BMX160_CHIPID 0x00
+#define BMX160_CHIPID_BMX160 0xd8
+#define BMX160_ERR_REG 0x02
+#define BMX160_PMU_STATUS 0x03
+#define BMX160_PMU_STATUS_MAG_IF_PMU_STATUS 0
+#define BMX160_PMU_STATUS_MAG_IF_PMU_STATUS_SUSPEND 0
+#define BMX160_PMU_STATUS_MAG_IF_PMU_STATUS_NORMAL 1
+#define BMX160_PMU_STATUS_MAG_IF_PMU_STATUS_LOW_POWER 2
+#define BMX160_PMU_STATUS_GYR_PMU_STATUS 2
+#define BMX160_PMU_STATUS_GYR_PMU_STATUS_SUSPEND 0
+#define BMX160_PMU_STATUS_GYR_PMU_STATUS_NORMAL 1
+#define BMX160_PMU_STATUS_GYR_PMU_STATUS_FAST_START_UP 3
+#define BMX160_PMU_STATUS_ACC_PMU_STATUS 4
+#define BMX160_PMU_STATUS_ACC_PMU_STATUS_SUSPEND 0
+#define BMX160_PMU_STATUS_ACC_PMU_STATUS_NORMAL 1
+#define BMX160_PMU_STATUS_ACC_PMU_STATUS_LOW_POWER 2
+#define BMX160_DATA_0 0x04
+#define BMX160_MAG_X_0_7 0x04
+#define BMX160_MAG_X_8_15 0x05
+#define BMX160_MAG_Y_0_7 0x06
+#define BMX160_MAG_Y_8_15 0x07
+#define BMX160_MAG_Z_0_7 0x08
+#define BMX160_MAG_Z_8_15 0x09
+#define BMX160_RHALL_0_7 0x0A
+#define BMX160_RHALL_8_15 0x0B
+#define BMX160_GYRO_X_0_7 0x0C
+#define BMX160_GYRO_X_8_15 0x0D
+#define BMX160_GYRO_Y_0_7 0x0E
+#define BMX160_GYRO_Y_8_15 0x0F
+#define BMX160_GYRO_Z_0_7 0x10
+#define BMX160_GYRO_Z_8_15 0x11
+#define BMX160_ACCEL_X_0_7 0x12
+#define BMX160_ACCEL_X_8_15 0x13
+#define BMX160_ACCEL_Y_0_7 0x14
+#define BMX160_ACCEL_Y_8_15 0x15
+#define BMX160_ACCEL_Z_0_7 0x16
+#define BMX160_ACCEL_Z_8_15 0x17
+#define BMX160_SENSORTIME_0_7 0x18
+#define BMX160_SENSORTIME_8_15 0x19
+#define BMX160_SENSORTIME_16_23 0x1A
+#define BMX160_STATUS 0x1B
+#define BMX160_STATUS_GYR_SELF_TEST_OK 1
+#define BMX160_STATUS_MAG_MAN_OP 2
+#define BMX160_STATUS_FOC_RDY 3
+#define BMX160_STATUS_NVM_RDY 4
+#define BMX160_STATUS_DRDY_MAG 5
+#define BMX160_STATUS_DRDY_GYR 6
+#define BMX160_STATUS_DRDY_ACC 7
+#define BMX160_INT_STATUS_0 0x1C-0x1F
+#define BMX160_INT_STATUS_1 0x1D
+#define BMX160_INT_STATUS_2 0x1E
+#define BMX160_INT_STATUS_3 0x1F
+#define BMX160_TEMPERATURE_0_7 0x20
+#define BMX160_TEMPERATURE_8_15 0x21
+#define BMX160_FIFO_LENGTH_0_7 0x22
+#define BMX160_FIFO_LENGTH_8_15 0x23
+#define BMX160_FIFO_DATA 0x24
+#define BMX160_ACC_CONF 0x40
+#define BMX160_ACC_CONF_ACC_ODR 0
+#define BMX160_ACC_CONF_ACC_ODR_25_32 0x1
+#define BMX160_ACC_CONF_ACC_ODR_25_16 0x2
+#define BMX160_ACC_CONF_ACC_ODR_25_8 0x3
+#define BMX160_ACC_CONF_ACC_ODR_25_4 0x4
+#define BMX160_ACC_CONF_ACC_ODR_25_2 0x5
+#define BMX160_ACC_CONF_ACC_ODR_25 0x6
+#define BMX160_ACC_CONF_ACC_ODR_50 0x7
+#define BMX160_ACC_CONF_ACC_ODR_100 0x8
+#define BMX160_ACC_CONF_ACC_ODR_200 0x9
+#define BMX160_ACC_CONF_ACC_ODR_400 0xa
+#define BMX160_ACC_CONF_ACC_ODR_800 0xb
+#define BMX160_ACC_CONF_ACC_ODR_1600 0xc
+#define BMX160_ACC_CONF_ACC_BWP 4
+#define BMX160_ACC_CONF_ACC_BWP_NORMAL 0x2
+#define BMX160_ACC_CONF_ACC_BWP_OSR2 0x1
+#define BMX160_ACC_CONF_ACC_BWP_OSR4 0x0
+#define BMX160_ACC_CONF_ACC_US 7
+#define BMX160_ACC_RANGE 0x41
+#define BMX160_ACC_RANGE_2G 0x3
+#define BMX160_ACC_RANGE_4G 0x5
+#define BMX160_ACC_RANGE_8G 0x8
+#define BMX160_ACC_RANGE_16G 0xc
+#define BMX160_ACC_RANGE_
+#define BMX160_ACC_RANGE_
+#define BMX160_GYR_CONF 0x42
+#define BMX160_GYR_CONF_GYR_ODR 0
+#define BMX160_GYR_CONF_GYR_ODR_25 0x6
+#define BMX160_GYR_CONF_GYR_ODR_50 0x7
+#define BMX160_GYR_CONF_GYR_ODR_100 0x8
+#define BMX160_GYR_CONF_GYR_ODR_200 0x9
+#define BMX160_GYR_CONF_GYR_ODR_400 0xa
+#define BMX160_GYR_CONF_GYR_ODR_800 0xb
+#define BMX160_GYR_CONF_GYR_ODR_1600 0xc
+#define BMX160_GYR_CONF_GYR_ODR_3200 0xd
+#define BMX160_GYR_CONF_GYR_BWP 4
+#define BMX160_GYR_CONF_GYR_BWP_NORMAL 0x2
+#define BMX160_GYR_CONF_GYR_BWP_OSR2 0x1
+#define BMX160_GYR_CONF_GYR_BWP_OSR4 0x0
+#define BMX160_GYR_RANGE 0x43
+#define BMX160_GYR_RANGE_2000 0x0
+#define BMX160_GYR_RANGE_1000 0x1
+#define BMX160_GYR_RANGE_500 0x2
+#define BMX160_GYR_RANGE_250 0x3
+#define BMX160_GYR_RANGE_125 0x4
+#define BMX160_MAG_CONF 0x44
+#define BMX160_MAG_CONF_MAG_ODR 0
+#define BMX160_MAG_CONF_MAG_ODR_25_32 0x1
+#define BMX160_MAG_CONF_MAG_ODR_25_16 0x2
+#define BMX160_MAG_CONF_MAG_ODR_25_8 0x3
+#define BMX160_MAG_CONF_MAG_ODR_25_4 0x4
+#define BMX160_MAG_CONF_MAG_ODR_25_2 0x5
+#define BMX160_MAG_CONF_MAG_ODR_25 0x6
+#define BMX160_MAG_CONF_MAG_ODR_50 0x7
+#define BMX160_MAG_CONF_MAG_ODR_100 0x8
+#define BMX160_MAG_CONF_MAG_ODR_200 0x9
+#define BMX160_MAG_CONF_MAG_ODR_400 0xa
+#define BMX160_MAG_CONF_MAG_ODR_800 0xb
+#define BMX160_FIFO_DOWNS 0x45
+#define BMX160_FIFO_CONFIG_0 0x46
+#define BMX160_FIFO_CONFIG_1 0x47
+#define BMX160_MAG_IF_0 0x4C
+#define BMX160_MAG_IF_0_MAG_RD_BURST 0
+#define BMX160_MAG_IF_0_MAG_OFFSET 2
+#define BMX160_MAG_IF_0_MAG_MANUAL_EN 7
+#define BMX160_MAG_IF_1 0x4D
+#define BMX160_MAG_IF_2 0x4E
+#define BMX160_MAG_IF_3 0x4F
+#define BMX160_INT_EN 0x50-0x52
+#define BMX160_INT_OUT_CTRL 0x53
+#define BMX160_INT_LATCH 0x54
+#define BMX160_INT_MAP 0x55-0x57
+#define BMX160_INT_DATA 0x58-0x59
+#define BMX160_INT_LOWHIGH 0x5A-0x5E
+#define BMX160_INT_MOTION 0x5F-0x62
+#define BMX160_INT_TAP 0x63-0x64
+#define BMX160_INT_ORIENT 0x65-0x66
+#define BMX160_INT_FLAT 0x67-0x68
+#define BMX160_FOC_CONF 0x69
+#define BMX160_CONF 0x6A
+#define BMX160_IF_CONF 0x6B
+#define BMX160_PMU_TRIGGER 0x6C
+#define BMX160_SELF_TEST 0x6D
+#define BMX160_NV_CONF 0x70
+#define BMX160_NV_CONF_SPI_EN 0
+#define BMX160_NV_CONF_I2C_WDT_SEL 1
+#define BMX160_NV_CONF_I2C_WDT_EN 2
+#define BMX160_OFFSET 0x71-0x77
+#define BMX160_STEP_CNT 0x78-0x79
+#define BMX160_STEP_CONF 0x7A-0x7B
+#define BMX160_CMD 0x7E
+#define BMX160_CMD_START_FOC 0x03
+#define BMX160_CMD_ACC_SET_PMU_MODE(n) (0x10 | (n))
+#define BMX160_CMD_GYR_SET_PMU_MODE(n) (0x14 | (n))
+#define BMX160_CMD_MAG_IF_SET_PMU_MODE(n) (0x18 | (n))
+#define BMX160_CMD_PROG_NVM 0xa0
+#define BMX160_CMD_FIFO_FLUSH 0xb0
+#define BMX160_CMD_INT_RESET 0xb1
+#define BMX160_CMD_SOFTRESET 0xb6
+#define BMX160_CMD_STEP_CNT_CLR 0xb2
+
+#define BMM150_CHIP_ID 0x40
+#define BMM150_DATA_X_0_4 0x42
+#define BMM150_DATA_X_5_12 0x43
+#define BMM150_DATA_Y_0_4 0x44
+#define BMM150_DATA_Y_5_12 0x45
+#define BMM150_DATA_Z_0_6 0x46
+#define BMM150_DATA_Z_7_14 0x47
+#define BMM150_RHALL_0_5 0x48
+#define BMM150_RHALL_6_13 0x49
+#define BMM150_INT_STATUS 0x4a
+#define BMM150_POWER_MODE 0x4b
+#define BMM150_POWER_MODE_SOFT_RESET_HI 7
+#define BMM150_POWER_MODE_SPI3EN 2
+#define BMM150_POWER_MODE_SOFT_RESET_LO 1
+#define BMM150_POWER_MODE_POWER_CONTROL 0
+#define BMM150_CONTROL 0x4c
+#define BMM150_CONTROL_ADV_ST_1 7
+#define BMM150_CONTROL_ADV_ST_0 6
+#define BMM150_CONTROL_DATA_RATE 3
+#define BMM150_CONTROL_DATA_RATE_10 0
+#define BMM150_CONTROL_DATA_RATE_2 1
+#define BMM150_CONTROL_DATA_RATE_6 2
+#define BMM150_CONTROL_DATA_RATE_8 3
+#define BMM150_CONTROL_DATA_RATE_15 4
+#define BMM150_CONTROL_DATA_RATE_20 5
+#define BMM150_CONTROL_DATA_RATE_25 6
+#define BMM150_CONTROL_DATA_RATE_30 7
+#define BMM150_CONTROL_OP_MODE 1
+#define BMM150_CONTROL_OP_MODE_NORMAL 0
+#define BMM150_CONTROL_OP_MODE_FORCED 1
+#define BMM150_CONTROL_OP_MODE_SLEEP 3
+#define BMM150_CONTROL_SELF_TEST 0
+#define BMM150_INT_EN 0x4d
+#define BMM150_INT_CONF 0x4e
+#define BMM150_INT_CONF_X_DISABLE 3
+#define BMM150_INT_CONF_Y_DISABLE 4
+#define BMM150_INT_CONF_Z_DISABLE 5
+#define BMM150_LOW_THRESHOLD 0x4f
+#define BMM150_HIGH_THRESHOLD 0x50
+#define BMM150_REPXY 0x51
+#define BMM150_REPXY_VALUE(n) (((n)-1) >> 1)
+#define BMM150_REPZ 0x52
+#define BMM150_REPZ_VALUE(n) ((n) -1)
+
+#define BMX160_GYRO_FULLSCALE ((float) 2000 * M_PI/180.0)
+
+static inline float
+ao_bmx160_gyro(float sensor) {
+ return sensor * ((float) (BMX160_GYRO_FULLSCALE / 32767.0));
+}
+
+#define BMX160_ACCEL_FULLSCALE 16
+
+static inline float
+ao_bmx160_accel(int16_t sensor) {
+ return (float) sensor * ((float) (BMX160_ACCEL_FULLSCALE * GRAVITY / 32767.0));
+}
+
+#endif /* _BMX160_H_ */
* it after a few characters.
*/
-uint8_t
+static uint8_t
ao_btm_get_line(void)
{
uint8_t ao_btm_reply_len = 0;
/*
* Drain the serial port completely
*/
-void
-ao_btm_drain()
+static void
+ao_btm_drain(void)
{
while (ao_btm_get_line())
;
/*
* Set the stdio echo for the bluetooth link
*/
-void
+static void
ao_btm_echo(uint8_t echo)
{
ao_stdios[ao_btm_stdio].echo = echo;
* can't keep up with 57600 baud
*/
-void
+static void
ao_btm_putchar(char c)
{
ao_btm_log_out_char(c);
* Wait for the bluetooth device to return
* status from the previously executed command
*/
-uint8_t
+static uint8_t
ao_btm_wait_reply(void)
{
for (;;) {
}
}
-void
+static void
ao_btm_string(const char *cmd)
{
char c;
ao_btm_putchar(c);
}
-uint8_t
+static uint8_t
ao_btm_cmd(const char *cmd)
{
ao_btm_drain();
return ao_btm_wait_reply();
}
-uint8_t
+static uint8_t
ao_btm_set_name(void)
{
char sn[8];
return ao_btm_wait_reply();
}
-uint8_t
+static uint8_t
ao_btm_try_speed(uint8_t speed)
{
ao_serial_btm_set_speed(speed);
#define BT_CC1111 1
#endif
-void
-ao_btm_check_link()
+static void
+ao_btm_check_link(void)
{
#if BT_CC1111
ao_arch_critical(
* A thread to initialize the bluetooth device and
* hang around to blink the LED when connected
*/
-void
+static void
ao_btm(void)
{
#ifdef AO_BTM_INT_PORT
#include <ao.h>
#include <ao_button.h>
#include <ao_exti.h>
+#include <ao_fast_timer.h>
#if AO_EVENT
#include <ao_event.h>
#define ao_button_queue(b,v) ao_event_put_isr(AO_EVENT_BUTTON, b, v)
}
#define init(b) do { \
- ao_enable_port(port(b)); \
- \
- ao_exti_setup(port(b), bit(b), \
- AO_BUTTON_MODE|AO_EXTI_MODE_FALLING|AO_EXTI_MODE_RISING|AO_EXTI_PRIORITY_MED, \
- ao_button_isr); \
- ao_exti_enable(port(b), bit(b)); \
+ ao_enable_input(port(b), bit(b), AO_BUTTON_MODE); \
_ao_button_init(b); \
} while (0)
#if AO_BUTTON_COUNT > 16
#error too many buttons
#endif
+ ao_fast_timer_init();
+ ao_fast_timer_on(ao_button_isr);
}
uint8_t ao_radio_tone_current;
uint8_t ao_radio_tone_offset;
-int16_t
+static int16_t
ao_radio_tone_fill(uint8_t *buf, int16_t len)
{
int16_t ret = 0;
COMPANION_DESELECT();
}
-void
+static void
ao_companion(void)
{
uint8_t i;
ao_exit();
}
-void
+static void
ao_companion_status(void)
{
uint8_t i;
ao_gps_char = c;
}
-void
+static void
ao_gps_skip_field(void)
{
for (;;) {
}
}
-void
+static void
ao_gps_skip_sep(void)
{
char c = ao_gps_char;
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, &ao_gps_next, sizeof (ao_gps_data));
+ memcpy(&ao_gps_data, &ao_gps_next, sizeof (ao_gps_data));
ao_mutex_put(&ao_gps_mutex);
ao_wakeup(&ao_gps_new);
}
else if (done) {
ao_mutex_get(&ao_gps_mutex);
ao_gps_new |= AO_GPS_NEW_TRACKING;
- ao_xmemcpy(&ao_gps_tracking_data, &ao_gps_tracking_next, sizeof(ao_gps_tracking_data));
+ memcpy(&ao_gps_tracking_data, &ao_gps_tracking_next, sizeof(ao_gps_tracking_data));
ao_mutex_put(&ao_gps_mutex);
ao_wakeup(&ao_gps_new);
}
static uint32_t ao_hmc5883_missed_irq;
-void
+static void
ao_hmc5883_sample(struct ao_hmc5883_sample *sample)
{
uint16_t *d = (uint16_t *) sample;
* visually inspect the system for correct operation
*/
static void
-ao_lco_display_test()
+ao_lco_display_test(void)
{
ao_mutex_get(&ao_lco_display_mutex);
ao_seven_segment_set(AO_LCO_PAD_DIGIT, 8 | 0x10);
}
#if DEBUG
-void
+static void
ao_lco_set_debug(void)
{
uint16_t r = ao_cmd_decimal();
}
#if DEBUG
-void
+static void
ao_lco_set_debug(void)
{
uint16_t r = ao_cmd_decimal();
#include "ao.h"
static const struct {
- struct stm_gpio *port;
+ void *port;
uint16_t pin;
} ao_leds[] = {
#ifdef LED_0_PORT
--- /dev/null
+/*
+ * Copyright © 2019 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.
+ */
+
+#include "ao.h"
+#include "ao_max6691.h"
+#include "ao_exti.h"
+
+#define cat2(a,b) a ## b
+#define cat(a,b) cat2(a,b)
+
+#if AO_MAX6691_CH != 2
+#error ao_max6691 driver currently only works for timer channel 2
+#endif
+
+#define AO_MAX6691_CCR (AO_MAX6691_TIMER->cat(ccr, AO_MAX6691_CH))
+
+/* Two samples per channel, plus time start value and two for Tready pulse */
+
+#define AO_MAX6691_SAMPLES (AO_MAX6691_CHANNELS * 2 + 3)
+
+static uint16_t ao_max6691_raw[AO_MAX6691_SAMPLES];
+
+static inline uint16_t
+ao_max6691_t_high(int channel)
+{
+ return ao_max6691_raw[channel * 2 + 3] - ao_max6691_raw[channel * 2 + 2];
+}
+
+static inline uint16_t
+ao_max6691_t_low(int channel)
+{
+ return ao_max6691_raw[channel * 2 + 4] - ao_max6691_raw[channel * 2 + 3];
+}
+
+struct ao_max6691_sample ao_max6691_current;
+
+static void
+ao_max6691_sample(void)
+{
+ struct stm_tim234 *tim = AO_MAX6691_TIMER;
+
+ tim->sr = 0;
+
+ memset(&ao_max6691_raw, '\0', sizeof (ao_max6691_raw));
+ /* Get the DMA engine ready */
+ ao_dma_set_transfer(AO_MAX6691_DMA,
+ &AO_MAX6691_CCR,
+ &ao_max6691_raw,
+ AO_MAX6691_SAMPLES,
+ (0 << STM_DMA_CCR_MEM2MEM) |
+ (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
+ (STM_DMA_CCR_MSIZE_16 << STM_DMA_CCR_MSIZE) |
+ (STM_DMA_CCR_PSIZE_16 << STM_DMA_CCR_PSIZE) |
+ (1 << STM_DMA_CCR_MINC) |
+ (0 << STM_DMA_CCR_PINC) |
+ (0 << STM_DMA_CCR_CIRC) |
+ (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR));
+ ao_dma_start(AO_MAX6691_DMA);
+
+ /* Prod the max6691 */
+ ao_set_output(AO_MAX6691_GPIO, AO_MAX6691_PIN, 0);
+ int i;
+ for (i = 0; i < 100; i++)
+ ao_arch_nop();
+ ao_set_input(AO_MAX6691_GPIO, AO_MAX6691_PIN);
+ for (i = 0; i < 100; i++)
+ ao_arch_nop();
+
+ /* Reset the timer count */
+ tim->cnt = 0;
+
+ /* Switch the pin to timer input mode */
+ stm_afr_set(AO_MAX6691_GPIO, AO_MAX6691_PIN, STM_AFR_AF1);
+
+ tim->ccer = ((0 << STM_TIM234_CCER_CC1E) |
+ (0 << STM_TIM234_CCER_CC1P) |
+ (0 << STM_TIM234_CCER_CC1NP) |
+ (1 << STM_TIM234_CCER_CC2E) |
+ (1 << STM_TIM234_CCER_CC2P) |
+ (1 << STM_TIM234_CCER_CC2NP) |
+ (0 << STM_TIM234_CCER_CC3E) |
+ (0 << STM_TIM234_CCER_CC3P) |
+ (0 << STM_TIM234_CCER_CC3NP) |
+ (0 << STM_TIM234_CCER_CC4E) |
+ (0 << STM_TIM234_CCER_CC4P) |
+ (0 << STM_TIM234_CCER_CC4NP));
+
+ /* Enable event generation on channel 2 */
+
+ tim->egr = ((0 << STM_TIM234_EGR_TG) |
+ (0 << STM_TIM234_EGR_CC4G) |
+ (0 << STM_TIM234_EGR_CC3G) |
+ (1 << STM_TIM234_EGR_CC2G) |
+ (0 << STM_TIM234_EGR_CC1G) |
+ (0 << STM_TIM234_EGR_UG));
+ /* Start the timer */
+ tim->cr1 |= (1 << STM_TIM234_CR1_CEN);
+
+ ao_arch_block_interrupts();
+ while (!ao_dma_done[AO_MAX6691_DMA])
+ ao_sleep(&ao_dma_done[AO_MAX6691_DMA]);
+ ao_arch_release_interrupts();
+
+ /* Disable event generation */
+ tim->egr = 0;
+
+ /* Disable capture */
+ tim->ccer = 0;
+
+ /* Stop the timer */
+ tim->cr1 &= ~(1 << STM_TIM234_CR1_CEN);
+
+ /* Switch back to GPIO mode */
+ stm_moder_set(AO_MAX6691_GPIO, AO_MAX6691_PIN, STM_MODER_INPUT);
+
+ /* Mark DMA done */
+ ao_dma_done_transfer(AO_MAX6691_DMA);
+
+ for (i = 0; i < AO_MAX6691_CHANNELS; i++) {
+ ao_max6691_current.sensor[i].t_high = ao_max6691_t_high(i);
+ ao_max6691_current.sensor[i].t_low = ao_max6691_t_low(i);
+ }
+}
+
+static void
+ao_max6691(void)
+{
+ for (;;) {
+ ao_max6691_sample();
+ ao_arch_critical(AO_DATA_PRESENT(AO_DATA_MAX6691););
+ }
+}
+
+static struct ao_task ao_max6691_task;
+
+#define R_EXT 1000.0f
+
+static void
+ao_max6691_dump(void)
+{
+ struct ao_max6691_sample ao_max6691;
+
+ ao_max6691 = ao_max6691_current;
+
+ int i;
+ for (i = 0; i < AO_MAX6691_CHANNELS; i++) {
+ uint16_t t_high = ao_max6691.sensor[i].t_high;
+ uint16_t t_low = ao_max6691.sensor[i].t_low;
+
+ /*
+ * From the MAX6691 data sheet
+ *
+ * Thigh Vext Rext
+ * ----- = ---- - 0.0002 = ---------- - 0.0002
+ * Tlow Vref Rext - Rth
+ *
+ * We want to find Rth given Rext and the timing values
+ *
+ * Thigh Rext
+ * ----- + 0.0002 = ----------
+ * Tlow Rext + Rth
+ *
+ * V = (Thigh / Tlow + 0.0002)
+ *
+ * (Rext + Rth) * V = Rext
+ *
+ * Rext * V + Rth * V = Rext
+ *
+ * Rth * V = Rext - Rext * V
+ *
+ * Rth * V = Rext * (1 - V)
+ *
+ * Rth = Rext * (1 - V) / V
+ */
+
+ float V = (float) t_high / (float) t_low + 0.0002f;
+
+ float Rth = R_EXT * (1 - V) / V;
+
+ printf("max6691 channel %d: high %5u low %5u ohms: %7g\n", i, t_high, t_low, Rth);
+ }
+}
+
+static const struct ao_cmds ao_max6691_cmds[] = {
+ { ao_max6691_dump, "q\0Thermistor test" },
+ { 0, NULL },
+};
+
+
+void
+ao_max6691_init(void)
+{
+ ao_cmd_register(&ao_max6691_cmds[0]);
+
+ struct stm_tim234 *tim = AO_MAX6691_TIMER;
+
+ stm_rcc.apb1enr |= (1 << AO_MAX6691_TIMER_ENABLE);
+
+ tim->cr1 = 0;
+ tim->psc = (AO_TIM23467_CLK / 4000000) - 1; /* run the timer at 4MHz */
+ tim->cnt = 0;
+
+ /*
+ * XXX This assumes we're using CH2, which is true on TeleFireOne v2.0
+ */
+ tim->ccmr1 = ((STM_TIM234_CCMR1_IC2F_NONE << STM_TIM234_CCMR1_IC2F) |
+ (STM_TIM234_CCMR1_IC2PSC_NONE << STM_TIM234_CCMR1_IC2PSC) |
+ (STM_TIM234_CCMR1_CC2S_INPUT_TI2 << STM_TIM234_CCMR1_CC2S));
+
+ tim->ccer = 0;
+
+ tim->sr = 0;
+ tim->dier = 0;
+ tim->smcr = 0;
+ tim->cr2 = ((0 << STM_TIM234_CR2_TI1S) |
+ (STM_TIM234_CR2_MMS_RESET<< STM_TIM234_CR2_MMS) |
+ (0 << STM_TIM234_CR2_CCDS));
+
+ tim->dier = ((0 << STM_TIM234_DIER_TDE) |
+ (0 << STM_TIM234_DIER_CC4DE) |
+ (0 << STM_TIM234_DIER_CC3DE) |
+ (1 << STM_TIM234_DIER_CC2DE) |
+ (0 << STM_TIM234_DIER_CC1DE) |
+ (0 << STM_TIM234_DIER_TIE) |
+ (0 << STM_TIM234_DIER_CC4IE) |
+ (0 << STM_TIM234_DIER_CC3IE) |
+ (0 << STM_TIM234_DIER_CC2IE) |
+ (0 << STM_TIM234_DIER_CC1IE) |
+ (0 << STM_TIM234_DIER_UIE));
+
+ tim->egr = 0;
+
+ tim->cr1 = ((STM_TIM234_CR1_CKD_1 << STM_TIM234_CR1_CKD) |
+ (0 << STM_TIM234_CR1_ARPE) |
+ (STM_TIM234_CR1_CMS_EDGE << STM_TIM234_CR1_CMS) |
+ (STM_TIM234_CR1_DIR_UP << STM_TIM234_CR1_DIR) |
+ (0 << STM_TIM234_CR1_OPM) |
+ (0 << STM_TIM234_CR1_URS) |
+ (0 << STM_TIM234_CR1_UDIS) |
+ (0 << STM_TIM234_CR1_CEN));
+
+ stm_ospeedr_set(AO_MAX6691_GPIO, AO_MAX6691_PIN, STM_OSPEEDR_40MHz);
+ ao_enable_input(AO_MAX6691_GPIO, AO_MAX6691_PIN, AO_EXTI_MODE_PULL_UP);
+
+ ao_add_task(&ao_max6691_task, ao_max6691, "max6691");
+}
--- /dev/null
+/*
+ * Copyright © 2019 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.
+ */
+
+#ifndef _AO_MAX6691_H_
+#define _AO_MAX6691_H_
+
+#define AO_MAX6691_CHANNELS 4
+
+struct ao_max6691_sample {
+ struct {
+ uint16_t t_high;
+ uint16_t t_low;
+ } sensor[AO_MAX6691_CHANNELS];
+};
+
+extern struct ao_max6691_sample ao_max6691_current;
+
+void
+ao_max6691_init(void);
+
+#endif /* _AO_MAX6691_H_ */
ao_delay(AO_ST_DELAY);
}
if (tries == AO_ST_TRIES)
- ao_sensor_errors = 1;
+ AO_SENSOR_ERROR(AO_DATA_MMA655X);
ao_mma655x_reg_write(AO_MMA655X_DEVCFG,
DEVCFG_VALUE | (1 << AO_MMA655X_DEVCFG_ENDINIT));
}
if (st_tries == ST_TRIES)
- ao_sensor_errors = 1;
+ AO_SENSOR_ERROR(AO_DATA_MPU6000);
/* Filter to about 100Hz, which also sets the gyro rate to 1000Hz */
_ao_mpu6000_reg_write(MPU6000_CONFIG,
static uint8_t ao_mpu9250_configured;
-extern uint8_t ao_sensor_errors;
-
#ifndef AO_MPU9250_I2C_INDEX
#define AO_MPU9250_SPI 1
#else
}
if (st_tries == ST_TRIES)
- ao_sensor_errors = 1;
+ AO_SENSOR_ERROR(AO_DATA_MPU9250);
/* Set up the mag sensor */
}
if (mag_tries == MAG_TRIES)
- ao_sensor_errors = 1;
+ AO_SENSOR_ERROR(AO_DATA_MPU9250);
/* Select continuous mode 2 (100Hz), 16 bit samples */
r++;
}
- if (!ao_ms5607_prom_valid((uint8_t *) prom))
+
+ if (!ao_ms5607_prom_valid((uint8_t *) prom)) {
+#if HAS_SENSOR_ERRORS
+ AO_SENSOR_ERROR(AO_DATA_MS5607);
+#else
ao_panic(AO_PANIC_SELF_TEST_MS5607);
+#endif
+ }
#if __BYTE_ORDER == __LITTLE_ENDIAN
/* Byte swap */
void
ao_ms5607_info(void)
{
+#if !HAS_MS5607_TASK
+ ao_ms5607_setup();
+#endif
printf ("ms5607 reserved: %u\n", ao_ms5607_prom.reserved);
printf ("ms5607 sens: %u\n", ao_ms5607_prom.sens);
printf ("ms5607 off: %u\n", ao_ms5607_prom.off);
{
struct ao_ms5607_value value;
+#if !HAS_MS5607_TASK
+ ao_ms5607_sample(&ao_ms5607_current);
+#endif
ao_ms5607_convert(&ao_ms5607_current, &value);
printf ("Pressure: %8lu %8ld\n", ao_ms5607_current.pres, value.pres);
printf ("Temperature: %8lu %8ld\n", ao_ms5607_current.temp, value.temp);
#endif
/* If any tx data is pending then copy it into the tx packet */
if (ao_packet_tx_used && ao_tx_packet.len == 0) {
- ao_xmemcpy(&ao_tx_packet.d, tx_data, ao_packet_tx_used);
+ memcpy(&ao_tx_packet.d, tx_data, ao_packet_tx_used);
ao_tx_packet.len = ao_packet_tx_used;
ao_tx_packet.seq++;
ao_packet_tx_used = 0;
/* Accept packets with matching call signs, or any packet if
* our callsign hasn't been configured
*/
- if (ao_xmemcmp(ao_rx_packet.packet.callsign,
+ if (memcmp(ao_rx_packet.packet.callsign,
ao_config.callsign,
AO_MAX_CALLSIGN) != 0 &&
- ao_xmemcmp(ao_config.callsign, "N0CALL", 7) != 0)
+ memcmp(ao_config.callsign, "N0CALL", 7) != 0)
return 0;
/* SYN packets carry no data */
/* Copy data to the receive data buffer and set up the
* offsets
*/
- ao_xmemcpy(rx_data, ao_rx_packet.packet.d, ao_rx_packet.packet.len);
+ memcpy(rx_data, ao_rx_packet.packet.d, ao_rx_packet.packet.len);
ao_packet_rx_used = 0;
ao_packet_rx_len = ao_rx_packet.packet.len;
ao_packet_master_delay = AO_PACKET_MASTER_DELAY_LONG;
}
-void
+static void
ao_packet_master(void)
{
ao_config_get();
ao_packet_master_delay = AO_PACKET_MASTER_DELAY_SHORT;
while (ao_packet_enable) {
uint8_t r;
- ao_xmemcpy(ao_tx_packet.callsign, ao_config.callsign, AO_MAX_CALLSIGN);
+ memcpy(ao_tx_packet.callsign, ao_config.callsign, AO_MAX_CALLSIGN);
ao_packet_send();
if (ao_tx_packet.len)
ao_packet_master_busy();
#include "ao.h"
-void
+static void
ao_packet_slave(void)
{
ao_tx_packet.addr = ao_serial_number;
ao_packet_restart = 1;
while (ao_packet_enable) {
if (ao_packet_recv(0)) {
- ao_xmemcpy(&ao_tx_packet.callsign, &ao_rx_packet.packet.callsign, AO_MAX_CALLSIGN);
+ memcpy(&ao_tx_packet.callsign, &ao_rx_packet.packet.callsign, AO_MAX_CALLSIGN);
#if HAS_FLIGHT
ao_flight_force_idle = true;
#endif
* AO_PAD_R_IGNITER_SENSE_GND Resistors from igniter sense ADC inputs to ground
*/
-int16_t
+static int16_t
ao_pad_decivolt(int16_t adc, int16_t r_plus, int16_t r_minus)
{
int32_t mul = (int32_t) AO_ADC_REFERENCE_DV * (r_plus + r_minus);
while (ao_pad_disabled)
ao_sleep(&ao_pad_disabled);
ret = ao_radio_cmac_recv(&command, sizeof (command), 0);
- PRINTD ("cmac_recv %d %d\n", ret, ao_radio_cmac_rssi);
+ PRINTD ("receive packet status %d rssi %d\n", ret, ao_radio_cmac_rssi);
if (ret != AO_RADIO_CMAC_OK)
continue;
ao_pad_packet_time = ao_time();
PRINTD ("time difference too large %d\n", time_difference);
break;
}
+ if (query.arm_status != AO_PAD_ARM_STATUS_ARMED) {
+ PRINTD ("box not armed locally\n");
+ break;
+ }
PRINTD ("armed\n");
ao_pad_armed = command.channels;
ao_pad_arm_time = ao_time();
}
}
-void
+static void
ao_pad_test(void)
{
uint8_t c;
}
}
-void
+static void
ao_pad_manual(void)
{
uint8_t ignite;
static struct ao_task ao_pad_monitor_task;
#if DEBUG
-void
+static void
ao_pad_set_debug(void)
{
uint16_t r = ao_cmd_decimal();
AO_RADIO_SPI_REPLY_HEADER_LEN + size,
AO_RADIO_SPI_BUS);
ao_radio_master_stop();
- ao_xmemcpy(d, ao_radio_spi_reply.payload, size);
+ memcpy(d, ao_radio_spi_reply.payload, size);
PRINTD ("fetched %d\n", size);
}
ao_radio_send(const void *d, uint8_t size)
{
ao_radio_get(AO_RADIO_SPI_SEND, size);
- ao_xmemcpy(&ao_radio_spi_request.payload, d, size);
+ memcpy(&ao_radio_spi_request.payload, d, size);
ao_radio_master_send();
ao_radio_put();
}
*/
PRINTD ("set key\n");
ao_radio_get(AO_RADIO_SPI_CMAC_KEY, AO_AES_LEN);
- ao_xmemcpy(&ao_radio_spi_request.payload, &ao_config.aes_key, AO_AES_LEN);
+ memcpy(&ao_radio_spi_request.payload, &ao_config.aes_key, AO_AES_LEN);
ao_radio_master_send();
ao_radio_put();
PRINTD ("key set\n");
PRINTD ("sending packet\n");
ao_radio_get(AO_RADIO_SPI_CMAC_SEND, len);
- ao_xmemcpy(&ao_radio_spi_request.payload, packet, len);
+ memcpy(&ao_radio_spi_request.payload, packet, len);
ao_radio_master_send();
ao_radio_put();
PRINTD ("packet sent\n");
break;
case AO_RADIO_SPI_CMAC_KEY:
- ao_xmemcpy(&ao_config.aes_key, ao_radio_spi_request.payload, AO_AES_LEN);
+ memcpy(&ao_config.aes_key, ao_radio_spi_request.payload, AO_AES_LEN);
break;
case AO_RADIO_SPI_TEST_ON:
* disabled due to a firmware bug. So, this code finds those in the
* input and strips them out.
*/
-int
+static int
_ao_wrap_rn_pollchar(void)
{
int c = AO_READ_AGAIN;
/*
* Set the stdio echo for the bluetooth link
*/
-void
+static void
ao_rn_echo(uint8_t echo)
{
ao_stdios[ao_rn_stdio].echo = echo;
PRODUCT_DEF=-DEASYMEGA
IDPRODUCT=0x0028
-CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF) -Os -g
+CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF)
PROGNAME=easymega-v1.0
PROG=$(PROGNAME)-$(VERSION).elf
all: $(PROG) $(HEX)
$(PROG): Makefile $(OBJ) altos.ld
- $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
-
-../altitude-pa.h: make-altitude-pa
- nickle $< > $@
+ $(call quiet,CC) $(LDFLAGS) -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:
--- /dev/null
+ao_product.h
+easymega-*.elf
PRODUCT_DEF=-DEASYMEGA
IDPRODUCT=0x0028
-CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF) -Os -g
+CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF)
PROGNAME=easymega-v2.0
PROG=$(PROGNAME)-$(VERSION).elf
all: $(PROG) $(HEX)
$(PROG): Makefile $(OBJ) altos.ld
- $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
-
-../altitude-pa.h: make-altitude-pa
- nickle $< > $@
+ $(call quiet,CC) $(LDFLAGS) -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:
--- /dev/null
+ao_product.h
+easymega-*.elf
--- /dev/null
+#
+# AltOS build
+#
+#
+
+include ../stm/Makefile.defs
+
+INC = \
+ ao.h \
+ ao_arch.h \
+ ao_arch_funcs.h \
+ ao_boot.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_bmx160.h \
+ ao_adxl375.h \
+ ao_profile.h \
+ ao_task.h \
+ ao_whiten.h \
+ ao_sample_profile.h \
+ ao_quaternion.h \
+ ao_mpu.h \
+ stm32l.h \
+ Makefile
+
+#
+# Common AltOS sources
+#
+
+#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_stm.c \
+ ao_stdio.c \
+ ao_panic.c \
+ ao_timer.c \
+ ao_mutex.c \
+ ao_ignite.c \
+ ao_freq.c \
+ ao_dma_stm.c \
+ ao_spi_stm.c \
+ ao_data.c \
+ ao_ms5607.c \
+ ao_bmx160.c \
+ ao_adxl375.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_convert_pa.c \
+ ao_convert_volt.c \
+ ao_log.c \
+ ao_log_mega.c \
+ ao_sample.c \
+ ao_kalman.c \
+ ao_flight.c \
+ ao_companion.c \
+ ao_pyro.c \
+ $(PROFILE) \
+ $(SAMPLE_PROFILE) \
+ $(STACK_GUARD)
+
+PRODUCT=EasyMega-v3.0
+PRODUCT_DEF=-DEASYMEGA
+IDPRODUCT=0x0028
+
+CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF)
+
+PROGNAME=easymega-v3.0
+PROG=$(PROGNAME)-$(VERSION).elf
+HEX=$(PROGNAME)-$(VERSION).ihx
+
+SRC=$(ALTOS_SRC) ao_easymega.c
+OBJ=$(SRC:.c=.o)
+
+all: $(PROG) $(HEX)
+
+$(PROG): Makefile $(OBJ) altos.ld
+ $(call quiet,CC) $(LDFLAGS) -o $(PROG) $(OBJ) $(LIBS)
+
+$(OBJ): $(INC)
+
+distclean: clean
+
+clean:
+ rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx
+ rm -f ao_product.h
+
+install:
+
+uninstall:
--- /dev/null
+/*
+ * Copyright © 2014 Bdale Garbee <bdale@gag.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 <ao.h>
+#include <ao_ms5607.h>
+#include <ao_bmx160.h>
+#include <ao_adxl375.h>
+#include <ao_log.h>
+#include <ao_exti.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_led_init();
+ ao_led_on(LEDS_AVAILABLE);
+ ao_timer_init();
+
+ ao_i2c_init();
+ ao_spi_init();
+ ao_dma_init();
+ ao_exti_init();
+
+ ao_adc_init();
+ ao_beep_init();
+ ao_cmd_init();
+
+ ao_ms5607_init();
+ ao_bmx160_init();
+ ao_adxl375_init();
+
+ ao_eeprom_init();
+ ao_storage_init();
+
+ ao_flight_init();
+ ao_log_init();
+ ao_report_init();
+
+ ao_usb_init();
+ 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_led_off(LEDS_AVAILABLE);
+ ao_start_scheduler();
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright © 2014 Bdale Garbee <bdale@gag.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.
+ */
+
+#ifndef _AO_PINS_H_
+#define _AO_PINS_H_
+
+#define HAS_TASK_QUEUE 1
+
+/* 16MHz High speed external crystal */
+#define AO_HSE 16000000
+
+/* PLLVCO = 96MHz (so that USB will work) */
+#define AO_PLLMUL 6
+#define AO_RCC_CFGR_PLLMUL (STM_RCC_CFGR_PLLMUL_6)
+
+/* 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 0
+
+#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 0
+#define USE_SERIAL_3_STDIN 0
+#define SERIAL_3_PB10_PB11 0
+#define SERIAL_3_PC10_PC11 0
+#define SERIAL_3_PD8_PD9 0
+
+#define ao_gps_getchar ao_serial1_getchar
+#define ao_gps_putchar ao_serial1_putchar
+#define ao_gps_set_speed ao_serial1_set_speed
+#define ao_gps_fifo (ao_stm_usart1.rx_fifo)
+
+#define AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX (1024 * 1024)
+#define AO_CONFIG_MAX_SIZE 1024
+#define LOG_ERASE_MARK 0x55
+#define LOG_MAX_ERASE 128
+#define AO_LOG_FORMAT AO_LOG_FORMAT_EASYMEGA_2
+
+#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_TIMER 2
+#define BEEPER_CHANNEL 3
+#define BEEPER_PORT (&stm_gpioa)
+#define BEEPER_PIN 2
+#define HAS_BATTERY_REPORT 1
+#define HAS_RADIO 0
+#define HAS_TELEMETRY 0
+#define HAS_APRS 0
+#define HAS_COMPANION 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, IMU, Companion */
+#define SPI_2_PD1_PD3_PD4 0
+#define SPI_2_OSPEEDR STM_OSPEEDR_10MHz
+
+#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 0
+#define PACKET_HAS_MASTER 0
+
+#define LOW_LEVEL_DEBUG 0
+
+#define LED_PORT_ENABLE STM_RCC_AHBENR_GPIOAEN
+#define LED_PORT (&stm_gpioa)
+#define LED_PIN_RED 9
+#define LED_PIN_GREEN 10
+#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 0
+#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_gpioa)
+#define AO_PYRO_PIN_0 15
+
+/* Pyro B */
+#define AO_PYRO_PORT_1 (&stm_gpioc)
+#define AO_PYRO_PIN_1 10
+
+/* Pyro C */
+#define AO_PYRO_PORT_2 (&stm_gpiob)
+#define AO_PYRO_PIN_2 11
+
+/* Pyro D */
+#define AO_PYRO_PORT_3 (&stm_gpiob)
+#define AO_PYRO_PIN_3 10
+
+/* Drogue */
+#define AO_IGNITER_DROGUE_PORT (&stm_gpioa)
+#define AO_IGNITER_DROGUE_PIN 0
+
+/* Main */
+#define AO_IGNITER_MAIN_PORT (&stm_gpioa)
+#define AO_IGNITER_MAIN_PIN 1
+
+/* Number of general purpose pyro channels available */
+#define AO_PYRO_NUM 4
+
+/*
+ * 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 14
+#define AO_ADC_SENSE_A_PORT (&stm_gpioc)
+#define AO_ADC_SENSE_A_PIN 4
+
+#define AO_ADC_SENSE_B 15
+#define AO_ADC_SENSE_B_PORT (&stm_gpioc)
+#define AO_ADC_SENSE_B_PIN 5
+
+#define AO_ADC_SENSE_C 13
+#define AO_ADC_SENSE_C_PORT (&stm_gpioc)
+#define AO_ADC_SENSE_C_PIN 3
+
+#define AO_ADC_SENSE_D 12
+#define AO_ADC_SENSE_D_PORT (&stm_gpioc)
+#define AO_ADC_SENSE_D_PIN 2
+
+#define AO_ADC_SENSE_DROGUE 11
+#define AO_ADC_SENSE_DROGUE_PORT (&stm_gpioc)
+#define AO_ADC_SENSE_DROGUE_PIN 1
+
+#define AO_ADC_SENSE_MAIN 10
+#define AO_ADC_SENSE_MAIN_PORT (&stm_gpioc)
+#define AO_ADC_SENSE_MAIN_PIN 0
+
+#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
+
+/*
+ * Voltage divider on ADC battery sampler
+ */
+#define AO_BATTERY_DIV_PLUS 56 /* 5.6k */
+#define AO_BATTERY_DIV_MINUS 100 /* 10k */
+
+/*
+ * Voltage divider on ADC igniter samplers
+ */
+#define AO_IGNITE_DIV_PLUS 100 /* 100k */
+#define AO_IGNITE_DIV_MINUS 27 /* 27k */
+
+/*
+ * ADC reference in decivolts
+ */
+#define AO_ADC_REFERENCE_DV 33
+
+/*
+ * Pressure sensor settings
+ */
+#define HAS_MS5607 1
+#define HAS_MS5611 0
+#define AO_MS5607_PRIVATE_PINS 1
+#define AO_MS5607_CS_PORT (&stm_gpioa)
+#define AO_MS5607_CS_PIN 3
+#define AO_MS5607_CS_MASK (1 << AO_MS5607_CS_PIN)
+#define AO_MS5607_MISO_PORT (&stm_gpioa)
+#define AO_MS5607_MISO_PIN 6
+#define AO_MS5607_MISO_MASK (1 << AO_MS5607_MISO_PIN)
+#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_PIN 12
+#define AO_M25_SPI_CS_MASK (1 << AO_M25_SPI_CS_PIN)
+#define AO_M25_SPI_BUS AO_SPI_2_PB13_PB14_PB15
+
+/*
+ * bmx160
+ */
+
+#define HAS_BMX160 1
+#define AO_BMX160_INT_PORT (&stm_gpioc)
+#define AO_BMX160_INT_PIN 15
+#define AO_BMX160_SPI_BUS (AO_SPI_2_PB13_PB14_PB15 | AO_SPI_MODE_0)
+#define AO_BMX160_SPI_CS_PORT (&stm_gpioc)
+#define AO_BMX160_SPI_CS_PIN 13
+#define HAS_IMU 1
+
+#define ao_data_along(packet) ((packet)->bmx160.acc_x)
+#define ao_data_across(packet) (-(packet)->bmx160.acc_y)
+#define ao_data_through(packet) ((packet)->bmx160.acc_z)
+
+#define ao_data_roll(packet) ((packet)->bmx160.gyr_x)
+#define ao_data_pitch(packet) (-(packet)->bmx160.gyr_y)
+#define ao_data_yaw(packet) ((packet)->bmx160.gyr_z)
+
+#define ao_data_mag_along(packet) ((packet)->bmx160.mag_x)
+#define ao_data_mag_across(packet) (-(packet)->bmx160.mag_y)
+#define ao_data_mag_through(packet) ((packet)->bmx160.mag_z)
+
+/* ADXL375 */
+
+#define HAS_ADXL375 1
+#define AO_ADXL375_SPI_INDEX (AO_SPI_1_PB3_PB4_PB5 | AO_SPI_MODE_3)
+#define AO_ADXL375_CS_PORT (&stm_gpioc)
+#define AO_ADXL375_CS_PIN 12
+#define AO_ADXL375_SPI_SPEED AO_SPI_SPEED_4MHz
+
+#define AO_ADXL375_INT1_PORT (&stm_gpiob)
+#define AO_ADXL375_INT1_PIN 8
+
+#define AO_ADXL375_INT2_PORT (&stm_gpiob)
+#define AO_ADXL375_INT2_PIN 9
+
+#define AO_ADXL375_AXIS x
+#define AO_ADXL375_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 0
+#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
+#
+# AltOS flash loader build
+#
+#
+
+TOPDIR=../..
+HARDWARE=easymega-v3.0
+include $(TOPDIR)/stm/Makefile-flash.defs
--- /dev/null
+/*
+ * Copyright © 2018 Bdale Garbee <bdale@gag.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.
+ */
+
+#ifndef _AO_PINS_H_
+#define _AO_PINS_H_
+
+/* External crystal at 16MHz */
+#define AO_HSE 16000000
+
+#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_ */
PRODUCT_DEF=-DEASYMINI_V_1_0
IDPRODUCT=0x0026
-CFLAGS = $(PRODUCT_DEF) $(LPC_CFLAGS) -g -Os
+CFLAGS = $(PRODUCT_DEF) $(LPC_CFLAGS)
PROGNAME=easymini-v1.0
PROG=$(PROGNAME)-$(VERSION).elf
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) > $@
+ $(call quiet,CC) $(LDFLAGS) -o $(PROG) $(OBJ) $(LIBS)
$(OBJ): $(INC)
#include <ao.h>
#include <ao_exti.h>
-void
+int
main(void)
{
ao_clock_init();
PRODUCT_DEF=-DEASYMINI_V_2_0
IDPRODUCT=0x0026
-CFLAGS = $(PRODUCT_DEF) $(STMF0_CFLAGS) -g -Os
+CFLAGS = $(PRODUCT_DEF) $(STMF0_CFLAGS)
PROGNAME=easymini-v2.0
PROG=$(PROGNAME)-$(VERSION).elf
all: $(PROG) $(HEX)
$(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) > $@
+ $(call quiet,CC) $(LDFLAGS) -o $(PROG) $(OBJ) $(LIBS)
$(OBJ): $(INC)
#include <ao.h>
#include <ao_exti.h>
-void
+int
main(void)
{
ao_clock_init();
PRODUCT_DEF=-DFOX
IDPRODUCT=0x0024
-CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF) -Os -g
+CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF)
PROGNAME=fox1ihu-v0.1
PROG=$(PROGNAME)-$(VERSION).elf
#define AO_PANIC_SELF_TEST_HMC5883 0x40 | 2 /* Self test failure */
#define AO_PANIC_SELF_TEST_MPU6000 0x40 | 3 /* Self test failure */
#define AO_PANIC_SELF_TEST_MPU9250 0x40 | 3 /* Self test failure */
+#define AO_PANIC_SELF_TEST_BMX160 0x40 | 3 /* Self test failure */
#define AO_PANIC_SELF_TEST_MS5607 0x40 | 4 /* Self test failure */
+#define AO_PANIC_SELF_TEST_ADS124S0X 0x40 | 5 /* Self test failure */
/* Stop the operating system, beeping and blinking the reason */
void
*/
#ifndef AO_TICK_TYPE
-#define AO_TICK_TYPE uint16_t
-#define AO_TICK_SIGNED int16_t
+#define AO_TICK_TYPE uint32_t
+#define AO_TICK_SIGNED int32_t
#endif
extern volatile AO_TICK_TYPE ao_tick_count;
AO_TICK_TYPE
ao_time(void);
+/* Returns the current time in ns */
+uint64_t
+ao_time_ns(void);
+
/* Suspend the current task until ticks time has passed */
void
ao_delay(uint16_t ticks);
#define AO_TELEPYRO_NUM_ADC 9
-#ifndef ao_xmemcpy
-#define ao_xmemcpy(d,s,c) memcpy(d,s,c)
-#define ao_xmemset(d,v,c) memset(d,v,c)
-#define ao_xmemcmp(d,s,c) memcmp(d,s,c)
-#endif
-
/*
* ao_terraui.c
*/
uint8_t ao_force_freq;
#endif
+#ifndef HAS_CONFIG_SAVE
+#define HAS_CONFIG_SAVE HAS_EEPROM
+#endif
+
#ifndef AO_CONFIG_DEFAULT_APRS_INTERVAL
#define AO_CONFIG_DEFAULT_APRS_INTERVAL 0
#endif
#define AO_CONFIG_DEFAULT_IGNITE_MODE AO_IGNITE_MODE_DUAL
#define AO_CONFIG_DEFAULT_PAD_ORIENTATION AO_PAD_ORIENTATION_ANTENNA_UP
#define AO_CONFIG_DEFAULT_PYRO_TIME AO_MS_TO_TICKS(50)
-#if HAS_EEPROM
+#if HAS_CONFIG_SAVE
#ifndef USE_INTERNAL_FLASH
#error Please define USE_INTERNAL_FLASH
#endif
#define AO_CONFIG_DEFAULT_APRS_SSID (ao_serial_number % 10)
#define AO_CONFIG_DEFAULT_RADIO_RATE AO_RADIO_RATE_38400
-#if HAS_EEPROM
+#if HAS_CONFIG_SAVE
static void
_ao_config_put(void)
{
if (ao_config_loaded)
return;
-#if HAS_EEPROM
+#if HAS_CONFIG_SAVE
/* Yes, I know ao_storage_read calls ao_storage_setup,
* but ao_storage_setup *also* sets ao_storage_config, which we
* need before calling ao_storage_read here
/* Version 0 stuff */
ao_config.main_deploy = AO_CONFIG_DEFAULT_MAIN_DEPLOY;
- ao_xmemset(&ao_config.callsign, '\0', sizeof (ao_config.callsign));
- ao_xmemcpy(&ao_config.callsign, AO_CONFIG_DEFAULT_CALLSIGN,
+ memset(&ao_config.callsign, '\0', sizeof (ao_config.callsign));
+ memcpy(&ao_config.callsign, AO_CONFIG_DEFAULT_CALLSIGN,
sizeof(AO_CONFIG_DEFAULT_CALLSIGN) - 1);
ao_config._legacy_radio_channel = 0;
}
if (minor < 8)
ao_config.radio_enable = AO_RADIO_ENABLE_CORE;
if (minor < 9)
- ao_xmemset(&ao_config.aes_key, '\0', AO_AES_LEN);
+ memset(&ao_config.aes_key, '\0', AO_AES_LEN);
if (minor < 10)
ao_config.frequency = 434550 + ao_config._legacy_radio_channel * 100;
if (minor < 11)
#if HAS_RADIO_RATE
ao_config.radio_rate = AO_CONFIG_DEFAULT_RADIO_RATE;
#endif
- ao_xmemcpy(&ao_config.callsign, AO_CONFIG_DEFAULT_CALLSIGN,
+ memcpy(&ao_config.callsign, AO_CONFIG_DEFAULT_CALLSIGN,
sizeof(AO_CONFIG_DEFAULT_CALLSIGN) - 1);
}
#endif
ao_mutex_put(&ao_config_mutex);
}
-void
+#if HAS_RADIO
+
+static void
ao_config_callsign_show(void)
{
printf ("Callsign: \"%s\"\n", ao_config.callsign);
}
-void
+static void
ao_config_callsign_set(void)
{
uint8_t c;
static char callsign[AO_MAX_CALLSIGN + 1];
- ao_xmemset(callsign, '\0', sizeof callsign);
+ memset(callsign, '\0', sizeof callsign);
ao_cmd_white();
c = 0;
while (ao_cmd_lex_c != '\n') {
if (ao_cmd_status != ao_cmd_success)
return;
_ao_config_edit_start();
- ao_xmemcpy(&ao_config.callsign, &callsign,
+ memcpy(&ao_config.callsign, &callsign,
AO_MAX_CALLSIGN + 1);
_ao_config_edit_finish();
}
-#if HAS_RADIO
-
-void
+static void
ao_config_frequency_show(void)
{
printf("Frequency: %ld\n",
ao_config.frequency);
}
-void
+static void
ao_config_frequency_set(void)
{
uint32_t r = ao_cmd_decimal();
#if HAS_FLIGHT
-void
+static void
ao_config_main_deploy_show(void)
{
printf("Main deploy: %d meters\n",
ao_config.main_deploy);
}
-void
+static void
ao_config_main_deploy_set(void)
{
uint32_t r = ao_cmd_decimal();
}
#if HAS_ACCEL
-void
+static void
ao_config_accel_calibrate_show(void)
{
printf("Accel cal +1g: %d -1g: %d\n",
return accel_total >> ACCEL_CALIBRATE_SHIFT;
}
-void
+static void
ao_config_accel_calibrate_set(void)
{
int16_t up, down;
}
#endif /* HAS_ACCEL */
-void
+static void
ao_config_apogee_delay_show(void)
{
printf("Apogee delay: %d seconds\n",
ao_config.apogee_delay);
}
-void
+static void
ao_config_apogee_delay_set(void)
{
uint32_t r = ao_cmd_decimal();
_ao_config_edit_finish();
}
-void
+static void
ao_config_apogee_lockout_show(void)
{
printf ("Apogee lockout: %d seconds\n",
ao_config.apogee_lockout);
}
-void
+static void
ao_config_apogee_lockout_set(void)
{
uint16_t r = ao_cmd_decimal();
#endif /* HAS_FLIGHT */
#if HAS_RADIO
-void
+static void
ao_config_radio_cal_show(void)
{
printf("Radio cal: %ld\n", ao_config.radio_cal);
}
-void
+static void
ao_config_radio_cal_set(void)
{
uint32_t r = ao_cmd_decimal();
#error Please define HAS_TELEMETRY
#endif
-void
+static void
ao_config_radio_rate_show(void)
{
printf("Telemetry rate: %d\n", ao_config.radio_rate);
}
-void
+static void
ao_config_radio_rate_set(void)
{
uint16_t r = ao_cmd_decimal();
#if HAS_LOG
-void
+static void
ao_config_log_show(void)
{
printf("Max flight log: %d kB\n", (int16_t) (ao_config.flight_log_max >> 10));
#endif
}
-#if FLIGHT_LOG_APPEND
+#if FLIGHT_LOG_APPEND && HAS_CONFIG_SAVE
void
ao_config_log_fix_append(void)
{
}
#endif
-void
+static void
ao_config_log_set(void)
{
#if FLIGHT_LOG_APPEND
#endif /* HAS_LOG */
#if HAS_IGNITE
-void
+static void
ao_config_ignite_mode_show(void)
{
printf("Ignite mode: %d\n", ao_config.ignite_mode);
}
-void
+static void
ao_config_ignite_mode_set(void)
{
uint16_t r = ao_cmd_decimal();
#endif
#if HAS_ACCEL
-void
+static void
ao_config_pad_orientation_show(void)
{
printf("Pad orientation: %d\n", ao_config.pad_orientation);
}
-#ifndef AO_ACCEL_INVERT
-#define AO_ACCEL_INVERT 0x7fff
-#endif
-
-void
+static void
ao_config_pad_orientation_set(void)
{
uint16_t r = ao_cmd_decimal() & 1;
return;
_ao_config_edit_start();
if (ao_config.pad_orientation != r) {
- int16_t t;
+ accel_t t;
t = ao_config.accel_plus_g;
- ao_config.accel_plus_g = AO_ACCEL_INVERT - ao_config.accel_minus_g;
- ao_config.accel_minus_g = AO_ACCEL_INVERT - t;
+ ao_config.accel_plus_g = ao_data_accel_invert(ao_config.accel_minus_g);
+ ao_config.accel_minus_g = ao_data_accel_invert(t);
}
ao_config.pad_orientation = r;
_ao_config_edit_finish();
#endif
#if HAS_RADIO
-void
+static void
ao_config_radio_enable_show(void)
{
printf("Radio enable: %d\n", ao_config.radio_enable);
}
-void
+static void
ao_config_radio_enable_set(void)
{
uint16_t r = ao_cmd_decimal();
uint8_t ao_config_aes_seq = 1;
-void
+static void
ao_config_key_show(void)
{
uint8_t i;
printf("\n");
}
-void
+static void
ao_config_key_set(void)
{
uint8_t i;
#if HAS_APRS
-void
+static void
ao_config_aprs_show(void)
{
printf ("APRS interval: %d\n", ao_config.aprs_interval);
}
-void
+static void
ao_config_aprs_set(void)
{
uint16_t r = ao_cmd_decimal();
#endif
#if HAS_BEEP_CONFIG
-void
+static void
ao_config_beep_show(void)
{
printf ("Beeper setting: %d\n", ao_config.mid_beep);
}
-void
+static void
ao_config_beep_set(void)
{
uint16_t r = ao_cmd_decimal();
#endif
#if HAS_TRACKER
-void
+static void
ao_config_tracker_show(void)
{
printf ("Tracker setting: %d %d\n",
ao_config.tracker_interval);
}
-void
+static void
ao_config_tracker_set(void)
{
uint16_t m, i;
#endif /* HAS_TRACKER */
#if AO_PYRO_NUM
-void
+static void
ao_config_pyro_time_show(void)
{
printf ("Pyro time: %d\n", ao_config.pyro_time);
}
-void
+static void
ao_config_pyro_time_set(void)
{
uint16_t r = ao_cmd_decimal();
#endif
#if HAS_APRS
-void
+static void
ao_config_aprs_ssid_show(void)
{
printf ("APRS SSID: %d\n",
ao_config.aprs_ssid);
}
-void
+static void
ao_config_aprs_ssid_set(void)
{
uint16_t r = ao_cmd_decimal();
_ao_config_edit_finish();
}
-void
+static void
ao_config_aprs_format_set(void)
{
uint16_t r = ao_cmd_decimal();
_ao_config_edit_finish();
}
-void
+static void
ao_config_aprs_format_show(void)
{
printf ("APRS format: %d\n", ao_config.aprs_format);
#endif /* HAS_APRS */
#if HAS_FIXED_PAD_BOX
-void
+static void
ao_config_pad_box_show(void)
{
printf ("Pad box: %d\n", ao_config.pad_box);
}
-void
+static void
ao_config_pad_box_set(void)
{
uint16_t r = ao_cmd_decimal();
_ao_config_edit_finish();
}
-void
+static void
ao_config_pad_idle_show(void)
{
printf ("Idle timeout: %d\n", ao_config.pad_idle);
}
-void
+static void
ao_config_pad_idle_set(void)
{
uint16_t r = ao_cmd_decimal();
static void
ao_config_show(void);
-#if HAS_EEPROM
+#if HAS_CONFIG_SAVE
static void
ao_config_save(void);
#endif
#endif
{ "s\0Show",
ao_config_show, 0 },
-#if HAS_EEPROM
+#if HAS_CONFIG_SAVE
{ "w\0Write to eeprom",
ao_config_save, 0 },
#endif
{ 0, 0, 0 }
};
-void
+static void
ao_config_set(void)
{
char c;
#endif
}
-#if HAS_EEPROM
+#if HAS_CONFIG_SAVE
static void
ao_config_save(void)
{
#define AO_DATA_ADXL375 0
#endif
+#if HAS_MAX6691
+#include <ao_max6691.h>
+#define AO_DATA_MAX6691 (1 << 4)
+#else
+#define AO_DATA_MAX6691 0
+#endif
+
+#if HAS_BMX160
+#include <ao_bmx160.h>
+#define AO_DATA_BMX160 (1 << 2)
+#else
+#define AO_DATA_BMX160 0
+#endif
+
+#ifndef HAS_SENSOR_ERRORS
+#if HAS_IMU || HAS_MMA655X || HAS_MS5607 || HAS_MS5611
+#define HAS_SENSOR_ERRORS 1
+#endif
+#endif
+
+#if HAS_SENSOR_ERRORS
+extern uint8_t ao_sensor_errors;
+#endif
+
#ifdef AO_DATA_RING
-#define AO_DATA_ALL (AO_DATA_ADC|AO_DATA_MS5607|AO_DATA_MPU6000|AO_DATA_HMC5883|AO_DATA_MMA655X|AO_DATA_MPU9250|AO_DATA_ADXL375)
+#define AO_DATA_ALL (AO_DATA_ADC|AO_DATA_MS5607|AO_DATA_MPU6000|AO_DATA_HMC5883|AO_DATA_MMA655X|AO_DATA_MPU9250|AO_DATA_ADXL375|AO_DATA_BMX160)
struct ao_data {
uint16_t tick;
#if HAS_ADXL375
struct ao_adxl375_sample adxl375;
#endif
+#if HAS_MAX6691
+ struct ao_max6691_sample max6691;
+#endif
+#if HAS_ADS131A0X
+ struct ao_ads131a0x_sample ads131a0x;
+#endif
+#if HAS_BMX160
+ struct ao_bmx160_sample bmx160;
+#endif
};
#define ao_data_ring_next(n) (((n) + 1) & (AO_DATA_RING - 1))
*/
#define AO_DATA_PRESENT(bit) (ao_data_present |= (bit))
+/*
+ * Mark sensor failed, and unblock the sample collection code by
+ * marking the data as present
+ */
+#define AO_SENSOR_ERROR(bit) (ao_data_present |= (ao_sensor_errors |= (bit)))
+
/*
* Wait until it is time to write a sensor sample; this is
* signaled by the timer tick
#define HAS_ACCEL 1
-#define AO_ACCEL_INVERT 0
-
typedef int16_t accel_t;
/* MPU6000 is hooked up so that positive y is positive acceleration */
#endif
+#if !HAS_GYRO && HAS_BMX160
+
+#define HAS_GYRO 1
+
+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) */
+/* Z axis is aligned perpendicular to the board (through) */
+
+static inline float ao_convert_gyro(float sensor)
+{
+ return ao_bmx160_gyro(sensor);
+}
+
+static inline float ao_convert_accel(int16_t sensor)
+{
+ return ao_bmx160_accel(sensor);
+}
+
+#endif
+
#if !HAS_MAG && HAS_HMC5883
#define HAS_MAG 1
#endif
#if HAS_ADXL375
ao_data_ring[head].adxl375 = ao_adxl375_current;
+#endif
+#if HAS_MAX6691
+ ao_data_ring[head].max6691 = ao_max6691_current;
+#endif
+#if HAS_ADS131A0X
+ ao_data_ring[head].ads131a0x = ao_ads131a0x_current;
#endif
ao_data_ring[head].tick = ao_tick_count;
ao_data_head = ao_data_ring_next(head);
uint8_t
ao_ee_read_config(uint8_t *buf, uint16_t len)
{
- ao_xmemset(buf, '\0', len);
+ memset(buf, '\0', len);
return 1;
}
extern uint16_t ao_launch_tick;
extern uint16_t ao_motor_number;
-#if HAS_IMU || HAS_MMA655X
-#define HAS_SENSOR_ERRORS 1
-#endif
-
-#if HAS_SENSOR_ERRORS
-extern uint8_t ao_sensor_errors;
-#endif
-
extern uint16_t ao_launch_time;
extern uint8_t ao_flight_force_idle;
/*
* The provided 'calibration' value is
* that needed to tune the radio to precisely 434550kHz.
- * Use that to 'walk' to the target frequency by following
- * a 'bresenham' line from 434550kHz to the target
- * frequency, and updating the radio setting along the way
+ * The relation between value and freq is linear, so
+ * to get the value for an arbitrary frequency:
+ *
+ * target_value target_freq
+ * ------------ = ------------
+ * cal_value cal_freq
+ *
+ * cal_value * target_freq
+ * target_value = -----------------------
+ * cal_freq
*/
-int32_t ao_freq_to_set(int32_t freq, int32_t cal)
+int32_t ao_freq_to_set(int32_t target_freq, int32_t cal_value)
{
- static int32_t set;
- static uint8_t neg;
- static int32_t error;
+ int64_t prod = (int64_t) target_freq * (int64_t) cal_value;
- set = 0;
- neg = 0;
- error = -434550 / 2;
+ /* Round to nearest */
+ int32_t target_value = (prod + (434550 / 2)) / 434550;
- if ((freq -= 434550) < 0) {
- neg = 1;
- freq = -freq;
- }
- for (;;) {
- if (error > 0) {
- error -= 434550;
- set++;
- } else {
- error += cal;
- if (--freq < 0)
- break;
- }
- }
- if (neg)
- set = -set;
- return cal + set;
+ return target_value;
}
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));
+ memcpy(&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));
+ memcpy(&gps_tracking_data, &ao_gps_tracking_data, sizeof (ao_gps_tracking_data));
ao_gps_new = 0;
ao_mutex_put(&ao_gps_mutex);
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));
+ memcpy(&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));
+ memcpy(&gps_tracking_data, &ao_gps_tracking_data, sizeof (ao_gps_tracking_data));
ao_gps_new = 0;
ao_mutex_put(&ao_gps_mutex);
#include "ao.h"
#include "ao_log.h"
-void
+static void
ao_gps_report_metrum(void)
{
static struct ao_log_metrum gps_log;
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));
+ memcpy(&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));
+ memcpy(&gps_tracking_data, &ao_gps_tracking_data, sizeof (ao_gps_tracking_data));
ao_gps_new = 0;
ao_mutex_put(&ao_gps_mutex);
int16_t sense_m; /* main continuity sense */
};
-#define const
-
-#define a (a)
-#define a (a)
-#define a (a)
-
enum ao_flight_state {
ao_flight_startup = 0,
ao_flight_idle = 1,
struct ao_config ao_config = { 250, 16000 };
-#define ao_xmemcpy(d,s,c) memcpy(d,s,c)
-#define ao_xmemset(d,v,c) memset(d,v,c)
-#define ao_xmemcmp(d,s,c) memcmp(d,s,c)
+#define memcpy(d,s,c) memcpy(d,s,c)
+#define memset(d,v,c) memset(d,v,c)
+#define memcmp(d,s,c) memcmp(d,s,c)
#define AO_IGNITER_CHARGE_TIME AO_MS_TO_TICKS(2000)
#endif
-void
+static void
ao_igniter_fire(enum ao_igniter igniter)
{
ao_ignition[igniter].firing = 1;
ao_ignition[igniter].firing = 0;
}
-void
+static void
ao_igniter(void)
{
enum ao_igniter igniter;
#endif
-void
+static void
ao_ignite_manual(void)
{
ao_cmd_white();
};
#if HAS_IGNITE
-void
+static void
ao_ignite_print_status(enum ao_igniter igniter, const char *name)
{
enum ao_igniter_status status = ao_igniter_status(igniter);
}
#endif
-void
+static void
ao_ignite_test(void)
{
#if HAS_IGNITE
/* Set all LEDs in 'mask' to the specified state */
void
-ao_led_set_mask(uint8_t colors, uint8_t mask);
+ao_led_set_mask(AO_LED_TYPE colors, AO_LED_TYPE mask);
/* Toggle the specified LEDs */
void
/* Turn on the specified LEDs for the indicated interval */
void
-ao_led_for(AO_LED_TYPE colors, uint16_t ticks);
+ao_led_for(AO_LED_TYPE colors, AO_TICK_TYPE ticks);
/* Initialize the LEDs */
void
#endif
static uint8_t
-ao_log_slots()
+ao_log_slots(void)
{
return (uint8_t) (ao_storage_log_max / ao_config.flight_log_max);
}
static struct ao_task ao_log_task;
#endif
-void
+static void
ao_log_list(void)
{
uint8_t slot;
printf ("done\n");
}
-void
+static void
ao_log_delete(void)
{
uint8_t slot;
#define AO_LOG_FORMAT_EASYMINI2 14 /* 16-byte MS5607 baro only, 3.3V supply, stm32f042 SoC */
#define AO_LOG_FORMAT_TELEMEGA_3 15 /* 32 byte typed telemega records with 32 bit gyro cal and mpu9250 */
#define AO_LOG_FORMAT_EASYMEGA_2 16 /* 32 byte typed telemega records with 32 bit gyro cal, mpu9250 rotated 90° and adxl375 */
+#define AO_LOG_FORMAT_TELESTATIC 17 /* 32 byte typed telestatic records */
+#define AO_LOG_FORMAT_MICROPEAK2 18 /* 2-byte baro values with header */
#define AO_LOG_FORMAT_NONE 127 /* No log at all */
/* Return the flight number from the given log slot, 0 if none, -slot on failure */
} u; /* 32 */
};
+struct ao_log_telestatic {
+ char type; /* 0 */
+ uint8_t csum; /* 1 */
+ uint16_t tick; /* 2 */
+ union { /* 4 */
+ /* AO_LOG_FLIGHT */
+ struct {
+ uint16_t flight; /* 4 */
+ } flight; /* 6 */
+ /* AO_LOG_STATE */
+ struct {
+ uint16_t state; /* 4 */
+ uint16_t reason; /* 6 */
+ } state; /* 8 */
+ /* AO_LOG_SENSOR */
+ struct {
+ uint32_t pressure; /* 4 */
+ uint32_t pressure2; /* 8 */
+ uint32_t thrust; /* 12 */
+ uint32_t mass; /* 16 */
+ uint16_t t_low; /* 20 */
+ uint16_t t_high[4]; /* 22 */
+ } sensor; /* 30 */
+ uint8_t align[28]; /* 4 */
+ } u; /* 32 */
+};
+
struct ao_log_metrum {
char type; /* 0 */
uint8_t csum; /* 1 */
typedef struct ao_log_metrum ao_log_type;
#endif
+#if AO_LOG_FORMAT == AO_LOG_FORMAT_TELEFIRETWO
+typedef struct ao_log_firetwo ao_log_type;
+#endif
+
#if AO_LOG_FORMAT == AO_LOG_FORMAT_EASYMINI1 || AO_LOG_FORMAT == AO_LOG_FORMAT_EASYMINI2 || AO_LOG_FORMAT == AO_LOG_FORMAT_TELEMINI2 || AO_LOG_FORMAT == AO_LOG_FORMAT_TELEMINI3
typedef struct ao_log_mini ao_log_type;
#endif
#define AO_LOG_UNCOMMON 1
#endif
+#if AO_LOG_FORMAT == AO_LOG_FORMAT_MICROPEAK2
+#define AO_LOG_UNCOMMON 1
+#endif
+
#ifndef AO_LOG_UNCOMMON
extern ao_log_type ao_log_data;
#include <ao_data.h>
#include <ao_flight.h>
-static struct ao_log_firetwo log;
+static struct ao_log_firetwo ao_fireone_data;
const uint8_t ao_log_format = AO_LOG_FORMAT_TELEFIRETWO;
return -sum;
}
-uint8_t
-ao_log_firetwo(struct ao_log_firetwo *log)
+static uint8_t
+ao_log_firetwo(void)
{
uint8_t wrote = 0;
/* set checksum */
- log->csum = 0;
- log->csum = ao_log_csum((uint8_t *) log);
+ ao_fireone_data.csum = 0;
+ ao_fireone_data.csum = ao_log_csum((uint8_t *) &ao_fireone_data);
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,
+ &ao_fireone_data,
sizeof (struct ao_log_firetwo));
ao_log_current_pos += sizeof (struct ao_log_firetwo);
}
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 uint8_t ao_log_data_pos;
+static uint8_t ao_fireone_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_firetwo))] ;
void
ao_log(void)
{
- uint16_t ao_flight_state = ao_flight_startup;
-
ao_storage_setup();
do {
while (!ao_log_running)
ao_sleep(&ao_log_running);
- log.type = AO_LOG_FLIGHT;
- log.tick = ao_time();
- log.u.flight.flight = ao_flight_number;
- ao_log_firetwo(&log);
+ ao_fireone_data.type = AO_LOG_FLIGHT;
+ ao_fireone_data.tick = ao_time();
+ ao_fireone_data.u.flight.flight = ao_flight_number;
+ ao_log_firetwo();
/* Write the whole contents of the ring to the log
* when starting up.
*/
- ao_log_data_pos = ao_data_ring_next(ao_data_head);
- ao_log_state = ao_flight_startup;
+ ao_fireone_data_pos = ao_data_ring_next(ao_data_head);
for (;;) {
/* Write samples to EEPROM */
- while (ao_log_data_pos != ao_data_head) {
- log.tick = ao_data_ring[ao_log_data_pos].tick;
- log.type = AO_LOG_SENSOR;
- log.u.sensor.pressure = ao_data_ring[ao_log_data_pos].adc.pressure;
- log.u.sensor.thrust = ao_data_ring[ao_log_data_pos].adc.thrust;
+ while (ao_fireone_data_pos != ao_data_head) {
+ ao_fireone_data.tick = ao_data_ring[ao_fireone_data_pos].tick;
+ ao_fireone_data.type = AO_LOG_SENSOR;
+ ao_fireone_data.u.sensor.pressure = ao_data_ring[ao_fireone_data_pos].adc.pressure;
+ ao_fireone_data.u.sensor.thrust = ao_data_ring[ao_fireone_data_pos].adc.thrust;
// for (i = 0; i < 4; i++) {
- // log.u.sensor.thermistor[i] = ao_data_ring[ao_log_data_pos].sensor.thermistor[i];
+ // ao_fireone_data.u.sensor.thermistor[i] = ao_data_ring[ao_fireone_data_pos].sensor.thermistor[i];
// }
- ao_log_firetwo(&log);
- ao_log_data_pos = ao_data_ring_next(ao_log_data_pos);
+ ao_log_firetwo();
+ ao_fireone_data_pos = ao_data_ring_next(ao_fireone_data_pos);
}
- /* 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_firetwo(&log);
-
- if (ao_log_state == ao_flight_landed)
- ao_log_stop();
- }
-
+
ao_log_flush();
if (!ao_log_running) break;
} while (ao_log_running);
}
-uint16_t
-ao_log_flight(uint8_t slot)
-{
- if (!ao_storage_read(ao_log_pos(slot),
- &log,
- sizeof (struct ao_log_firetwo)))
- return 0;
-
- if (ao_log_dump_check_data() && log.type == AO_LOG_FLIGHT)
- return log.u.flight.flight;
- return 0;
-}
void
ao_log_gps_data(uint16_t tick, struct ao_telemetry_location *gps_data);
+void
+ao_log_gps_tracking(uint16_t tick, struct ao_telemetry_satellite *gps_tracking_data);
+
#endif /* _AO_LOG_GPS_H_ */
while (ao_log_running) {
/* Write samples to EEPROM */
while (ao_log_monitor_pos != ao_monitor_head) {
- ao_xmemcpy(&ao_log_single_write_data.telemetry,
+ memcpy(&ao_log_single_write_data.telemetry,
&ao_monitor_ring[ao_log_monitor_pos],
AO_LOG_SINGLE_SIZE);
ao_log_single_write();
--- /dev/null
+/*
+ * Copyright © 2017 Bdale Garbee <bdale@gag.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 "ao.h"
+#include <ao_log.h>
+#include <ao_data.h>
+#include <ao_flight.h>
+
+static struct ao_log_telestatic log;
+
+const uint8_t ao_log_format = AO_LOG_FORMAT_TELESTATIC;
+
+static uint8_t
+ao_log_csum(uint8_t *b)
+{
+ uint8_t sum = 0x5a;
+ uint8_t i;
+
+ for (i = 0; i < sizeof (struct ao_log_telestatic); i++)
+ sum += *b++;
+ return -sum;
+}
+
+static uint8_t
+ao_log_telestatic(void)
+{
+ uint8_t wrote = 0;
+ /* set checksum */
+ log.csum = 0;
+ log.csum = ao_log_csum((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_telestatic));
+ ao_log_current_pos += sizeof (struct ao_log_telestatic);
+ }
+ } ao_mutex_put(&ao_log_mutex);
+ return wrote;
+}
+
+#if HAS_ADC
+static 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_telestatic))] ;
+#endif
+
+void
+ao_log(void)
+{
+ ao_storage_setup();
+
+ do {
+ ao_log_scan();
+
+ while (!ao_log_running)
+ ao_sleep(&ao_log_running);
+
+ log.type = AO_LOG_FLIGHT;
+ log.tick = ao_time();
+ log.u.flight.flight = ao_flight_number;
+ ao_log_telestatic();
+
+ /* Write the whole contents of the ring to the log
+ * when starting up.
+ */
+ ao_log_data_pos = ao_data_ring_next(ao_data_head);
+ for (;;) {
+ /* Write samples to EEPROM */
+ while (ao_log_data_pos != ao_data_head) {
+ log.tick = ao_data_ring[ao_log_data_pos].tick;
+ log.type = AO_LOG_SENSOR;
+#if HAS_ADS131A0X
+ log.u.sensor.pressure = ao_data_ring[ao_log_data_pos].ads131a0x.ain[0];
+ log.u.sensor.pressure2 = ao_data_ring[ao_log_data_pos].ads131a0x.ain[1];
+ log.u.sensor.thrust = ao_data_ring[ao_log_data_pos].ads131a0x.ain[2];
+ log.u.sensor.mass = ao_data_ring[ao_log_data_pos].ads131a0x.ain[3];
+#endif
+ log.u.sensor.t_low = ao_data_ring[ao_log_data_pos].max6691.sensor[0].t_low;
+ int i;
+ for (i = 0; i < 4; i++)
+ log.u.sensor.t_high[i] = ao_data_ring[ao_log_data_pos].max6691.sensor[i].t_high;
+ ao_log_telestatic();
+ ao_log_data_pos = ao_data_ring_next(ao_log_data_pos);
+ }
+
+ ao_log_flush();
+
+ if (!ao_log_running) break;
+
+ /* Wait for a while */
+ ao_delay(AO_MS_TO_TICKS(100));
+ }
+ } while (ao_log_running);
+}
+
ao_wakeup(&ao_monitoring);
}
-void
+static void
ao_monitor_get(void)
{
uint8_t size;
#if AO_MONITOR_LED
struct ao_task ao_monitor_blink_task;
-void
+static void
ao_monitor_blink(void)
{
#ifdef AO_MONITOR_BAD
#define hex(c) do { putchar(xdigit[(c) >> 4]); putchar(xdigit[(c)&0xf]); } while (0)
-void
+static void
ao_monitor_put(void)
{
#if LEGACY_MONITOR
state = recv_orig.telemetry_orig.flight_state;
rssi = (int16_t) AO_RSSI_FROM_RADIO(recv_orig.rssi);
- ao_xmemcpy(callsign, recv_orig.telemetry_orig.callsign, AO_MAX_CALLSIGN);
+ memcpy(callsign, recv_orig.telemetry_orig.callsign, AO_MAX_CALLSIGN);
if (state > ao_flight_invalid)
state = ao_flight_invalid;
if (recv_orig.status & PKT_APPEND_STATUS_1_CRC_OK) {
if (len > AO_CMAC_MAX_LEN)
return AO_RADIO_CMAC_LEN_ERROR;
ao_mutex_get(&ao_radio_cmac_mutex);
- ao_xmemcpy(cmac_data, packet, len);
+ memcpy(cmac_data, packet, len);
#if AO_LED_TX
ao_led_on(AO_LED_TX);
#endif
ao_led_off(AO_LED_RX);
#endif
if (i == AO_RADIO_CMAC_OK)
- ao_xmemcpy(packet, cmac_data, len);
+ memcpy(packet, cmac_data, len);
ao_mutex_put(&ao_radio_cmac_mutex);
return i;
}
}
#endif
-void
+static void
ao_report(void)
{
for(;;) {
else
#endif
ao_report_beep();
+#if HAS_SENSOR_ERRORS
+ if (ao_report_state == ao_flight_invalid && ao_sensor_errors)
+ ao_report_number(ao_sensor_errors);
+#endif
+
if (ao_report_state == ao_flight_landed) {
ao_report_altitude();
#if HAS_FLIGHT
*/
#include "ao.h"
+#include "ao_send_packet.h"
#define AO_MAX_SEND 128
ao_serial3_set_speed(uint8_t speed);
#endif
+void
+ao_serial_shutdown(void);
+
void
ao_serial_init(void);
int8_t
ao_add_stdio(int (*_pollchar)(void),
void (*putchar)(char),
- void (*flush)(void))
+ void (*_flush)(void))
{
if (ao_num_stdios == AO_NUM_STDIOS)
ao_panic(AO_PANIC_STDIO);
ao_stdios[ao_num_stdios]._pollchar = _pollchar;
ao_stdios[ao_num_stdios].putchar = putchar;
- ao_stdios[ao_num_stdios].flush = flush;
+ ao_stdios[ao_num_stdios].flush = _flush;
ao_stdios[ao_num_stdios].echo = 1;
#if AO_NUM_STDIOS > 1
return ao_num_stdios++;
#include <ao_storage.h>
uint8_t
-ao_storage_read(ao_pos_t pos, void *buf, uint16_t len)
+ao_storage_read(ao_pos_t pos, void *v_buf, uint16_t len)
{
-#ifdef CC1111
- return ao_storage_device_read(pos, buf, len);
-#else
+ uint8_t *buf = v_buf;
uint16_t this_len;
uint16_t this_off;
pos += this_len;
}
return 1;
-#endif
}
uint8_t
-ao_storage_write(ao_pos_t pos, void *buf, uint16_t len)
+ao_storage_write(ao_pos_t pos, void *v_buf, uint16_t len)
{
-#ifdef CC1111
- return ao_storage_device_write(pos, buf, len);
-#else
+ uint8_t *buf = v_buf;
uint16_t this_len;
uint16_t this_off;
pos += this_len;
}
return 1;
-#endif
}
static uint8_t storage_data[128];
}
#endif
-void
+static void
ao_storage_zap(void)
{
uint32_t v = ao_cmd_hex();
ao_storage_erase((uint32_t) v << 8);
}
-void
+static void
ao_storage_zapall(void)
{
uint32_t pos;
}
#endif /* AO_STORAGE_TEST */
-void
+static void
ao_storage_info(void)
{
ao_storage_setup();
static struct ao_list run_queue;
static struct ao_list alarm_queue;
-static struct ao_list sleep_queue[SLEEP_HASH_SIZE];
+static struct ao_list ao_sleep_queue[SLEEP_HASH_SIZE];
static void
ao_task_to_run_queue(struct ao_task *task)
static struct ao_list *
ao_task_sleep_queue(void *wchan)
{
- return &sleep_queue[(uintptr_t) wchan % SLEEP_HASH_SIZE];
+ return &ao_sleep_queue[(uintptr_t) wchan % SLEEP_HASH_SIZE];
}
static void
ao_list_init(&alarm_queue);
ao_task_alarm_tick = 0;
for (i = 0; i < SLEEP_HASH_SIZE; i++)
- ao_list_init(&sleep_queue[i]);
+ ao_list_init(&ao_sleep_queue[i]);
}
#if DEBUG
#endif /* HAS_TASK_QUEUE */
void
-ao_add_task(struct ao_task * task, void (*start)(void), const char *name)
+ao_add_task(struct ao_task * task, void (*task_func)(void), const char *name)
{
uint8_t task_id;
uint8_t t;
* Construct a stack frame so that it will 'return'
* to the start of the task
*/
- ao_arch_init_stack(task, start);
+ ao_arch_init_stack(task, task_func);
ao_arch_critical(
#if HAS_TASK_QUEUE
ao_task_init_queue(task);
#define HAS_TASK_INFO 1
#endif
-/* arm stacks must be 32-bit aligned */
+/* arm stacks must be 64-bit aligned */
#ifndef AO_STACK_ALIGNMENT
#ifdef __arm__
-#define AO_STACK_ALIGNMENT __attribute__ ((aligned(4)))
+#define AO_STACK_ALIGNMENT __attribute__ ((aligned(8)))
#else
#define AO_STACK_ALIGNMENT
#endif
/* An AltOS task */
struct ao_task {
- void *wchan; /* current wait channel (NULL if running) */
+ void *wchan; /* current wait channel (NULL if running) */
uint16_t alarm; /* abort ao_sleep time */
- ao_arch_task_members /* any architecture-specific fields */
- uint8_t task_id; /* unique id */
+ uint16_t task_id; /* unique id */
+ /* Saved stack pointer */
+ union {
+ uint32_t *sp32;
+ uint8_t *sp8;
+ };
const char *name; /* task name */
-#ifdef NEWLIB
- int __errno; /* storage for errno in newlib libc */
-#endif
#if HAS_TASK_QUEUE
struct ao_list queue;
struct ao_list alarm_queue;
#endif
- uint8_t stack[AO_STACK_SIZE] AO_STACK_ALIGNMENT; /* saved stack */
+ /* Provide both 32-bit and 8-bit stacks */
+ union {
+ uint32_t stack32[AO_STACK_SIZE>>2];
+ uint8_t stack8[AO_STACK_SIZE];
+ } AO_STACK_ALIGNMENT;
#if HAS_SAMPLE_PROFILE
uint32_t ticks;
uint32_t yields;
#define AO_SEND_MEGA 1
#endif
-#if defined (TELEMETRUM_V_2_0)
+#if defined (TELEMETRUM_V_2_0) || defined (TELEMETRUM_V_3_0)
#define AO_SEND_METRUM 1
#endif
#endif
telemetry.configuration.flight_log_max = ao_config.flight_log_max >> 10;
- ao_xmemcpy (telemetry.configuration.callsign,
- ao_config.callsign,
- AO_MAX_CALLSIGN);
- ao_xmemcpy (telemetry.configuration.version,
- ao_version,
- AO_MAX_VERSION);
+ memcpy (telemetry.configuration.callsign,
+ ao_config.callsign,
+ AO_MAX_CALLSIGN);
+ memcpy (telemetry.configuration.version,
+ ao_version,
+ AO_MAX_VERSION);
ao_telemetry_config_cur = ao_telemetry_config_max;
ao_telemetry_send();
}
static int8_t ao_telemetry_loc_cur;
static int8_t ao_telemetry_sat_cur;
+static inline void *
+telemetry_bits(struct ao_telemetry_location *l)
+{
+ return ((uint8_t *) l) + offsetof(struct ao_telemetry_location, flags);
+}
+
+static inline int
+telemetry_size(void)
+{
+ return sizeof(struct ao_telemetry_location) - offsetof(struct ao_telemetry_location, flags);
+}
+
static void
ao_send_location(void)
{
{
telemetry.generic.type = AO_TELEMETRY_LOCATION;
ao_mutex_get(&ao_gps_mutex);
- ao_xmemcpy(&telemetry.location.flags,
- &ao_gps_data.flags,
- 27);
+ memcpy(telemetry_bits(&telemetry.location),
+ telemetry_bits(&ao_gps_data),
+ telemetry_size());
telemetry.location.tick = ao_gps_tick;
ao_mutex_put(&ao_gps_mutex);
ao_telemetry_loc_cur = ao_telemetry_gps_max;
telemetry.generic.type = AO_TELEMETRY_SATELLITE;
ao_mutex_get(&ao_gps_mutex);
telemetry.satellite.channels = ao_gps_tracking_data.channels;
- ao_xmemcpy(&telemetry.satellite.sats,
+ memcpy(&telemetry.satellite.sats,
&ao_gps_tracking_data.sats,
AO_MAX_GPS_TRACKING * sizeof (struct ao_telemetry_satellite_info));
ao_mutex_put(&ao_gps_mutex);
telemetry.companion.update_period = ao_companion_setup.update_period;
telemetry.companion.channels = ao_companion_setup.channels;
ao_mutex_get(&ao_companion_mutex);
- ao_xmemcpy(&telemetry.companion.companion_data,
+ memcpy(&telemetry.companion.companion_data,
ao_companion_data,
ao_companion_setup.channels * 2);
ao_mutex_put(&ao_companion_mutex);
}
#endif
-void
+static void
ao_telemetry(void)
{
uint16_t time;
PRODUCT_DEF=-DLAMBDAKEY
IDPRODUCT=0x000a
-CFLAGS = $(PRODUCT_DEF) -I. -I$(aoschemelib) $(STMF0_CFLAGS) -Os -g
+CFLAGS = $(PRODUCT_DEF) -I. -I$(aoschemelib) $(STMF0_CFLAGS)
PROGNAME=lambdakey-v1.0
PROG=$(PROGNAME)-$(VERSION).elf
all: $(PROG) $(HEX)
$(PROG): Makefile $(OBJ)
- $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
+ $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS) -Wl,-M=$(PROGNAME).map
$(OBJ): $(INC)
-ao_product.h: ao-make-product.5c ../Version
- $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@
-
ao_scheme_const.h: ao-scheme-make-const ao_scheme_basic_syntax.scheme
$^ -o $@ -d FLOAT,VECTOR,QUASI,BIGINT,POSIX,PORT,SAVE,UNDEF
#include <ao.h>
#include <ao_scheme.h>
-static void scheme_cmd() {
+static void scheme_cmd(void) {
ao_scheme_read_eval_print(stdin, stdout, false);
}
void main(void)
{
#ifdef LEDS_AVAILABLE
- ao_led_init(LEDS_AVAILABLE);
+ ao_led_init();
#endif
ao_clock_init();
ao_timer_init();
PRODUCT_DEF=-DALTOS_FLASH
IDPRODUCT=0x000a
-CFLAGS = $(PRODUCT_DEF) $(LPC_CFLAGS) -g -Os
+CFLAGS = $(PRODUCT_DEF) $(LPC_CFLAGS)
LDFLAGS=$(CFLAGS) -L$(TOPDIR)/lpc -Wl,-Taltos-loader.ld
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) > $@
+ $(call quiet,CC) $(LDFLAGS) -o $(PROG) $(OBJ) $(LIBS)
$(OBJ): $(INC)
TOPDIR=..
endif
-include $(TOPDIR)/Makedefs
+include $(TOPDIR)/Makefile.defs
-vpath % $(TOPDIR)/lpc:$(TOPDIR)/product:$(TOPDIR)/drivers:$(TOPDIR)/kernel:$(TOPDIR)/util:$(TOPDIR)/kalman:$(TOPDIR)/aes:$(TOPDIR):$(TOPDIR)/math
-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
+vpath % $(TOPDIR)/lpc:$(AO_VPATH)
-.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)
-WARN_FLAGS=-Wall -Wextra -Werror -Wcast-align
-
-AO_CFLAGS=-I. -I$(TOPDIR)/lpc -I$(TOPDIR)/kernel -I$(TOPDIR)/drivers \
- -DNEWLIB_INTEGER_PRINTF_SCANF \
- -I$(TOPDIR)/product -I$(TOPDIR) -I$(TOPDIR)/math -I$(TOPDIR) \
- -isystem $(NEWLIB_NANO)/arm-none-eabi/include
-
-LPC_CFLAGS=-std=gnu99 -mlittle-endian -mcpu=cortex-m0 -mthumb\
- -ffreestanding -nostdlib $(AO_CFLAGS) $(WARN_FLAGS)
-
-NICKLE=nickle
-
LIBS=-L$(NEWLIB_NANO)/arm-none-eabi/lib/thumb/v6-m -lc -lm -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 $@ $<
+LPC_CFLAGS=-mlittle-endian -mcpu=cortex-m0 -mthumb\
+ -I$(TOPDIR)/lpc $(AO_CFLAGS) $(NEWLIB_CFLAGS)
endif
include $(TOPDIR)/lpc/Makefile-lpc.defs
-include $(TOPDIR)/Makedefs
LDFLAGS=$(CFLAGS) -L$(TOPDIR)/lpc -Wl,-Taltos.ld -n
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
#define AO_LED_TYPE AO_PORT_TYPE
-#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_ROMCONFIG_SYMBOL __attribute__((section(".romconfig"))) const
-#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")
}
static inline void
-ao_arch_memory_barrier() {
+ao_arch_memory_barrier(void) {
asm volatile("" ::: "memory");
}
static inline void
ao_arch_init_stack(struct ao_task *task, void *start)
{
- uint32_t *sp = (uint32_t *) (void *) (task->stack + AO_STACK_SIZE);
+ uint32_t *sp = &task->stack32[AO_STACK_SIZE >> 2];
uint32_t a = (uint32_t) start;
int i;
/* PRIMASK with interrupts enabled */
ARM_PUSH32(sp, 0);
- task->sp = sp;
+ task->sp32 = sp;
}
static inline void ao_arch_save_regs(void) {
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_cur_task->sp32 = (sp);
+ if (sp < &ao_cur_task->stack32[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) );
+ asm("mov sp, %0" : : "r" (ao_cur_task->sp32) );
/* Restore PRIMASK */
asm("pop {r0}");
} \
} while (0)
+void
+ao_debug_out(char c);
+
#define HAS_ARCH_START_SCHEDULER 1
static inline void ao_arch_start_scheduler(void) {
asm("isb");
}
+void start(void);
+
#endif /* _AO_ARCH_FUNCS_H_ */
#define AO_EXTI_PIN_NOCONFIGURE 64
void
-ao_exti_setup(uint8_t gpio, uint8_t pin, uint8_t mode, void (*callback)());
+ao_exti_setup(uint8_t gpio, uint8_t pin, uint8_t mode, void (*callback)(void));
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)());
+ao_exti_set_callback(uint8_t gpio, uint8_t pin, void (*callback)(void));
void
ao_exti_enable(uint8_t gpio, uint8_t pin);
}
void
-ao_exti_set_callback(uint8_t port, uint8_t pin, void (*callback)()) {
+ao_exti_set_callback(uint8_t port, uint8_t pin, void (*callback)(void)) {
uint8_t id = pin_id(port,pin);
uint8_t pint = ao_pint_map[id];
}
void
-ao_led_for(AO_PORT_TYPE colors, uint16_t ticks)
+ao_led_for(AO_PORT_TYPE colors, AO_TICK_TYPE ticks)
{
ao_led_on(colors);
ao_delay(ticks);
#include <ao.h>
+#define AO_SYSTICK (AO_LPC_SYSCLK / 2)
+
volatile AO_TICK_TYPE ao_tick_count;
-uint16_t
+AO_TICK_TYPE
ao_time(void)
{
return ao_tick_count;
}
+uint64_t
+ao_time_ns(void)
+{
+ AO_TICK_TYPE before, after;
+ uint32_t cvr;
+
+ do {
+ before = ao_tick_count;
+ cvr = lpc_systick.cvr;
+ after = ao_tick_count;
+ } while (before != after);
+
+ return (uint64_t) after * (1000000000ULL / AO_HERTZ) +
+ (uint64_t) cvr * (1000000000ULL / AO_SYSTICK);
+}
+
#if AO_DATA_ALL
volatile uint8_t ao_data_interval = 1;
volatile uint8_t ao_data_count;
* Set current device address and mark the
* interface as active
*/
-void
+static void
ao_usb_set_address(uint8_t address)
{
debug("ao_usb_set_address %02x\n", address);
ao_usb_set_epn_out(AO_USB_OUT_EP, ao_usb_out_rx_buffer[1-ao_usb_out_rx_cur], AO_USB_OUT_SIZE);
}
-int
+static int
_ao_usb_pollchar(void)
{
uint8_t c;
--- /dev/null
+#!/usr/bin/nickle
+
+real
+pll_out(real clock_in, int mul, int div)
+{
+ return clock_in * mul / div;
+}
+
+real
+pll_in(real pll_out, int mul, int div)
+{
+ return pll_out * div / mul;
+}
+
+real
+fcco_out(real clock_in, int mul, int div)
+{
+ real out = pll_out(clock_in, mul, div);
+ return out * div;
+}
+
+bool
+valid_clock_in(real clock_in)
+{
+ return 10 <= clock_in && clock_in < 25;
+}
+
+bool
+valid_fcco(real clock_in, int mul, int div)
+{
+ real fcco = fcco_out (clock_in, mul, div);
+ return 156 <= fcco && fcco <= 320;
+}
+
+void
+all_clocks(real clock_in) {
+ for (int mul = 1; mul <= 32; mul++) {
+ for (int div = 2; div <= 16; div *= 2) {
+ if (!valid_fcco(clock_in, mul, div))
+ printf ("clock_in %f mul %d div %d invalid fcco %f\n",
+ clock_in, mul, div, fcco_out(clock_in, mul, div));
+ else
+ printf ("clock_in %f mul %d div %d pll_out %f\n",
+ clock_in, mul, div, pll_out(clock_in, mul, div));
+ }
+ }
+}
+
+typedef struct {
+ real clock_in;
+ int mul;
+ int div;
+ real pll_out;
+} clock;
+
+clock[]
+all_ins(real pll_out)
+{
+ clock[...] clocks = {};
+ for (int mul = 1; mul <= 32; mul++) {
+ for (int div = 2; div <= 16; div *= 2) {
+ real clock_in = pll_in(pll_out, mul, div);
+ if (valid_clock_in(clock_in) && valid_fcco(clock_in, mul, div)) {
+ clocks[dim(clocks)] = (clock) {
+ .clock_in = clock_in,
+ .mul = mul,
+ .div = div,
+ .pll_out = pll_out
+ };
+ }
+ }
+ }
+ return clocks;
+}
+
+#all_clocks(12.0);
+
+autoload Sort;
+
+void
+dump_clocks(clock[] clocks)
+{
+ printf ("Clocks for %f\n", clocks[0].pll_out);
+ Sort::qsort(&clocks, bool func(clock a, clock b) { return a.clock_in > b.clock_in; });
+ for (int i = 0; i < dim (clocks); i++) {
+ printf("\tclock_in %f mul %d div %d\n",
+ clocks[i].clock_in,
+ clocks[i].mul,
+ clocks[i].div);
+ }
+}
+
+void
+find_clocks() {
+ clock[] c40 = all_ins(40.0);
+ clock[] c48 = all_ins(48.0);
+
+ dump_clocks(c40);
+ dump_clocks(c48);
+ for (int i40 = 0; i40 < dim(c40); i40++) {
+ for (int i48 = 0; i48 < dim(c48); i48++) {
+ if (c40[i40].clock_in == c48[i48].clock_in)
+ printf ("clock_in %f mul_40 %d div_40 %d mul_48 %d div_48 %d\n",
+ c40[i40].clock_in,
+ c40[i40].mul,
+ c40[i40].div,
+ c48[i48].mul,
+ c48[i48].div);
+ }
+ }
+}
+
+find_clocks();
#define LPC_CT32B_EMR_EMC_SET 2
#define LPC_CT32B_EMR_EMC_TOGGLE 3
+#define isr_decl(name) \
+ void lpc_ ## name ## _isr(void)
+
+isr_decl(halt);
+isr_decl(ignore);
+
+isr_decl(nmi);
+isr_decl(hardfault);
+isr_decl(memmanage);
+isr_decl(busfault);
+isr_decl(usagefault);
+isr_decl(svc);
+isr_decl(debugmon);
+isr_decl(pendsv);
+isr_decl(systick);
+
+isr_decl(pin_int0); /* IRQ0 */
+isr_decl(pin_int1);
+isr_decl(pin_int2);
+isr_decl(pin_int3);
+isr_decl(pin_int4); /* IRQ4 */
+isr_decl(pin_int5);
+isr_decl(pin_int6);
+isr_decl(pin_int7);
+
+isr_decl(gint0); /* IRQ8 */
+isr_decl(gint1);
+isr_decl(ssp1);
+isr_decl(i2c);
+
+isr_decl(ct16b0); /* IRQ16 */
+isr_decl(ct16b1);
+isr_decl(ct32b0);
+isr_decl(ct32b1);
+isr_decl(ssp0); /* IRQ20 */
+isr_decl(usart);
+isr_decl(usb_irq);
+isr_decl(usb_fiq);
+
+isr_decl(adc); /* IRQ24 */
+isr_decl(wwdt);
+isr_decl(bod);
+isr_decl(flash);
+
+isr_decl(usb_wakeup);
+
#endif /* _LPC_H_ */
PRODUCT_DEF=-DLPC_DEMO
IDPRODUCT=0x000a
-CFLAGS = $(PRODUCT_DEF) $(LPC_CFLAGS) -g -Os
+CFLAGS = $(PRODUCT_DEF) $(LPC_CFLAGS)
PROG=lpc-demo.elf
# Tiny AltOS build
#
#
-vpath % ../attiny:../drivers:../kernel:../product:..
-vpath ao-make-product.5c ../util
-vpath make-altitude-pa ../util
-
-include ../avr/Makefile.defs
+TOPDIR=..
+include $(TOPDIR)/attiny/Makefile.defs
PROGNAME=microkite-v0.1
PROG=$(PROGNAME)-$(VERSION).elf
PUBLISH_HEX=$(PUBLISH_DIR)/$(HEX)
PUBLISH_SCRIPT=$(PUBLISH_DIR)/$(SCRIPT)
-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_ms5607.h \
ao_log_micro.h \
ao_micropeak.h \
+ ao_product.h \
altitude-pa.h
IDPRODUCT=0
PRODUCT=MicroKite-v0.1
PRODUCT_DEF=-DMICROPEAK
-CFLAGS = $(PRODUCT_DEF) -I. -I../attiny -I../kernel -I.. -I../drivers -I../product
-CFLAGS += -g -mmcu=$(MCU) -Wall -Wstrict-prototypes -O2 -mcall-prologues -DATTINY
-
-NICKLE=nickle
+CFLAGS = $(PRODUCT_DEF) $(ATTINY_CFLAGS)
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) $(HEX) microkite-load
+all: $(PROG) $(HEX) $(SCRIPT)
CHECK=sh ../util/check-avr-mem
avr-size $(PROG)
$(OBJCOPY) -R .eeprom -O ihex $(PROG) $@
-
load: $(HEX)
$(LOADCMD) $(LOADARG)$(HEX)
load-slow: $(HEX)
$(LOADCMD) $(LOADSLOW) $(LOADARG)$(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) $(HEX) $(SCRIPT)
+ rm -f *.o *.elf *.ihx $(SCRIPT)
rm -f ao_product.h
publish: $(PUBLISH_HEX) $(PUBLISH_SCRIPT)
load-product-slow:
./$(SCRIPT) slow
-../altitude-pa.h: make-altitude-pa
- nickle $< > $@
-
-$(SCRIPT): $(SCRIPT).tmpl Makefile ../Version
+$(SCRIPT): $(SCRIPT).tmpl Makefile $(TOPDIR)/Makedefs
sed -e 's/%HEX%/$(HEX)/' -e 's/%LOADCMD%/$(LOADCMD)/' -e 's/%LOADARG%/$(LOADARG)/' -e 's/%LOADSLOW%/$(LOADSLOW)/' $(SCRIPT).tmpl > $@ || (rm $@ && exit 1)
chmod +x $@
uninstall:
-$(OBJ): ao_product.h $(INC)
+$(OBJ): $(INC)
#define HAS_SERIAL_1 0
#define HAS_TASK 0
#define HAS_MS5607 1
+#define HAS_SENSOR_ERRORS 0
#define HAS_MS5611 0
#define HAS_EEPROM 0
#define HAS_BEEP 0
ao_product.h
-microsplash-v*
-microsplash-load
+micropeak-v*
+
ao_mutex.c \
ao_interrupt.c \
ao_cmd.c \
+ ao_config.c \
ao_task.c \
ao_data.c \
ao_boot_chain.c \
ao_log_micro.h \
ao_micropeak.h \
altitude-pa.h \
+ ao_product.h \
stm32f0.h
IDPRODUCT=0x14
PRODUCT=MicroPeak-v2.0
PRODUCT_DEF=-DMICROPEAK
-CFLAGS = $(PRODUCT_DEF) $(STMF0_CFLAGS) -g -Os
+CFLAGS = $(PRODUCT_DEF) $(STMF0_CFLAGS)
PROGNAME=micropeak-v2.0
PROG=$(PROGNAME)-$(VERSION).elf
LDFLAGS=$(CFLAGS) -L$(TOPDIR)/stmf0 -Wl,-Tmicropeak.ld -n
$(PROG): Makefile $(OBJ) micropeak.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) > $@
-
-ao_product.o: ao_product.c ao_product.h
+ $(call quiet,CC) $(LDFLAGS) -o $(PROG) $(OBJ) $(LIBS)
distclean: clean
$(PUBLISH_HEX): $(HEX)
cp -a $(HEX) $@
-../altitude-pa.h: make-altitude-pa
- nickle $< > $@
-
install:
uninstall:
-$(OBJ): ao_product.h $(INC)
+$(OBJ): $(INC)
return 330 * stm_cal.vrefint_cal / vrefint;
}
+static void
+ao_log_erase(void)
+{
+ uint32_t pos;
+ for (pos = 0; pos < ao_storage_log_max; pos += ao_storage_block)
+ ao_storage_erase(pos);
+}
uint8_t ao_on_battery;
ao_micropeak(void)
{
ao_ms5607_setup();
- ao_storage_setup();
/* Give the person a second to get their finger out of the way */
ao_delay(AO_MS_TO_TICKS(1000));
- ao_pips();
-
ao_log_micro_restore();
ao_compute_height();
ao_report_altitude();
+
+ ao_pips();
+
ao_log_micro_dump();
#if BOOST_DELAY
ao_delay(BOOST_DELAY);
#endif
+ ao_log_erase();
ao_microflight();
ao_compute_height();
ao_report_altitude();
+ ao_sleep_mode();
ao_sleep(&ao_on_battery);
}
printf("battery: %u\n", ao_battery_voltage());
}
+uint8_t
+ao_log_present(void)
+{
+ uint16_t n_samples;
+
+ ao_eeprom_read(N_SAMPLES_OFFSET, &n_samples, sizeof (n_samples));
+
+ return n_samples != 0xffff;
+}
+
+static void
+ao_log_list(void)
+{
+ if (ao_log_present())
+ printf ("flight %d start %x end %x\n",
+ 1,
+ 0, MAX_LOG_OFFSET >> 8);
+ printf ("done\n");
+}
+
+static void
+ao_log_delete(void)
+{
+ int16_t cmd_flight = 1;
+
+ ao_cmd_white();
+ if (ao_cmd_lex_c == '-') {
+ cmd_flight = -1;
+ ao_cmd_lex();
+ }
+ cmd_flight *= ao_cmd_decimal();
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+
+ /* Look for the flight log matching the requested flight */
+ if (cmd_flight == 1 && ao_log_present()) {
+ ao_log_erase();
+ puts("Erased");
+ return;
+ }
+ printf("No such flight: %d\n", cmd_flight);
+}
+
static struct ao_cmds mp_cmd[] = {
+ { ao_log_list, "l\0List logs" },
+ { ao_log_delete, "d <flight-number>\0Delete flight" },
{ ao_show_bat, "b\0Show battery voltage" },
{ 0 }
};
/* Enable prefetch */
stm_flash.acr |= (1 << STM_FLASH_ACR_PRFTBE);
- /* Enable power interface clock */
- stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_PWREN);
-
/* HCLK to 48MHz -> AHB prescaler = /1 */
cfgr = stm_rcc.cfgr;
cfgr &= ~(STM_RCC_CFGR_HPRE_MASK << STM_RCC_CFGR_HPRE);
stm_rcc.csr |= (1 << STM_RCC_CSR_RMVF);
}
-void
+int
main(void)
{
+ int i;
+
+ for (i = 0; i < 100000; i++)
+ ao_arch_nop();
+
if (ao_battery_voltage() < 320)
ao_on_battery = 1;
ao_led_init();
ao_task_init();
ao_timer_init();
- ao_serial_init();
stm_moder_set(&stm_gpioa, 2, STM_MODER_OUTPUT);
-
ao_dma_init();
ao_spi_init();
ao_exti_init();
- /* Leave USB disabled on battery */
- if (!ao_on_battery) {
- ao_usb_init();
- ao_cmd_init();
- }
+ ao_storage_setup();
ao_ms5607_init();
-
ao_storage_init();
- ao_add_task(&mp_task, ao_micropeak, "micropeak");
- ao_cmd_register(mp_cmd);
+ /* Let FLITF clock turn off in sleep mode */
+ stm_rcc.ahbenr &= ~(1 << STM_RCC_AHBENR_FLITFEN);
+
+ /* Le SRAM clock turn off in sleep mode */
+ stm_rcc.ahbenr &= ~(1 << STM_RCC_AHBENR_SRAMEN);
+
+ if (ao_on_battery) {
+ /* On battery power, run the flight code */
+ ao_add_task(&mp_task, ao_micropeak, "micropeak");
+ } else {
+ /* otherwise, turn on USB and run the command processor */
+ ao_usb_init();
+ ao_cmd_init();
+ ao_cmd_register(mp_cmd);
+ ao_config_init();
+ }
ao_start_scheduler();
}
#define AO_RCC_CFGR_HPRE_DIV (ao_on_battery ? STM_RCC_CFGR_HPRE_DIV_16 : STM_RCC_CFGR_HPRE_DIV_1)
/* APB = 12MHz usb / 2MHz battery */
-#define AO_APB_PRESCALER 1
-#define AO_RCC_CFGR_PPRE_DIV STM_RCC_CFGR_PPRE_DIV_1
+#define AO_APB_PRESCALER (ao_on_battery ? 2 : 1)
+#define AO_RCC_CFGR_PPRE_DIV (ao_on_battery ? STM_RCC_CFGR_PPRE_DIV_2 : STM_RCC_CFGR_PPRE_DIV_1)
#define HAS_USB 1
#define AO_PA11_PA12_RMP 1
#define IS_FLASH_LOADER 0
#define HAS_MS5607 1
+#define HAS_SENSOR_ERRORS 0
#define HAS_MS5611 0
#define HAS_MS5607_TASK 0
-#define HAS_EEPROM 0
+#define HAS_EEPROM 1
+#define HAS_CONFIG_SAVE 0
#define HAS_BEEP 0
/* Logging */
#define LOG_INTERVAL 1
#define SAMPLE_SLEEP AO_MS_TO_TICKS(100)
#define BOOST_DELAY AO_SEC_TO_TICKS(60)
-#define AO_LOG_ID AO_LOG_ID_MICRO_PEAK2
+#define AO_LOG_ID AO_LOG_ID_MICROPEAK2
+#define HAS_LOG 1
+#define AO_LOG_FORMAT AO_LOG_FORMAT_MICROPEAK2
+#define FLIGHT_LOG_APPEND 1
/* Kalman filter */
/* SPI */
#define HAS_SPI_1 1
+#define SPI_1_POWER_MANAGE 1
#define SPI_1_PA5_PA6_PA7 1
#define SPI_1_PB3_PB4_PB5 0
#define SPI_1_OSPEEDR STM_OSPEEDR_MEDIUM
#define ao_async_stop() do { \
ao_serial2_drain(); \
stm_moder_set(&stm_gpioa, 2, STM_MODER_OUTPUT); \
+ ao_serial_shutdown(); \
} while (0)
#define ao_async_start() do { \
+ ao_serial_init(); \
stm_moder_set(&stm_gpioa, 2, STM_MODER_ALTERNATE); \
ao_delay(AO_MS_TO_TICKS(100)); \
} while (0)
#define ao_eeprom_read(pos, ptr, size) ao_storage_read(pos, ptr, size)
#define ao_eeprom_write(pos, ptr, size) ao_storage_write(pos, ptr, size)
#define MAX_LOG_OFFSET ao_storage_total
+#define ao_storage_log_max ao_storage_total
extern uint32_t __flash__[];
extern uint32_t __flash_end__[];
# Tiny AltOS build
#
#
-vpath % ../attiny:../drivers:../kernel:../product:..
-vpath ao-make-product.5c ../util
-vpath make-altitude-pa ../util
-
-include ../avr/Makefile.defs
+TOPDIR=..
+include $(TOPDIR)/attiny/Makefile.defs
PROGNAME=micropeak-v0.1
PROG=$(PROGNAME)-$(VERSION).elf
PUBLISH_HEX=$(PUBLISH_DIR)/$(HEX)
PUBLISH_SCRIPT=$(PUBLISH_DIR)/$(SCRIPT)
-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_ms5607.h \
ao_log_micro.h \
ao_micropeak.h \
+ ao_product.h \
altitude-pa.h
IDPRODUCT=0
PRODUCT=MicroPeak-v0.1
PRODUCT_DEF=-DMICROPEAK
-CFLAGS = $(PRODUCT_DEF) -I. -I../attiny -I../kernel -I.. -I../drivers -I../product
-CFLAGS += -g -mmcu=$(MCU) -Wall -Wstrict-prototypes -O2 -mcall-prologues -DATTINY
-
-NICKLE=nickle
+CFLAGS = $(PRODUCT_DEF) $(ATTINY_CFLAGS)
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) $(HEX) micropeak-load
+all: $(PROG) $(HEX) $(SCRIPT)
CHECK=sh ../util/check-avr-mem
avr-size $(PROG)
$(OBJCOPY) -R .eeprom -O ihex $(PROG) $@
-
load: $(HEX)
$(LOADCMD) $(LOADARG)$(HEX)
load-slow: $(HEX)
$(LOADCMD) $(LOADSLOW) $(LOADARG)$(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:
load-product-slow:
./$(SCRIPT) slow
-../altitude-pa.h: make-altitude-pa
- nickle $< > $@
-
-$(SCRIPT): $(SCRIPT).tmpl Makefile ../Version
+$(SCRIPT): $(SCRIPT).tmpl Makefile $(TOPDIR)/Makedefs
sed -e 's/%HEX%/$(HEX)/' -e 's/%LOADCMD%/$(LOADCMD)/' -e 's/%LOADARG%/$(LOADARG)/' -e 's/%LOADSLOW%/$(LOADSLOW)/' $(SCRIPT).tmpl > $@ || (rm $@ && exit 1)
chmod +x $@
uninstall:
-$(OBJ): ao_product.h $(INC)
+$(OBJ): $(INC)
#define HAS_TASK 0
#define HAS_MS5607 1
#define HAS_MS5611 0
+#define HAS_SENSOR_ERRORS 0
#define HAS_EEPROM 0
#define HAS_BEEP 0
#define AVR_CLOCK 250000UL
# Tiny AltOS build
#
#
-vpath % ../attiny:../drivers:../kernel:../product:..
-vpath ao-make-product.5c ../util
-vpath make-altitude-pa ../util
-
-include ../avr/Makefile.defs
+TOPDIR=..
+include $(TOPDIR)/attiny/Makefile.defs
PROGNAME=microsplash-v1.0
PROG=$(PROGNAME)-$(VERSION).elf
PUBLISH_HEX=$(PUBLISH_DIR)/$(HEX)
PUBLISH_SCRIPT=$(PUBLISH_DIR)/$(SCRIPT)
-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_ms5607.h \
ao_log_micro.h \
ao_micropeak.h \
+ ao_product.h \
altitude-pa.h
IDPRODUCT=0
PRODUCT=MicroSplash-v1.0
PRODUCT_DEF=-DMICROPEAK
-CFLAGS = $(PRODUCT_DEF) -I. -I../attiny -I../kernel -I.. -I../drivers -I../product
-CFLAGS += -g -mmcu=$(MCU) -Wall -Wstrict-prototypes -O2 -mcall-prologues -DATTINY
-
-NICKLE=nickle
+CFLAGS = $(PRODUCT_DEF) $(ATTINY_CFLAGS)
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) $(HEX) $(SCRIPT)
CHECK=sh ../util/check-avr-mem
avr-size $(PROG)
$(OBJCOPY) -R .eeprom -O ihex $(PROG) $@
-
load: $(HEX)
$(LOADCMD) $(LOADARG)$(HEX)
load-slow: $(HEX)
$(LOADCMD) $(LOADSLOW) $(LOADARG)$(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) $(HEX) $(SCRIPT)
+ rm -f *.o *.elf *.ihx $(SCRIPT)
rm -f ao_product.h
publish: $(PUBLISH_HEX) $(PUBLISH_SCRIPT)
load-product-slow:
./$(SCRIPT) slow
-../altitude-pa.h: make-altitude-pa
- nickle $< > $@
-
-$(SCRIPT): $(SCRIPT).tmpl Makefile ../Version
+$(SCRIPT): $(SCRIPT).tmpl Makefile $(TOPDIR)/Makedefs
sed -e 's/%HEX%/$(HEX)/' -e 's/%LOADCMD%/$(LOADCMD)/' -e 's/%LOADARG%/$(LOADARG)/' -e 's/%LOADSLOW%/$(LOADSLOW)/' $(SCRIPT).tmpl > $@ || (rm $@ && exit 1)
chmod +x $@
uninstall:
-$(OBJ): ao_product.h $(INC)
+$(OBJ): $(INC)
#define HAS_SERIAL_1 0
#define HAS_TASK 0
#define HAS_MS5607 1
+#define HAS_SENSOR_ERRORS 0
#define HAS_MS5611 0
#define HAS_EEPROM 0
#define HAS_BEEP 0
PRODUCT_DEF=-DMPUSB
IDPRODUCT=0x002b
-CFLAGS = $(PRODUCT_DEF) $(STMF0_CFLAGS) -Os -g
+CFLAGS = $(PRODUCT_DEF) $(STMF0_CFLAGS)
PROGNAME=mpusb-v3.0
PROG=$(PROGNAME)-$(VERSION).elf
PRODUCT_DEF=-DNUCLEO
IDPRODUCT=0x000a
-CFLAGS = $(PRODUCT_DEF) $(STMF0_CFLAGS) -Os -g
+CFLAGS = $(PRODUCT_DEF) $(STMF0_CFLAGS)
LDFLAGS=$(CFLAGS) -L$(TOPDIR)/stmf0 -Wl,-Tload.ld -n
PRODUCT_DEF=-DPNPSERVO
IDPRODUCT=0x000a
-CFLAGS = $(PRODUCT_DEF) -I. $(STMF0_CFLAGS) -Os -g
+CFLAGS = $(PRODUCT_DEF) -I. $(STMF0_CFLAGS)
LDFLAGS=$(CFLAGS) -L$(TOPDIR)/stmf0 -Wl,-Tlambda.ld
case AO_TELEMETRY_SENSOR_TELEMETRUM:
case AO_TELEMETRY_SENSOR_TELEMINI:
case AO_TELEMETRY_SENSOR_TELENANO:
- ao_xmemcpy(&ao_tel_sensor, &ao_monitor_ring[monitor], sizeof (ao_tel_sensor));
+ memcpy(&ao_tel_sensor, &ao_monitor_ring[monitor], sizeof (ao_tel_sensor));
if (ao_tel_sensor.state < ao_flight_boost) {
ao_tel_max_speed = 0;
ao_tel_max_height = 0;
ao_telem_progress = (ao_telem_progress + 1) & 0x3;
break;
case AO_TELEMETRY_LOCATION:
- ao_xmemcpy(&ao_tel_location, &ao_monitor_ring[monitor], sizeof (ao_tel_location));
+ memcpy(&ao_tel_location, &ao_monitor_ring[monitor], sizeof (ao_tel_location));
break;
case AO_TELEMETRY_CONFIGURATION:
- ao_xmemcpy(&ao_tel_config, &ao_monitor_ring[monitor], sizeof (ao_tel_config));
+ memcpy(&ao_tel_config, &ao_monitor_ring[monitor], sizeof (ao_tel_config));
}
}
}
TOPDIR=..
include $(TOPDIR)/Makedefs
-CC=arm-none-eabi-gcc
+CC=arm-none-eabicc
OBJCOPY=arm-none-eabi-objcopy
C_LIB=$(PDCLIB_LIBS_M3)
-DEF_CFLAGS=-g -std=gnu99 -Os -mlittle-endian -mthumb -ffreestanding -nostdlib -I. -I../stm $(PDCLIB_INCLUDES)
+DEF_CFLAGS= -std=gnu99 -mlittle-endian -mthumb -ffreestanding -nostdlib -I. -I../stm $(PDCLIB_INCLUDES)
# to run from SRAM
LD_FLAGS_RAM=-L../stm -Wl,-Taltos-ram.ld
PRODUCT_DEF=-DSTM_DEMO
IDPRODUCT=0x000a
-CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) -g -Os
+CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS)
PROG=stm-demo-$(VERSION)
ELF=$(PROG).elf
static inline int min(int a, int b) { return a < b ? a : b; }
-void
-ao_demo(void)
-{
- char message[] = "Hello, Mike & Bdale --- ";
- char part[7];
- int i = 0;
- int len = sizeof(message) - 1;
- int first, second;
-
- part[6] = '\0';
- for (;;) {
- ao_delay(AO_MS_TO_TICKS(150));
- first = min(6, len - i);
- second = 6 - first;
- memcpy(part, message + i, first);
- memcpy(part + first, message, second);
- ao_lcd_font_string(part);
- if (++i >= len)
- i = 0;
- }
-}
-
-void _close() { }
-void _sbrk() { }
-void _isatty() { }
-void _lseek() { }
-void _exit () { }
-void _read () { }
-void _fstat() { }
#define AO_DMA_TEST_INDEX STM_DMA_INDEX(4)
ao_task_init();
- ao_led_init(LEDS_AVAILABLE);
+ ao_led_init();
ao_led_on(AO_LED_GREEN);
ao_led_off(AO_LED_BLUE);
ao_timer_init();
PRODUCT_DEF=-DALTOS_FLASH
IDPRODUCT=0x000a
-CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) -g -Os
+CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS)
PROG=altos-flash-$(VERSION).elf
PRODUCT_DEF=-DSTM_SCHEME
IDPRODUCT=0x000a
-CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) -g -Os
+CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS)
PROG=stm-scheme-$(VERSION)
ELF=$(PROG).elf
PRODUCT=StmVga-v0.0
IDPRODUCT=0x000a
-CFLAGS = $(STM_CFLAGS) -g -Os
+CFLAGS = $(STM_CFLAGS)
PROG=stm-vga-$(VERSION)
ELF=$(PROG).elf
-vpath % $(TOPDIR)/stm:$(TOPDIR)/product:$(TOPDIR)/drivers:$(TOPDIR)/kernel:$(TOPDIR)/util:$(TOPDIR)
-vpath ao-make-product.5c $(TOPDIR)/util
-
-.SUFFIXES: .elf .ihx
-
-.elf.ihx:
- objcopy -O ihex $*.elf $@
-
-ifndef VERSION
-include $(TOPDIR)/Version
-endif
-include $(TOPDIR)/Makedefs
-
-CC=$(ARM_CC)
-LIBS=-L$(NEWLIB_NANO)/arm-none-eabi/lib/thumb/v7-m -lc -lm -lgcc
-
-AO_CFLAGS=-I. -I$(TOPDIR)/stm -I$(TOPDIR)/kernel -I$(TOPDIR)/drivers \
- -DNEWLIB_INTEGER_PRINTF_SCANF \
- -I$(TOPDIR)/product -I$(TOPDIR) -isystem $(NEWLIB_NANO)/arm-none-eabi/include
-
-STM_CFLAGS=-std=gnu99 -mlittle-endian -mcpu=cortex-m3 -mthumb \
- -ffreestanding -nostdlib $(AO_CFLAGS) $(SAT_CFLAGS)
-
-LDFLAGS=-L$(TOPDIR)/stm -Wl,-Taltos-loader.ld
-
-NICKLE=nickle
-
-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 $@ $<
+include $(TOPDIR)/stm/Makefile-stm.defs
INC = \
ao.h \
PRODUCT_DEF=-DALTOS_FLASH
IDPRODUCT=0x000a
-CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) -g -Os
+CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS)
+
+LDFLAGS=$(CFLAGS) -L$(TOPDIR)/stm -Wl,-Taltos-loader.ld -n
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)
--- /dev/null
+ifndef TOPDIR
+TOPDIR=..
+endif
+
+include $(TOPDIR)/Makefile.defs
+
+vpath % $(TOPDIR)/stm:$(AO_VPATH)
+
+CC=$(ARM_CC)
+LIBS=-L$(NEWLIB_NANO)/arm-none-eabi/lib/thumb/v7-m -lm -lc -lgcc
+
+STM_CFLAGS=-mlittle-endian -mcpu=cortex-m3 -mthumb \
+ -I$(TOPDIR)/stm $(AO_CFLAGS) $(NEWLIB_CFLAGS)
-vpath % ../stm:../product:../drivers:../kernel:../util:../kalman:../aes:../math:../draw:../scheme:..
-vpath make-altitude ../util
-vpath make-kalman ../util
-vpath kalman.5c ../kalman
-vpath kalman_filter.5c ../kalman
-vpath load_csv.5c ../kalman
-vpath matrix.5c ../kalman
-vpath ao-make-product.5c ../util
-
-.SUFFIXES: .elf .ihx
-
-.elf.ihx:
- $(ELFTOHEX) --output=$@ $*.elf
-
ifndef TOPDIR
TOPDIR=..
endif
-ifndef VERSION
-include $(TOPDIR)/Version
-endif
-include $(TOPDIR)/Makedefs
-
-CC=$(ARM_CC)
-LIBS=-L$(NEWLIB_NANO)/arm-none-eabi/lib/thumb/v7-m -lm -lc -lgcc
-
-WARN_FLAGS=-Wall -Wextra -Werror
-
-AO_CFLAGS=-I. -I../stm -I../kernel -I../drivers -I../math -I../draw \
- -DNEWLIB_INTEGER_PRINTF_SCANF \
- -I../lisp -I.. -isystem $(NEWLIB_NANO)/arm-none-eabi/include
-
-STM_CFLAGS=-std=gnu99 -mlittle-endian -mcpu=cortex-m3 -mthumb -Wcast-align \
- -ffreestanding -nostdlib $(AO_CFLAGS) $(WARN_FLAGS)
-
-LDFLAGS=-L../stm -Wl,-Taltos.ld -nostartfiles -Wl,-Map=$(PROGNAME).map
-
-NICKLE=nickle
-ELFTOHEX=$(TOPDIR)/../ao-tools/ao-elftohex/ao-elftohex
-
-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)
+include $(TOPDIR)/stm/Makefile-stm.defs
-.c.o:
- $(call quiet,CC) -c $(CFLAGS) -o $@ $<
+LDFLAGS=$(CFLAGS) -L$(TOPDIR)/stm -Wl,-Taltos.ld -n
glyph[*] font;
void init () {
- twixt (file f = File::open("ao_lcd_font.h", "r"); File::close(f)) {
+ twixt (file f = File::open("ao_lcd_font_bits.h", "r"); File::close(f)) {
font = read_font(f);
}
}
void dump() {
- twixt(file f = File::open("ao_lcd_font.h.new", "w"); File::close(f)) {
+ twixt(file f = File::open("ao_lcd_font_bits.h.new", "w"); File::close(f)) {
for (int i = 0; i < dim(font); i++) {
File::fprintf (f, "\t[%d] = 0x%04x,\n", i, glyph_value(font[i]));
File::fprintf (f, "/*\n");
#include <ao.h>
#include <ao_data.h>
+#include <ao_adc_single.h>
static uint8_t ao_adc_ready;
stm_adc.cr2 = AO_ADC_CR2_VAL | (1 << STM_ADC_CR2_SWSTART);
}
-/*
- * Fetch a copy of the most recent ADC data
- */
-void
-ao_adc_get(struct ao_adc *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].adc, sizeof (struct ao_adc));
-}
-
#ifdef AO_ADC_SQ1_NAME
static const char *ao_adc_name[AO_NUM_ADC] = {
AO_ADC_SQ1_NAME,
#define AO_STACK_SIZE 512
#endif
-#ifndef AO_TICK_TYPE
-#define AO_TICK_TYPE uint16_t
-#define AO_TICK_SIGNED int16_t
-#endif
-
#define AO_PORT_TYPE uint16_t
/* Various definitions to make GCC look more like SDCC */
#define AO_ROMCONFIG_SYMBOL __attribute__((section(".romconfig"))) const
-#define ao_arch_task_members\
- uint32_t *sp; /* saved stack pointer */
-
/*
* For now, we're running at a weird frequency
*/
extern const uint32_t ao_radio_cal;
void
-ao_adc_init();
+ao_adc_init(void);
/* ADC maximum reported value */
#define AO_ADC_MAX 4095
#endif
};
+void
+ao_debug_out(char c);
+
#if HAS_SERIAL_1
extern struct ao_stm_usart ao_stm_usart1;
#endif
}
static inline void
-ao_arch_memory_barrier() {
+ao_arch_memory_barrier(void) {
asm volatile("" ::: "memory");
}
static inline void
ao_arch_init_stack(struct ao_task *task, void *start)
{
- uint32_t *sp = (uint32_t *) ((void*) task->stack + AO_STACK_SIZE);
+ uint32_t *sp = &task->stack32[AO_STACK_SIZE>>2];
uint32_t a = (uint32_t) start;
int i;
/* BASEPRI with interrupts enabled */
ARM_PUSH32(sp, 0);
- task->sp = sp;
+ task->sp32 = sp;
}
static inline void ao_arch_save_regs(void) {
static inline void ao_arch_save_stack(void) {
uint32_t *sp;
asm("mov %0,sp" : "=&r" (sp) );
- ao_cur_task->sp = (sp);
+ ao_cur_task->sp32 = (sp);
}
static inline void ao_arch_restore_stack(void) {
/* Switch stacks */
- asm("mov sp, %0" : : "r" (ao_cur_task->sp) );
+ asm("mov sp, %0" : : "r" (ao_cur_task->sp32) );
#ifdef AO_NONMASK_INTERRUPTS
/* Restore BASEPRI */
ao_arch_irqrestore(__mask); \
} while (0)
+void start(void);
+
#endif /* _AO_ARCH_FUNCS_H_ */
*/
#include "ao.h"
+#include "ao_beep.h"
#if BEEPER_TIMER == 2
#define stm_beeper stm_tim2
#define AO_EXTI_PIN_NOCONFIGURE 64
void
-ao_exti_setup(struct stm_gpio *gpio, uint8_t pin, uint8_t mode, void (*callback)());
+ao_exti_setup(struct stm_gpio *gpio, uint8_t pin, uint8_t mode, void (*callback)(void));
void
ao_exti_set_mode(struct stm_gpio *gpio, uint8_t pin, uint8_t mode);
void
-ao_exti_set_callback(struct stm_gpio *gpio, uint8_t pin, void (*callback)());
+ao_exti_set_callback(struct stm_gpio *gpio, uint8_t pin, void (*callback)(void));
void
ao_exti_enable(struct stm_gpio *gpio, uint8_t pin);
}
void
-ao_exti_set_callback(struct stm_gpio *gpio, uint8_t pin, void (*callback)()) {
+ao_exti_set_callback(struct stm_gpio *gpio, uint8_t pin, void (*callback)(void)) {
(void) gpio;
ao_exti_callback[pin] = callback;
}
return true;
}
-void
+static void
ao_i2c_recv_dma_isr(int index)
{
int i;
(0 << STM_DMA_CCR_PINC) |
(0 << STM_DMA_CCR_CIRC) |
(STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR));
+
+ /* XXX ao_i2c_recv_dma_isr hasn't ever been used, so it
+ * doesn't appear to be necessary. Testing with a device
+ * that uses i2c would really be useful here to discover
+ * whether this function is necessary or not.
+ */
+#if 0
+ ao_dma_set_isr(rx_dma_index, ao_i2c_recv_dma_isr);
+#else
+ (void) ao_i2c_recv_dma_isr;
+#endif
stm_i2c->cr1 = AO_STM_I2C_CR1 | (1 << STM_I2C_CR1_ACK);
stm_i2c->cr2 = AO_STM_I2C_CR2 |
(1 << STM_I2C_CR2_DMAEN) | (1 << STM_I2C_CR2_LAST);
return ret;
}
-void
+static void
ao_i2c_channel_init(uint8_t index)
{
struct stm_i2c *stm_i2c = ao_i2c_stm_info[index].stm_i2c;
*/
#include <ao.h>
+#include "ao_lcd_font.h"
static const uint16_t ao_lcd_font[] = {
-#include "ao_lcd_font.h"
+#include "ao_lcd_font_bits.h"
};
/*
ao_lcd_font_string(string);
}
-const struct ao_cmds ao_lcd_font_cmds[] = {
+static const struct ao_cmds ao_lcd_font_cmds[] = {
{ ao_lcd_font_text, "t <string>\0Write <string> to LCD" },
{ 0, NULL }
};
{
ao_cmd_register(ao_lcd_font_cmds);
}
-
- [0] = 0x0000,
/*
-CHAR 32 ' '
-
-
-
-
-
-
-
-*/
+ * Copyright © 2019 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.
+ */
- [1] = 0x0102,
-/*
-CHAR 33 '!'
-
- |
- |
-
- |
- |
-
-*/
-
- [2] = 0x000a,
-/*
-CHAR 34 '"'
-
- | |
- | |
-
-
-
-
-*/
-
- [3] = 0x05e8,
-/*
-CHAR 35 '#'
-
- | |
- | |
- -- --
- | |
- | |
-
-*/
-
- [4] = 0x34cb,
-/*
-CHAR 36 '$'
- -----
- | |
- | |
- -- --
- | |
- | |
- -----
-*/
-
- [5] = 0x1212,
-/*
-CHAR 37 '%'
-
- | /
- | /
-
- / |
- / |
-
-*/
-
- [6] = 0x2955,
-/*
-CHAR 38 '&'
- -----
- \ /
- \ /
- --
- | \
- | \
- -----
-*/
-
- [7] = 0x0008,
-/*
-CHAR 39 '''
-
- |
- |
-
-
-
-
-*/
-
- [8] = 0x2103,
-/*
-CHAR 40 '('
- -----
- |
- |
-
- |
- |
- -----
-*/
-
- [9] = 0x3021,
-/*
-CHAR 41 ')'
- -----
- |
- |
-
- |
- |
- -----
-*/
-
- [10] = 0x0e1c,
-/*
-CHAR 42 '*'
-
- \ | /
- \|/
-
- /|\
- / | \
-
-*/
-
- [11] = 0x04c8,
-/*
-CHAR 43 '+'
-
- |
- |
- -- --
- |
- |
-
-*/
-
- [12] = 0x0200,
-/*
-CHAR 44 ','
-
-
-
-
- /
- /
-
-*/
-
- [13] = 0x00c0,
-/*
-CHAR 45 '-'
-
-
-
- -- --
-
-
-
-*/
-
- [14] = 0x0800,
-/*
-CHAR 46 '.'
-
-
-
-
- \
- \
-
-*/
-
- [15] = 0x0210,
-/*
-CHAR 47 '/'
-
- /
- /
-
- /
- /
-
-*/
-
- [16] = 0x3333,
-/*
-CHAR 48 '0'
- -----
- | /|
- | / |
-
- | / |
- |/ |
- -----
-*/
-
- [17] = 0x1030,
-/*
-CHAR 49 '1'
-
- /|
- / |
-
- |
- |
-
-*/
-
- [18] = 0x21e1,
-/*
-CHAR 50 '2'
- -----
- |
- |
- -- --
- |
- |
- -----
-*/
-
- [19] = 0x30a1,
-/*
-CHAR 51 '3'
- -----
- |
- |
- --
- |
- |
- -----
-*/
-
- [20] = 0x10e2,
-/*
-CHAR 52 '4'
-
- | |
- | |
- -- --
- |
- |
-
-*/
-
- [21] = 0x30c3,
-/*
-CHAR 53 '5'
- -----
- |
- |
- -- --
- |
- |
- -----
-*/
-
- [22] = 0x31c3,
-/*
-CHAR 54 '6'
- -----
- |
- |
- -- --
- | |
- | |
- -----
-*/
-
- [23] = 0x0411,
-/*
-CHAR 55 '7'
- -----
- /
- /
-
- |
- |
-
-*/
-
- [24] = 0x31e3,
-/*
-CHAR 56 '8'
- -----
- | |
- | |
- -- --
- | |
- | |
- -----
-*/
-
- [25] = 0x10e3,
-/*
-CHAR 57 '9'
- -----
- | |
- | |
- -- --
- |
- |
-
-*/
-
- [26] = 0x0408,
-/*
-CHAR 58 ':'
-
- |
- |
-
- |
- |
-
-*/
-
- [27] = 0x0208,
-/*
-CHAR 59 ';'
-
- |
- |
-
- /
- /
-
-*/
-
- [28] = 0x0810,
-/*
-CHAR 60 '<'
-
- /
- /
-
- \
- \
-
-*/
-
- [29] = 0x20c0,
-/*
-CHAR 61 '='
-
-
-
- -- --
-
-
- -----
-*/
-
- [30] = 0x0204,
-/*
-CHAR 62 '>'
-
- \
- \
-
- /
- /
-
-*/
-
- [31] = 0x0413,
-/*
-CHAR 63 '?'
- -----
- | /
- | /
-
- |
- |
-
-*/
-
- [32] = 0x39b3,
-/*
-CHAR 64 '@'
- -----
- | /|
- | / |
- --
- | \ |
- | \|
- -----
-*/
-
- [33] = 0x11e3,
-/*
-CHAR 65 'A'
- -----
- | |
- | |
- -- --
- | |
- | |
-
-*/
-
- [34] = 0x34a9,
-/*
-CHAR 66 'B'
- -----
- | |
- | |
- --
- | |
- | |
- -----
-*/
-
- [35] = 0x2103,
-/*
-CHAR 67 'C'
- -----
- |
- |
-
- |
- |
- -----
-*/
-
- [36] = 0x3429,
-/*
-CHAR 68 'D'
- -----
- | |
- | |
-
- | |
- | |
- -----
-*/
-
- [37] = 0x2143,
-/*
-CHAR 69 'E'
- -----
- |
- |
- --
- |
- |
- -----
-*/
-
- [38] = 0x0143,
-/*
-CHAR 70 'F'
- -----
- |
- |
- --
- |
- |
-
-*/
-
- [39] = 0x3183,
-/*
-CHAR 71 'G'
- -----
- |
- |
- --
- | |
- | |
- -----
-*/
-
- [40] = 0x11e2,
-/*
-CHAR 72 'H'
-
- | |
- | |
- -- --
- | |
- | |
-
-*/
-
- [41] = 0x2409,
-/*
-CHAR 73 'I'
- -----
- |
- |
-
- |
- |
- -----
-*/
-
- [42] = 0x3120,
-/*
-CHAR 74 'J'
-
- |
- |
-
- | |
- | |
- -----
-*/
-
- [43] = 0x0952,
-/*
-CHAR 75 'K'
-
- | /
- | /
- --
- | \
- | \
-
-*/
-
- [44] = 0x2102,
-/*
-CHAR 76 'L'
-
- |
- |
-
- |
- |
- -----
-*/
-
- [45] = 0x1136,
-/*
-CHAR 77 'M'
-
- |\ /|
- | \ / |
-
- | |
- | |
-
-*/
-
- [46] = 0x1926,
-/*
-CHAR 78 'N'
-
- |\ |
- | \ |
-
- | \ |
- | \|
-
-*/
-
- [47] = 0x3123,
-/*
-CHAR 79 'O'
- -----
- | |
- | |
-
- | |
- | |
- -----
-*/
+#ifndef _AO_LCD_FONT_H_
+#define _AO_LCD_FONT_H_
- [48] = 0x01e3,
-/*
-CHAR 80 'P'
- -----
- | |
- | |
- -- --
- |
- |
-
-*/
-
- [49] = 0x3923,
-/*
-CHAR 81 'Q'
- -----
- | |
- | |
-
- | \ |
- | \|
- -----
-*/
-
- [50] = 0x09e3,
-/*
-CHAR 82 'R'
- -----
- | |
- | |
- -- --
- | \
- | \
-
-*/
-
- [51] = 0x3085,
-/*
-CHAR 83 'S'
- -----
- \
- \
- --
- |
- |
- -----
-*/
-
- [52] = 0x0409,
-/*
-CHAR 84 'T'
- -----
- |
- |
-
- |
- |
-
-*/
-
- [53] = 0x3122,
-/*
-CHAR 85 'U'
-
- | |
- | |
-
- | |
- | |
- -----
-*/
-
- [54] = 0x0312,
-/*
-CHAR 86 'V'
-
- | /
- | /
-
- | /
- |/
-
-*/
-
- [55] = 0x1b22,
-/*
-CHAR 87 'W'
-
- | |
- | |
-
- | / \ |
- |/ \|
-
-*/
-
- [56] = 0x0a14,
-/*
-CHAR 88 'X'
-
- \ /
- \ /
-
- / \
- / \
-
-*/
-
- [57] = 0x0414,
-/*
-CHAR 89 'Y'
-
- \ /
- \ /
-
- |
- |
-
-*/
-
- [58] = 0x2211,
-/*
-CHAR 90 'Z'
- -----
- /
- /
-
- /
- /
- -----
-*/
+void
+ao_lcd_font_init(void);
- [59] = 0x2103,
-/*
-CHAR 91 '['
- -----
- |
- |
-
- |
- |
- -----
-*/
-
- [60] = 0x0804,
-/*
-CHAR 92 '\'
-
- \
- \
-
- \
- \
-
-*/
+void
+ao_lcd_font_string(char *s);
- [61] = 0x3021,
-/*
-CHAR 93 ']'
- -----
- |
- |
-
- |
- |
- -----
-*/
-
- [62] = 0x0023,
-/*
-CHAR 94 '^'
- -----
- | |
- | |
-
-
-
-
-*/
-
- [63] = 0x2000,
-/*
-CHAR 95 '_'
-
-
-
-
-
-
- -----
-*/
-
- [64] = 0x0004,
-/*
-CHAR 96 '`'
-
- \
- \
-
-
-
-
-*/
-
- [65] = 0x2540,
-/*
-CHAR 97 'a'
-
-
-
- --
- | |
- | |
- -----
-*/
-
- [66] = 0x2942,
-/*
-CHAR 98 'b'
-
- |
- |
- --
- | \
- | \
- -----
-*/
-
- [67] = 0x21c0,
-/*
-CHAR 99 'c'
-
-
-
- -- --
- |
- |
- -----
-*/
-
- [68] = 0x32a0,
-/*
-CHAR 100 'd'
-
- |
- |
- --
- / |
- / |
- -----
-*/
-
- [69] = 0x2340,
-/*
-CHAR 101 'e'
-
-
-
- --
- | /
- |/
- -----
-*/
-
- [70] = 0x0143,
-/*
-CHAR 102 'f'
- -----
- |
- |
- --
- |
- |
-
-*/
-
- [71] = 0x10a5,
-/*
-CHAR 103 'g'
- -----
- \ |
- \ |
- --
- |
- |
-
-*/
-
- [72] = 0x11c2,
-/*
-CHAR 104 'h'
-
- |
- |
- -- --
- | |
- | |
-
-*/
-
- [73] = 0x0400,
-/*
-CHAR 105 'i'
-
-
-
-
- |
- |
-
-*/
-
- [74] = 0x3000,
-/*
-CHAR 106 'j'
-
-
-
-
- |
- |
- -----
-*/
-
- [75] = 0x0c88,
-/*
-CHAR 107 'k'
-
- |
- |
- --
- |\
- | \
-
-*/
-
- [76] = 0x0408,
-/*
-CHAR 108 'l'
-
- |
- |
-
- |
- |
-
-*/
-
- [77] = 0x15c0,
-/*
-CHAR 109 'm'
-
-
-
- -- --
- | | |
- | | |
-
-*/
-
- [78] = 0x0940,
-/*
-CHAR 110 'n'
-
-
-
- --
- | \
- | \
-
-*/
-
- [79] = 0x31c0,
-/*
-CHAR 111 'o'
-
-
-
- -- --
- | |
- | |
- -----
-*/
-
- [80] = 0x0146,
-/*
-CHAR 112 'p'
-
- |\
- | \
- --
- |
- |
-
-*/
-
- [81] = 0x10b0,
-/*
-CHAR 113 'q'
-
- /|
- / |
- --
- |
- |
-
-*/
-
- [82] = 0x0140,
-/*
-CHAR 114 'r'
-
-
-
- --
- |
- |
-
-*/
-
- [83] = 0x2880,
-/*
-CHAR 115 's'
-
-
-
- --
- \
- \
- -----
-*/
-
- [84] = 0x2142,
-/*
-CHAR 116 't'
-
- |
- |
- --
- |
- |
- -----
-*/
-
- [85] = 0x3100,
-/*
-CHAR 117 'u'
-
-
-
-
- | |
- | |
- -----
-*/
-
- [86] = 0x0300,
-/*
-CHAR 118 'v'
-
-
-
-
- | /
- |/
-
-*/
-
- [87] = 0x1b00,
-/*
-CHAR 119 'w'
-
-
-
-
- | / \ |
- |/ \|
-
-*/
-
- [88] = 0x0a14,
-/*
-CHAR 120 'x'
-
- \ /
- \ /
-
- / \
- / \
-
-*/
-
- [89] = 0x3800,
-/*
-CHAR 121 'y'
-
-
-
-
- \ |
- \|
- -----
-*/
-
- [90] = 0x2240,
-/*
-CHAR 122 'z'
-
-
-
- --
- /
- /
- -----
-*/
-
- [91] = 0x2245,
-/*
-CHAR 123 '{'
- -----
- \
- \
- --
- /
- /
- -----
-*/
-
- [92] = 0x0408,
-/*
-CHAR 124 '|'
-
- |
- |
-
- |
- |
-
-*/
-
- [93] = 0x2891,
-/*
-CHAR 125 '}'
- -----
- /
- /
- --
- \
- \
- -----
-*/
-
- [94] = 0x000e,
-/*
-CHAR 126 '~'
-
- |\ |
- | \|
-
-
-
-
-*/
-
- [95] = 0x3fff,
-/*
-CHAR 127 'DEL'
- -----
- |\ | /|
- | \|/ |
- -- --
- | /|\ |
- |/ | \|
- -----
-*/
+void
+ao_lcd_font_char(uint8_t pos, char c, uint16_t flags);
+#endif /* _AO_LCD_FONT_H_ */
--- /dev/null
+ [0] = 0x0000,
+/*
+CHAR 32 ' '
+
+
+
+
+
+
+
+*/
+
+ [1] = 0x0102,
+/*
+CHAR 33 '!'
+
+ |
+ |
+
+ |
+ |
+
+*/
+
+ [2] = 0x000a,
+/*
+CHAR 34 '"'
+
+ | |
+ | |
+
+
+
+
+*/
+
+ [3] = 0x05e8,
+/*
+CHAR 35 '#'
+
+ | |
+ | |
+ -- --
+ | |
+ | |
+
+*/
+
+ [4] = 0x34cb,
+/*
+CHAR 36 '$'
+ -----
+ | |
+ | |
+ -- --
+ | |
+ | |
+ -----
+*/
+
+ [5] = 0x1212,
+/*
+CHAR 37 '%'
+
+ | /
+ | /
+
+ / |
+ / |
+
+*/
+
+ [6] = 0x2955,
+/*
+CHAR 38 '&'
+ -----
+ \ /
+ \ /
+ --
+ | \
+ | \
+ -----
+*/
+
+ [7] = 0x0008,
+/*
+CHAR 39 '''
+
+ |
+ |
+
+
+
+
+*/
+
+ [8] = 0x2103,
+/*
+CHAR 40 '('
+ -----
+ |
+ |
+
+ |
+ |
+ -----
+*/
+
+ [9] = 0x3021,
+/*
+CHAR 41 ')'
+ -----
+ |
+ |
+
+ |
+ |
+ -----
+*/
+
+ [10] = 0x0e1c,
+/*
+CHAR 42 '*'
+
+ \ | /
+ \|/
+
+ /|\
+ / | \
+
+*/
+
+ [11] = 0x04c8,
+/*
+CHAR 43 '+'
+
+ |
+ |
+ -- --
+ |
+ |
+
+*/
+
+ [12] = 0x0200,
+/*
+CHAR 44 ','
+
+
+
+
+ /
+ /
+
+*/
+
+ [13] = 0x00c0,
+/*
+CHAR 45 '-'
+
+
+
+ -- --
+
+
+
+*/
+
+ [14] = 0x0800,
+/*
+CHAR 46 '.'
+
+
+
+
+ \
+ \
+
+*/
+
+ [15] = 0x0210,
+/*
+CHAR 47 '/'
+
+ /
+ /
+
+ /
+ /
+
+*/
+
+ [16] = 0x3333,
+/*
+CHAR 48 '0'
+ -----
+ | /|
+ | / |
+
+ | / |
+ |/ |
+ -----
+*/
+
+ [17] = 0x1030,
+/*
+CHAR 49 '1'
+
+ /|
+ / |
+
+ |
+ |
+
+*/
+
+ [18] = 0x21e1,
+/*
+CHAR 50 '2'
+ -----
+ |
+ |
+ -- --
+ |
+ |
+ -----
+*/
+
+ [19] = 0x30a1,
+/*
+CHAR 51 '3'
+ -----
+ |
+ |
+ --
+ |
+ |
+ -----
+*/
+
+ [20] = 0x10e2,
+/*
+CHAR 52 '4'
+
+ | |
+ | |
+ -- --
+ |
+ |
+
+*/
+
+ [21] = 0x30c3,
+/*
+CHAR 53 '5'
+ -----
+ |
+ |
+ -- --
+ |
+ |
+ -----
+*/
+
+ [22] = 0x31c3,
+/*
+CHAR 54 '6'
+ -----
+ |
+ |
+ -- --
+ | |
+ | |
+ -----
+*/
+
+ [23] = 0x0411,
+/*
+CHAR 55 '7'
+ -----
+ /
+ /
+
+ |
+ |
+
+*/
+
+ [24] = 0x31e3,
+/*
+CHAR 56 '8'
+ -----
+ | |
+ | |
+ -- --
+ | |
+ | |
+ -----
+*/
+
+ [25] = 0x10e3,
+/*
+CHAR 57 '9'
+ -----
+ | |
+ | |
+ -- --
+ |
+ |
+
+*/
+
+ [26] = 0x0408,
+/*
+CHAR 58 ':'
+
+ |
+ |
+
+ |
+ |
+
+*/
+
+ [27] = 0x0208,
+/*
+CHAR 59 ';'
+
+ |
+ |
+
+ /
+ /
+
+*/
+
+ [28] = 0x0810,
+/*
+CHAR 60 '<'
+
+ /
+ /
+
+ \
+ \
+
+*/
+
+ [29] = 0x20c0,
+/*
+CHAR 61 '='
+
+
+
+ -- --
+
+
+ -----
+*/
+
+ [30] = 0x0204,
+/*
+CHAR 62 '>'
+
+ \
+ \
+
+ /
+ /
+
+*/
+
+ [31] = 0x0413,
+/*
+CHAR 63 '?'
+ -----
+ | /
+ | /
+
+ |
+ |
+
+*/
+
+ [32] = 0x39b3,
+/*
+CHAR 64 '@'
+ -----
+ | /|
+ | / |
+ --
+ | \ |
+ | \|
+ -----
+*/
+
+ [33] = 0x11e3,
+/*
+CHAR 65 'A'
+ -----
+ | |
+ | |
+ -- --
+ | |
+ | |
+
+*/
+
+ [34] = 0x34a9,
+/*
+CHAR 66 'B'
+ -----
+ | |
+ | |
+ --
+ | |
+ | |
+ -----
+*/
+
+ [35] = 0x2103,
+/*
+CHAR 67 'C'
+ -----
+ |
+ |
+
+ |
+ |
+ -----
+*/
+
+ [36] = 0x3429,
+/*
+CHAR 68 'D'
+ -----
+ | |
+ | |
+
+ | |
+ | |
+ -----
+*/
+
+ [37] = 0x2143,
+/*
+CHAR 69 'E'
+ -----
+ |
+ |
+ --
+ |
+ |
+ -----
+*/
+
+ [38] = 0x0143,
+/*
+CHAR 70 'F'
+ -----
+ |
+ |
+ --
+ |
+ |
+
+*/
+
+ [39] = 0x3183,
+/*
+CHAR 71 'G'
+ -----
+ |
+ |
+ --
+ | |
+ | |
+ -----
+*/
+
+ [40] = 0x11e2,
+/*
+CHAR 72 'H'
+
+ | |
+ | |
+ -- --
+ | |
+ | |
+
+*/
+
+ [41] = 0x2409,
+/*
+CHAR 73 'I'
+ -----
+ |
+ |
+
+ |
+ |
+ -----
+*/
+
+ [42] = 0x3120,
+/*
+CHAR 74 'J'
+
+ |
+ |
+
+ | |
+ | |
+ -----
+*/
+
+ [43] = 0x0952,
+/*
+CHAR 75 'K'
+
+ | /
+ | /
+ --
+ | \
+ | \
+
+*/
+
+ [44] = 0x2102,
+/*
+CHAR 76 'L'
+
+ |
+ |
+
+ |
+ |
+ -----
+*/
+
+ [45] = 0x1136,
+/*
+CHAR 77 'M'
+
+ |\ /|
+ | \ / |
+
+ | |
+ | |
+
+*/
+
+ [46] = 0x1926,
+/*
+CHAR 78 'N'
+
+ |\ |
+ | \ |
+
+ | \ |
+ | \|
+
+*/
+
+ [47] = 0x3123,
+/*
+CHAR 79 'O'
+ -----
+ | |
+ | |
+
+ | |
+ | |
+ -----
+*/
+
+ [48] = 0x01e3,
+/*
+CHAR 80 'P'
+ -----
+ | |
+ | |
+ -- --
+ |
+ |
+
+*/
+
+ [49] = 0x3923,
+/*
+CHAR 81 'Q'
+ -----
+ | |
+ | |
+
+ | \ |
+ | \|
+ -----
+*/
+
+ [50] = 0x09e3,
+/*
+CHAR 82 'R'
+ -----
+ | |
+ | |
+ -- --
+ | \
+ | \
+
+*/
+
+ [51] = 0x3085,
+/*
+CHAR 83 'S'
+ -----
+ \
+ \
+ --
+ |
+ |
+ -----
+*/
+
+ [52] = 0x0409,
+/*
+CHAR 84 'T'
+ -----
+ |
+ |
+
+ |
+ |
+
+*/
+
+ [53] = 0x3122,
+/*
+CHAR 85 'U'
+
+ | |
+ | |
+
+ | |
+ | |
+ -----
+*/
+
+ [54] = 0x0312,
+/*
+CHAR 86 'V'
+
+ | /
+ | /
+
+ | /
+ |/
+
+*/
+
+ [55] = 0x1b22,
+/*
+CHAR 87 'W'
+
+ | |
+ | |
+
+ | / \ |
+ |/ \|
+
+*/
+
+ [56] = 0x0a14,
+/*
+CHAR 88 'X'
+
+ \ /
+ \ /
+
+ / \
+ / \
+
+*/
+
+ [57] = 0x0414,
+/*
+CHAR 89 'Y'
+
+ \ /
+ \ /
+
+ |
+ |
+
+*/
+
+ [58] = 0x2211,
+/*
+CHAR 90 'Z'
+ -----
+ /
+ /
+
+ /
+ /
+ -----
+*/
+
+ [59] = 0x2103,
+/*
+CHAR 91 '['
+ -----
+ |
+ |
+
+ |
+ |
+ -----
+*/
+
+ [60] = 0x0804,
+/*
+CHAR 92 '\'
+
+ \
+ \
+
+ \
+ \
+
+*/
+
+ [61] = 0x3021,
+/*
+CHAR 93 ']'
+ -----
+ |
+ |
+
+ |
+ |
+ -----
+*/
+
+ [62] = 0x0023,
+/*
+CHAR 94 '^'
+ -----
+ | |
+ | |
+
+
+
+
+*/
+
+ [63] = 0x2000,
+/*
+CHAR 95 '_'
+
+
+
+
+
+
+ -----
+*/
+
+ [64] = 0x0004,
+/*
+CHAR 96 '`'
+
+ \
+ \
+
+
+
+
+*/
+
+ [65] = 0x2540,
+/*
+CHAR 97 'a'
+
+
+
+ --
+ | |
+ | |
+ -----
+*/
+
+ [66] = 0x2942,
+/*
+CHAR 98 'b'
+
+ |
+ |
+ --
+ | \
+ | \
+ -----
+*/
+
+ [67] = 0x21c0,
+/*
+CHAR 99 'c'
+
+
+
+ -- --
+ |
+ |
+ -----
+*/
+
+ [68] = 0x32a0,
+/*
+CHAR 100 'd'
+
+ |
+ |
+ --
+ / |
+ / |
+ -----
+*/
+
+ [69] = 0x2340,
+/*
+CHAR 101 'e'
+
+
+
+ --
+ | /
+ |/
+ -----
+*/
+
+ [70] = 0x0143,
+/*
+CHAR 102 'f'
+ -----
+ |
+ |
+ --
+ |
+ |
+
+*/
+
+ [71] = 0x10a5,
+/*
+CHAR 103 'g'
+ -----
+ \ |
+ \ |
+ --
+ |
+ |
+
+*/
+
+ [72] = 0x11c2,
+/*
+CHAR 104 'h'
+
+ |
+ |
+ -- --
+ | |
+ | |
+
+*/
+
+ [73] = 0x0400,
+/*
+CHAR 105 'i'
+
+
+
+
+ |
+ |
+
+*/
+
+ [74] = 0x3000,
+/*
+CHAR 106 'j'
+
+
+
+
+ |
+ |
+ -----
+*/
+
+ [75] = 0x0c88,
+/*
+CHAR 107 'k'
+
+ |
+ |
+ --
+ |\
+ | \
+
+*/
+
+ [76] = 0x0408,
+/*
+CHAR 108 'l'
+
+ |
+ |
+
+ |
+ |
+
+*/
+
+ [77] = 0x15c0,
+/*
+CHAR 109 'm'
+
+
+
+ -- --
+ | | |
+ | | |
+
+*/
+
+ [78] = 0x0940,
+/*
+CHAR 110 'n'
+
+
+
+ --
+ | \
+ | \
+
+*/
+
+ [79] = 0x31c0,
+/*
+CHAR 111 'o'
+
+
+
+ -- --
+ | |
+ | |
+ -----
+*/
+
+ [80] = 0x0146,
+/*
+CHAR 112 'p'
+
+ |\
+ | \
+ --
+ |
+ |
+
+*/
+
+ [81] = 0x10b0,
+/*
+CHAR 113 'q'
+
+ /|
+ / |
+ --
+ |
+ |
+
+*/
+
+ [82] = 0x0140,
+/*
+CHAR 114 'r'
+
+
+
+ --
+ |
+ |
+
+*/
+
+ [83] = 0x2880,
+/*
+CHAR 115 's'
+
+
+
+ --
+ \
+ \
+ -----
+*/
+
+ [84] = 0x2142,
+/*
+CHAR 116 't'
+
+ |
+ |
+ --
+ |
+ |
+ -----
+*/
+
+ [85] = 0x3100,
+/*
+CHAR 117 'u'
+
+
+
+
+ | |
+ | |
+ -----
+*/
+
+ [86] = 0x0300,
+/*
+CHAR 118 'v'
+
+
+
+
+ | /
+ |/
+
+*/
+
+ [87] = 0x1b00,
+/*
+CHAR 119 'w'
+
+
+
+
+ | / \ |
+ |/ \|
+
+*/
+
+ [88] = 0x0a14,
+/*
+CHAR 120 'x'
+
+ \ /
+ \ /
+
+ / \
+ / \
+
+*/
+
+ [89] = 0x3800,
+/*
+CHAR 121 'y'
+
+
+
+
+ \ |
+ \|
+ -----
+*/
+
+ [90] = 0x2240,
+/*
+CHAR 122 'z'
+
+
+
+ --
+ /
+ /
+ -----
+*/
+
+ [91] = 0x2245,
+/*
+CHAR 123 '{'
+ -----
+ \
+ \
+ --
+ /
+ /
+ -----
+*/
+
+ [92] = 0x0408,
+/*
+CHAR 124 '|'
+
+ |
+ |
+
+ |
+ |
+
+*/
+
+ [93] = 0x2891,
+/*
+CHAR 125 '}'
+ -----
+ /
+ /
+ --
+ \
+ \
+ -----
+*/
+
+ [94] = 0x000e,
+/*
+CHAR 126 '~'
+
+ |\ |
+ | \|
+
+
+
+
+*/
+
+ [95] = 0x3fff,
+/*
+CHAR 127 'DEL'
+ -----
+ |\ | /|
+ | \|/ |
+ -- --
+ | /|\ |
+ |/ | \|
+ -----
+*/
+
}
void
-ao_led_for(AO_LED_TYPE colors, AO_LED_TYPE ticks)
+ao_led_for(AO_LED_TYPE colors, AO_TICK_TYPE ticks)
{
ao_led_on(colors);
ao_delay(ticks);
#ifndef _AO_PROFILE_H_
#define _AO_PROFILE_H_
-void ao_profile_init();
+void ao_profile_init(void);
static inline uint32_t ao_profile_tick(void) {
uint16_t hi, lo, second_hi;
}
#if HAS_SERIAL_SW_FLOW
-void
+static void
ao_serial2_cts(void)
{
_ao_usart_cts(&ao_stm_usart2);
{
return ao_tick_count;
}
+
+uint64_t
+ao_time_ns(void)
+{
+ AO_TICK_TYPE before, after;
+ uint32_t cvr;
+
+ do {
+ before = ao_tick_count;
+ cvr = stm_systick.cvr;
+ after = ao_tick_count;
+ } while (before != after);
+
+ return (uint64_t) after * (1000000000ULL / AO_HERTZ) +
+ (uint64_t) cvr * (1000000000ULL / AO_SYSTICK);
+}
+
#endif
#if AO_DATA_ALL
}
void
-stm_usb_fs_wkup(void)
+stm_usb_fs_wkup_isr(void)
{
/* USB wakeup, just clear the bit for now */
stm_usb.istr &= ~(1 << STM_USB_ISTR_WKUP);
_ao_usb_set_stat_rx(AO_USB_OUT_EPR, STM_USB_EPR_STAT_RX_VALID);
}
-int
+static int
_ao_usb_pollchar(void)
{
uint8_t c;
#define STM_MPU_RASR_SIZE_MASK 0x1f
#define STM_MPU_RASR_ENABLE 0
-#define isr(name) void stm_ ## name ## _isr(void);
-
-isr(nmi)
-isr(hardfault)
-isr(memmanage)
-isr(busfault)
-isr(usagefault)
-isr(svc)
-isr(debugmon)
-isr(pendsv)
-isr(systick)
-isr(wwdg)
-isr(pvd)
-isr(tamper_stamp)
-isr(rtc_wkup)
-isr(flash)
-isr(rcc)
-isr(exti0)
-isr(exti1)
-isr(exti2)
-isr(exti3)
-isr(exti4)
-isr(dma1_channel1)
-isr(dma1_channel2)
-isr(dma1_channel3)
-isr(dma1_channel4)
-isr(dma1_channel5)
-isr(dma1_channel6)
-isr(dma1_channel7)
-isr(adc1)
-isr(usb_hp)
-isr(usb_lp)
-isr(dac)
-isr(comp)
-isr(exti9_5)
-isr(lcd)
-isr(tim9)
-isr(tim10)
-isr(tim11)
-isr(tim2)
-isr(tim3)
-isr(tim4)
-isr(i2c1_ev)
-isr(i2c1_er)
-isr(i2c2_ev)
-isr(i2c2_er)
-isr(spi1)
-isr(spi2)
-isr(usart1)
-isr(usart2)
-isr(usart3)
-isr(exti15_10)
-isr(rtc_alarm)
-isr(usb_fs_wkup)
-isr(tim6)
-isr(tim7)
-
-#undef isr
+#define isr_decl(name) void stm_ ## name ## _isr(void)
+
+isr_decl(halt);
+isr_decl(ignore);
+
+isr_decl(nmi);
+isr_decl(hardfault);
+isr_decl(memmanage);
+isr_decl(busfault);
+isr_decl(usagefault);
+isr_decl(svc);
+isr_decl(debugmon);
+isr_decl(pendsv);
+isr_decl(systick);
+isr_decl(wwdg);
+isr_decl(pvd);
+isr_decl(tamper_stamp);
+isr_decl(rtc_wkup);
+isr_decl(flash);
+isr_decl(rcc);
+isr_decl(exti0);
+isr_decl(exti1);
+isr_decl(exti2);
+isr_decl(exti3);
+isr_decl(exti4);
+isr_decl(dma1_channel1);
+isr_decl(dma1_channel2);
+isr_decl(dma1_channel3);
+isr_decl(dma1_channel4);
+isr_decl(dma1_channel5);
+isr_decl(dma1_channel6);
+isr_decl(dma1_channel7);
+isr_decl(adc1);
+isr_decl(usb_hp);
+isr_decl(usb_lp);
+isr_decl(dac);
+isr_decl(comp);
+isr_decl(exti9_5);
+isr_decl(lcd);
+isr_decl(tim9);
+isr_decl(tim10);
+isr_decl(tim11);
+isr_decl(tim2);
+isr_decl(tim3);
+isr_decl(tim4);
+isr_decl(i2c1_ev);
+isr_decl(i2c1_er);
+isr_decl(i2c2_ev);
+isr_decl(i2c2_er);
+isr_decl(spi1);
+isr_decl(spi2);
+isr_decl(usart1);
+isr_decl(usart2);
+isr_decl(usart3);
+isr_decl(exti15_10);
+isr_decl(rtc_alarm);
+isr_decl(usb_fs_wkup);
+isr_decl(tim6);
+isr_decl(tim7);
+
+#undef isr_decl
#define STM_ISR_WWDG_POS 0
#define STM_ISR_PVD_POS 1
#define STM_TIM234_SMCR_SMS_EXTERNAL_CLOCK 7
#define STM_TIM234_SMCR_SMS_MASK 7
+#define STM_TIM234_DIER_TDE 14
+#define STM_TIM234_DIER_CC4DE 12
+#define STM_TIM234_DIER_CC3DE 11
+#define STM_TIM234_DIER_CC2DE 10
+#define STM_TIM234_DIER_CC1DE 9
+#define STM_TIM234_DIER_UDE 8
+
+#define STM_TIM234_DIER_TIE 6
#define STM_TIM234_DIER_CC4IE 4
#define STM_TIM234_DIER_CC3IE 3
#define STM_TIM234_DIER_CC2IE 2
#define STM_TIM234_CCMR1_CC1S_INPUT_TRC 3
#define STM_TIM234_CCMR1_CC1S_MASK 3
+#define STM_TIM234_CCMR1_IC2F 12
+#define STM_TIM234_CCMR1_IC2F_NONE 0
+#define STM_TIM234_CCMR1_IC2F_CK_INT_N_2 1
+#define STM_TIM234_CCMR1_IC2F_CK_INT_N_4 2
+#define STM_TIM234_CCMR1_IC2F_CK_INT_N_8 3
+#define STM_TIM234_CCMR1_IC2F_DTS_2_N_6 4
+#define STM_TIM234_CCMR1_IC2F_DTS_2_N_8 5
+#define STM_TIM234_CCMR1_IC2F_DTS_4_N_6 6
+#define STM_TIM234_CCMR1_IC2F_DTS_4_N_8 7
+#define STM_TIM234_CCMR1_IC2F_DTS_8_N_6 8
+#define STM_TIM234_CCMR1_IC2F_DTS_8_N_8 9
+#define STM_TIM234_CCMR1_IC2F_DTS_16_N_5 10
+#define STM_TIM234_CCMR1_IC2F_DTS_16_N_6 11
+#define STM_TIM234_CCMR1_IC2F_DTS_16_N_8 12
+#define STM_TIM234_CCMR1_IC2F_DTS_32_N_5 13
+#define STM_TIM234_CCMR1_IC2F_DTS_32_N_6 14
+#define STM_TIM234_CCMR1_IC2F_DTS_32_N_8 15
+#define STM_TIM234_CCMR1_IC2PSC 10
+#define STM_TIM234_CCMR1_IC2PSC_NONE 0
+#define STM_TIM234_CCMR1_IC2PSC_2 1
+#define STM_TIM234_CCMR1_IC2PSC_4 2
+#define STM_TIM234_CCMR1_IC2PSC_8 3
+#define STM_TIM234_CCMR1_IC1F 4
+#define STM_TIM234_CCMR1_IC1F_NONE 0
+#define STM_TIM234_CCMR1_IC1F_CK_INT_N_2 1
+#define STM_TIM234_CCMR1_IC1F_CK_INT_N_4 2
+#define STM_TIM234_CCMR1_IC1F_CK_INT_N_8 3
+#define STM_TIM234_CCMR1_IC1F_DTS_2_N_6 4
+#define STM_TIM234_CCMR1_IC1F_DTS_2_N_8 5
+#define STM_TIM234_CCMR1_IC1F_DTS_4_N_6 6
+#define STM_TIM234_CCMR1_IC1F_DTS_4_N_8 7
+#define STM_TIM234_CCMR1_IC1F_DTS_8_N_6 8
+#define STM_TIM234_CCMR1_IC1F_DTS_8_N_8 9
+#define STM_TIM234_CCMR1_IC1F_DTS_16_N_5 10
+#define STM_TIM234_CCMR1_IC1F_DTS_16_N_6 11
+#define STM_TIM234_CCMR1_IC1F_DTS_16_N_8 12
+#define STM_TIM234_CCMR1_IC1F_DTS_32_N_5 13
+#define STM_TIM234_CCMR1_IC1F_DTS_32_N_6 14
+#define STM_TIM234_CCMR1_IC1F_DTS_32_N_8 15
+#define STM_TIM234_CCMR1_IC1PSC 2
+#define STM_TIM234_CCMR1_IC1PSC_NONE 0
+#define STM_TIM234_CCMR1_IC1PSC_2 1
+#define STM_TIM234_CCMR1_IC1PSC_4 2
+#define STM_TIM234_CCMR1_IC1PSC_8 3
+
#define STM_TIM234_CCMR2_OC4CE 15
#define STM_TIM234_CCMR2_OC4M 12
#define STM_TIM234_CCMR2_OC4M_FROZEN 0
include ../stm32f4/Makefile-raw.defs
-aoschemelib=$(shell pkg-config --variable=aoschemelib ao-scheme)
-
-include $(aoschemelib)/Makefile-scheme
-
IDVENDOR=0xfffe
IDPRODUCT=0xfffa
PRODUCT=stm32f4-disco
ao_pins.h \
ao_task.h \
ao_product.h \
- $(SCHEME_HDRS) \
- ao_scheme_const.h \
stm32f4.h \
Makefile
ao_usb_gen.c \
ao_usb_stm32f4.c \
ao_led.c \
- ao_impure.c \
- $(SCHEME_SRCS)
+ ao_impure.c
-CFLAGS = $(STM32F4_CFLAGS) -I$(aoschemelib)
+CFLAGS = $(STM32F4_CFLAGS)
PROG=stm32f4-disco-$(VERSION)
ELF=$(PROG).elf
$(OBJ): $(INC)
-ao_product.h: ao-make-product.5c ../Version Makefile
- $(call quiet,NICKLE,$<) $< -m altusmetrum.org -V $(IDVENDOR) -s $(SERIAL) -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@
-
-SCHEME_SCHEME=\
- ao_scheme_basic_syntax.scheme \
- ao_scheme_list.scheme \
- ao_scheme_advanced_syntax.scheme \
- ao_scheme_vector.scheme \
- ao_scheme_string.scheme \
- ao_scheme_char.scheme \
- ao_scheme_number.scheme
-
-ao_scheme_const.h: ao-scheme-make-const-big $(SCHEME_SCHEME)
- $^ -o $@ -d POSIX,PORT,SAVE
-
distclean: clean
clean:
*/
#include <ao.h>
-#include <ao_scheme.h>
#include <ao_usb.h>
-static void scheme_cmd() {
- ao_scheme_read_eval_print(stdin, stdout, false);
-}
-
-static const struct ao_cmds scheme_cmds[] = {
- { scheme_cmd, "l\0Run scheme interpreter" },
- { 0, 0 }
-};
-
-int
-_ao_scheme_getc(void)
-{
- static uint8_t at_eol;
- int c;
-
- if (at_eol) {
- ao_cmd_readline(ao_scheme_read_list ? "- " : "> ");
- at_eol = 0;
- }
- c = (unsigned char) ao_cmd_lex();
- if (c == '\n')
- at_eol = 1;
- return c;
-}
-
void main(void)
{
ao_clock_init();
ao_usart_init();
ao_usb_init();
ao_cmd_init();
- ao_cmd_register(scheme_cmds);
ao_start_scheduler();
}
PRODUCT_DEF=-DALTOS_FLASH
IDPRODUCT=0x000a
-CFLAGS = $(PRODUCT_DEF) $(STM32F4_CFLAGS) -g -Os
+CFLAGS = $(PRODUCT_DEF) $(STM32F4_CFLAGS)
LDFLAGS=$(CFLAGS) -L$(TOPDIR)/stm32f4 -Wl,-Taltos-loader.ld
$(BIN): $(PROG)
$(MAKEBIN) --output=$@ --base=$(FLASH_ADDR) $(PROG)
-ao_product.h: ao-make-product.5c $(TOPDIR)/Version
- $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@
-
$(OBJ): $(INC)
distclean: clean
TOPDIR=..
endif
-include $(TOPDIR)/Makedefs
+include $(TOPDIR)/Makefile.defs
-vpath % $(TOPDIR)/stm32f4:$(TOPDIR)/product:$(TOPDIR)/drivers:$(TOPDIR)/kernel:$(TOPDIR)/util:$(TOPDIR)/kalman:$(TOPDIR)/aes:$(TOPDIR):$(TOPDIR)/math
-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
+vpath % $(TOPDIR)/stm32f4:$(AO_VPATH)
-.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)
-
-WARN_FLAGS=-Wall -Wextra -Werror -Wcast-align
-
-AO_CFLAGS=-I. -I$(TOPDIR)/stm32f4 -I$(TOPDIR)/kernel -I$(TOPDIR)/drivers \
- -Os -g \
- -I$(TOPDIR)/product -I$(TOPDIR) -I$(TOPDIR)/math \
- -isystem $(NEWLIB_NANO)/arm-none-eabi/include
-
-STM32F4_CFLAGS=-std=gnu99 -mlittle-endian -mcpu=cortex-m4 -mthumb \
- -mfloat-abi=hard -mfpu=fpv4-sp-d16 \
- -ffreestanding -nostdlib $(AO_CFLAGS) $(WARN_FLAGS)
-
-NICKLE=nickle
-
LIBS=-L$(NEWLIB_NANO)/arm-none-eabi/lib/thumb/v7e-m/fpv4-sp/hard -lc -lm -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 $@ $<
+STM32F4_CFLAGS=-mlittle-endian -mcpu=cortex-m4 -mthumb -mfloat-abi=hard \
+ -I$(TOPDIR)/stm32f4 $(AO_CFLAGS) $(NEWLIB_CFLAGS)
include $(TOPDIR)/stm32f4/Makefile-stm32f4.defs
-LOADER=flash-loader/$(PROGNAME)-altos-flash-$(VERSION).elf
-MAKEBIN=$(TOPDIR)/../ao-tools/ao-makebin/ao-makebin
-FLASH_ADDR=0x08000000
-
LDFLAGS=$(CFLAGS) -L$(TOPDIR)/stm32f4 -Wl,-Taltos.ld -n
-
-.DEFAULT_GOAL=all
#define AO_ROMCONFIG_SYMBOL __attribute__((section(".romconfig"))) const
-#define ao_arch_task_members\
- uint32_t *sp; /* saved stack pointer */
-
#define ao_arch_naked_declare __attribute__((naked))
#define ao_arch_naked_define
}
static inline void
-ao_arch_memory_barrier() {
+ao_arch_memory_barrier(void) {
asm volatile("" ::: "memory");
}
static inline void
ao_arch_init_stack(struct ao_task *task, void *start)
{
- uint32_t *sp = (uint32_t *) ((void*) task->stack + AO_STACK_SIZE);
+ uint32_t *sp = &task->stack32[AO_STACK_SIZE>>2];
uint32_t a = (uint32_t) start;
int i;
/* BASEPRI with interrupts enabled */
ARM_PUSH32(sp, 0);
- task->sp = sp;
+ task->sp32 = sp;
}
static inline void ao_arch_save_regs(void) {
static inline void ao_arch_save_stack(void) {
uint32_t *sp;
asm("mov %0,sp" : "=&r" (sp) );
- ao_cur_task->sp = (sp);
+ ao_cur_task->sp32 = (sp);
}
static inline void ao_arch_restore_stack(void) {
/* Switch stacks */
- asm("mov sp, %0" : : "r" (ao_cur_task->sp) );
+ asm("mov sp, %0" : : "r" (ao_cur_task->sp32) );
#ifdef AO_NONMASK_INTERRUPTS
/* Restore BASEPRI */
static inline void ao_enable_port(struct stm_gpio *port)
{
if ((port) == &stm_gpioa) {
- stm_rcc.ahb1enr |= (1 << STM_RCC_AHB1ENR_IOPAEN);
+ stm_rcc_ahb1_clk_enable(1 << STM_RCC_AHB1ENR_IOPAEN);
ao_power_register(&ao_power_gpioa);
} else if ((port) == &stm_gpiob) {
- stm_rcc.ahb1enr |= (1 << STM_RCC_AHB1ENR_IOPBEN);
+ stm_rcc_ahb1_clk_enable(1 << STM_RCC_AHB1ENR_IOPBEN);
ao_power_register(&ao_power_gpiob);
} else if ((port) == &stm_gpioc) {
- stm_rcc.ahb1enr |= (1 << STM_RCC_AHB1ENR_IOPCEN);
+ stm_rcc_ahb1_clk_enable(1 << STM_RCC_AHB1ENR_IOPCEN);
ao_power_register(&ao_power_gpioc);
} else if ((port) == &stm_gpiod) {
- stm_rcc.ahb1enr |= (1 << STM_RCC_AHB1ENR_IOPDEN);
+ stm_rcc_ahb1_clk_enable(1 << STM_RCC_AHB1ENR_IOPDEN);
ao_power_register(&ao_power_gpiod);
} else if ((port) == &stm_gpioe) {
- stm_rcc.ahb1enr |= (1 << STM_RCC_AHB1ENR_IOPEEN);
+ stm_rcc_ahb1_clk_enable(1 << STM_RCC_AHB1ENR_IOPEEN);
ao_power_register(&ao_power_gpioe);
} else if ((port) == &stm_gpiof) {
- stm_rcc.ahb1enr |= (1 << STM_RCC_AHB1ENR_IOPFEN);
+ stm_rcc_ahb1_clk_enable(1 << STM_RCC_AHB1ENR_IOPFEN);
ao_power_register(&ao_power_gpiof);
} else if ((port) == &stm_gpiog) {
- stm_rcc.ahb1enr |= (1 << STM_RCC_AHB1ENR_IOPGEN);
+ stm_rcc_ahb1_clk_enable(1 << STM_RCC_AHB1ENR_IOPGEN);
ao_power_register(&ao_power_gpiog);
} else if ((port) == &stm_gpioh) {
- stm_rcc.ahb1enr |= (1 << STM_RCC_AHB1ENR_IOPHEN);
+ stm_rcc_ahb1_clk_enable(1 << STM_RCC_AHB1ENR_IOPHEN);
ao_power_register(&ao_power_gpioh);
}
}
static inline void ao_disable_port(struct stm_gpio *port)
{
if ((port) == &stm_gpioa) {
- stm_rcc.ahb1enr &= ~(1 << STM_RCC_AHB1ENR_IOPAEN);
+ stm_rcc_ahb1_clk_disable(1 << STM_RCC_AHB1ENR_IOPAEN);
ao_power_unregister(&ao_power_gpioa);
} else if ((port) == &stm_gpiob) {
- stm_rcc.ahb1enr &= ~(1 << STM_RCC_AHB1ENR_IOPBEN);
+ stm_rcc_ahb1_clk_disable(1 << STM_RCC_AHB1ENR_IOPBEN);
ao_power_unregister(&ao_power_gpiob);
} else if ((port) == &stm_gpioc) {
- stm_rcc.ahb1enr &= ~(1 << STM_RCC_AHB1ENR_IOPCEN);
+ stm_rcc_ahb1_clk_disable(1 << STM_RCC_AHB1ENR_IOPCEN);
ao_power_unregister(&ao_power_gpioc);
} else if ((port) == &stm_gpiod) {
- stm_rcc.ahb1enr &= ~(1 << STM_RCC_AHB1ENR_IOPDEN);
+ stm_rcc_ahb1_clk_disable(1 << STM_RCC_AHB1ENR_IOPDEN);
ao_power_unregister(&ao_power_gpiod);
} else if ((port) == &stm_gpioe) {
- stm_rcc.ahb1enr &= ~(1 << STM_RCC_AHB1ENR_IOPEEN);
+ stm_rcc_ahb1_clk_disable(1 << STM_RCC_AHB1ENR_IOPEEN);
ao_power_unregister(&ao_power_gpioe);
} else if ((port) == &stm_gpiof) {
- stm_rcc.ahb1enr &= ~(1 << STM_RCC_AHB1ENR_IOPFEN);
+ stm_rcc_ahb1_clk_disable(1 << STM_RCC_AHB1ENR_IOPFEN);
ao_power_unregister(&ao_power_gpiof);
} else if ((port) == &stm_gpiog) {
- stm_rcc.ahb1enr &= ~(1 << STM_RCC_AHB1ENR_IOPGEN);
+ stm_rcc_ahb1_clk_disable(1 << STM_RCC_AHB1ENR_IOPGEN);
ao_power_unregister(&ao_power_gpiog);
} else if ((port) == &stm_gpioh) {
- stm_rcc.ahb1enr &= ~(1 << STM_RCC_AHB1ENR_IOPHEN);
+ stm_rcc_ahb1_clk_disable(1 << STM_RCC_AHB1ENR_IOPHEN);
ao_power_unregister(&ao_power_gpioh);
}
}
void
ao_usart_init(void);
+void
+start(void);
+
+char
+ao_serial6_getchar(void);
+
+void
+ao_serial6_putchar(char c);
+
+int
+_ao_serial6_pollchar(void);
+
+uint8_t
+_ao_serial6_sleep_for(uint16_t timeout);
+
+void
+ao_serial6_set_speed(uint32_t speed);
+
+void
+ao_serial6_drain(void);
#endif /* _AO_ARCH_FUNCS_H_ */
#define AO_EXTI_PIN_NOCONFIGURE 64
void
-ao_exti_setup(struct stm_gpio *gpio, uint8_t pin, uint8_t mode, void (*callback)());
+ao_exti_setup(struct stm_gpio *gpio, uint8_t pin, uint8_t mode, void (*callback)(void));
void
ao_exti_set_mode(struct stm_gpio *gpio, uint8_t pin, uint8_t mode);
void
-ao_exti_set_callback(struct stm_gpio *gpio, uint8_t pin, void (*callback)());
+ao_exti_set_callback(struct stm_gpio *gpio, uint8_t pin, void (*callback)(void));
void
ao_exti_enable(struct stm_gpio *gpio, uint8_t pin);
}
void
-ao_exti_set_callback(struct stm_gpio *gpio, uint8_t pin, void (*callback)()) {
+ao_exti_set_callback(struct stm_gpio *gpio, uint8_t pin, void (*callback)(void)) {
(void) gpio;
ao_exti_callback[pin] = callback;
}
#if DEBUG_THE_CLOCK
/* Output PLL clock on PA8 and SYCLK on PC9 for measurments */
- stm_rcc.ahb1enr |= ((1 << STM_RCC_AHB1ENR_IOPAEN) |
- (1 << STM_RCC_AHB1ENR_IOPCEN));
-
+ ao_enable_port(&stm_gpioa);
stm_afr_set(&stm_gpioa, 8, STM_AFR_AF0);
stm_moder_set(&stm_gpioa, 8, STM_MODER_ALTERNATE);
stm_ospeedr_set(&stm_gpioa, 8, STM_OSPEEDR_HIGH);
+ ao_enable_port(&stm_gpioc);
stm_afr_set(&stm_gpioc, 9, STM_AFR_AF0);
stm_moder_set(&stm_gpioc, 9, STM_MODER_ALTERNATE);
stm_ospeedr_set(&stm_gpioc, 9, STM_OSPEEDR_HIGH);
}
void
-stm_usb_fs_wkup(void)
+stm_otg_fs_wkup_isr(void)
{
/* USB wakeup, just clear the bit for now */
// stm_usb.istr &= ~(1 << STM_USB_ISTR_WKUP);
ao_usb_rx_pos = 0;
}
-int
+static int
_ao_usb_pollchar(void)
{
uint8_t c;
ao_usb_enable(void)
{
ao_usb_dev_enable();
-
ao_usb_configuration = 0;
}
void
ao_usb_out_interrupt(uint32_t mask);
+void
+ao_usb_int_interrupt(uint32_t mask);
+
#endif /* _AO_USB_GEN_H_ */
/* Queue IN bytes to EPn */
void
-ao_usb_dev_ep_in(uint8_t ep, const void *data, uint16_t len)
+ao_usb_dev_ep_in(uint8_t ep, const void *_data, uint16_t len)
{
+ const uint8_t *data = _data;
int l = len;
while (l > 0) {
- stm_usb.dfifo[ep].fifo = *((__packed uint32_t *) data);
+ uint32_t d;
+ memcpy(&d, data, 4);
+ stm_usb.dfifo[ep].fifo = d;
l -= 4;
data += 4;
}
/* Receive OUT bytes from EPn */
uint16_t
-ao_usb_dev_ep_out(uint8_t ep, void *data, uint16_t len)
+ao_usb_dev_ep_out(uint8_t ep, void *_data, uint16_t len)
{
+ uint8_t *data = _data;
uint16_t received;
int l = len;
uint32_t t;
received = len;
while (l >= 4) {
- *((__packed uint32_t *) data) = stm_usb.dfifo[0].fifo;
+ uint32_t d;
+ d = stm_usb.dfifo[0].fifo;
+ memcpy(data, &d, 4);
l -= 4;
data += 4;
}
ao_usb_device_init(void)
{
/* deactivate vbus sensing */
+ stm_usb.gccfg |= (1 << STM_USB_GCCFG_VBDEN);
+
stm_usb.gccfg &= ~(1 << STM_USB_GCCFG_VBDEN);
/* Force device mode */
else
stm_usb.diep[i].diepctl = 0;
stm_usb.diep[i].dieptsiz = 0;
- stm_usb.diep[i].diepint = 0xfffffffful;
+ stm_usb.diep[i].diepint = 0xffu;
+ }
+ for (int i = 0; i < 6; i++) {
/* Reset OUT endpoint */
if (stm_usb.doep[i].doepctl & (1 << STM_USB_DOEPCTL_EPENA))
stm_usb.doep[i].doepctl = ((1 << STM_USB_DOEPCTL_EPDIS) |
stm_usb.doep[i].doepctl = 0;
stm_usb.doep[i].doeptsiz = 0;
- stm_usb.doep[i].doepint = 0xfffffffful;
+ stm_usb.doep[i].doepint = 0xffu;
}
+ stm_usb.diepmsk &= ~(1 << STM_USB_DIEPMSK_TXFURM);
+
/* Disable all interrupts */
stm_usb.gintmsk = 0;
ao_usb_delay(20);
}
-#if 0
static void
ao_usb_device_disconnect(void)
{
stm_usb.dctl |= (1 << STM_USB_DCTL_SDIS);
ao_usb_delay(20);
}
-#endif
+
+static void
+ao_usb_dev_start(void)
+{
+ ao_usb_device_connect();
+ stm_usb.gahbcfg |= (1 << STM_USB_GAHBCFG_GINTMSK);
+}
void
ao_usb_dev_enable(void)
stm_afr_set(&stm_gpioa, 11, STM_AFR_AF10);
stm_ospeedr_set(&stm_gpioa, 11, STM_OSPEEDR_HIGH);
stm_pupdr_set(&stm_gpioa, 11, STM_PUPDR_NONE);
+
stm_afr_set(&stm_gpioa, 12, STM_AFR_AF10);
stm_ospeedr_set(&stm_gpioa, 12, STM_OSPEEDR_HIGH);
stm_pupdr_set(&stm_gpioa, 12, STM_PUPDR_NONE);
/* Power on USB */
- stm_rcc.ahb2enr |= (1 << STM_RCC_AHB2ENR_OTGFSEN);
+ stm_rcc_ahb2_clk_enable(1 << STM_RCC_AHB2ENR_OTGFSEN);
/* Route interrupts */
stm_nvic_set_priority(STM_ISR_OTG_FS_POS, AO_STM_NVIC_LOW_PRIORITY);
stm_nvic_set_enable(STM_ISR_OTG_FS_POS);
+ ao_arch_release_interrupts();
+
/* Core init */
ao_usb_core_init();
ao_usb_device_init();
- /* Connect */
- ao_usb_device_connect();
+ /* Disconnect */
+ ao_usb_device_disconnect();
+
+ /* Start */
+ ao_usb_dev_start();
}
void
ao_usb_dev_disable(void)
{
+ ao_usb_device_disconnect();
+
stm_usb.gusbcfg = ((1 << STM_USB_GUSBCFG_FDMOD) |
(0 << STM_USB_GUSBCFG_FHMOD) |
(6 << STM_USB_GUSBCFG_TRDT) |
stm_usb.dctl = ((0 << STM_USB_DCTL_POPRGDNE) |
(1 << STM_USB_DCTL_SDIS));
- stm_rcc.ahb2enr &= ~(1 << STM_RCC_AHB2ENR_OTGFSEN);
+ stm_rcc_ahb2_clk_disable(1 << STM_RCC_AHB2ENR_OTGFSEN);
}
void
CK48MSEL = 1 PLLI2S_Q
I2CFMP1SEL = 0 APB
}
-
-
*/
+
+/*
+ *
+ * altos clock configuration
+ * (gdb) print/x stm_rcc
+ * $8 = {
+ * altos demo firmware
+ * cr = 0x0307 7d80, 0x0f077d83,
+ *
+ * PLLI2SRDY 0 1
+ * PLLI2SON 0 1
+ * PLLRDY 1 1
+ * PLLON 1 1
+ * CSSON 0 0
+ * HSEBYP 1 1
+ * HSERDY 1 1
+ * HSEON 1 1
+ * HSICAL 0x7d 0x7d
+ * HSITRIM 0x10 0x10
+ * HSIRDY 0 1
+ * HSION 0 1
+ *
+ * pllcfgr = 0x24403008, 0x27403208,
+ * PLLR 2 2
+ * PLLQ 4 7
+ * PLLSRC 1 1
+ * PLLP 0 (/2) 0 (/2)
+ * PLLN 192 200
+ * PLLM 8 8
+ *
+ * cfgr = 0x3640100a, 0x0000100a,
+ * upper bits are just MCO
+ *
+ * cir = 0x0, 0x0
+ * ahb1rstr = 0x0, 0x0
+ * ahb2rstr = 0x0, 0x0
+ * ahb3rstr = 0x0,
+ * pad_1c = 0x0,
+ * apb1rstr = 0x0,
+ * apb2rstr = 0x0,
+ * pad_28 = 0x0,
+ * pad_2c = 0x0,
+ * _ahb1enr = 0x55, 0x80
+ * _ahb2enr = 0x80, 0xc800
+ * ahbdnr = 0x0,
+ * pad_3c = 0x0,
+ * apb1enr = 0x10000400,
+ * apb2enr = 0x8020,
+ * pad_48 = 0x0,
+ * pad_4c = 0x0,
+ * ahb1lpenr = 0x6390ff, 0x6390ff
+ * ahb2lpenr = 0xd0, 0xd0
+ * ahb3lpenr = 0x3, 0x3
+ * pad_5c = 0x0,
+ * apb1lpenr = 0xfffecfff, 0xfffecfff,
+ * apb2lpenr = 0x357f9f3, 0x357f9f3,
+ * pad_68 = 0x0,
+ * pad_6c = 0x0,
+ * bdcr = 0x0, 0x8200,
+ * csr = 0x0, 0x1e000003,
+ * pad_78 = 0x0,
+ * pad_7c = 0x0,
+ * sscgr = 0x0,
+ * plli2scfgr = 0x24003010, 0x44003008,
+ * pad_88 = 0x0,
+ * dckcfgr = 0x0,
+ * ckgatenr = 0x0,
+ * dckcfgr2 = 0x8000000 0x08000000
+ * }
+ *
+ *
+ */
+
+/*
+ *
+ * main
+ * HAL_Init
+ * SystemClock_Config
+ *
+ * USBD_Init
+ * USBD_LL_Init
+ * HAL_PCD_Init
+ * HAL_PCD_MspInit
+ * __HAL_RCC_GPIOA_CLK_ENABLE
+ * HAL_GPIO_Init
+ * __HAL_RCC_USB_OTG_FS_CLK_ENABLE
+ * HAL_NVIC_SetPriority
+ * HAL_NVIC_EnableIRQ
+ * USB_CoreInit
+ * Select FS Embedded PHY
+ * USB_CoreReset
+ * Deactivate the power down
+ * USB_SetCurrentMode
+ * USB_DevInit
+ * VBUS sensing stuff
+ * Restart PHY clock
+ * USB_SetDevSpeed
+ * USB_FlushTxFifo
+ * USB_FlushRxFifo
+ * Clear pending interrupts
+ * Disable all endpoints
+ * Disable all interrupts
+ * Clear pending interrupts
+ * enable interrupts
+ * USB_DevDisconnect
+ * Turn on SDIS bit
+ * delay 3ms
+ * HAL_PCDEx_SeRxFifo
+ * HAL_PCDEx_SetTxFifo
+ * USBD_RegisterClass
+ * USBD_MSC_RegisterStorage
+ * USBD_Start
+ * USBD_LL_Start
+ * HAL_PCD_Start
+ * __HAL_LOCK
+ * USB_DevConnect
+ * Turn off SDIS bit
+ * delay 3ms
+ * __HAL_PCD_ENABLE
+ * USB_EnableGlobalInt
+ * USBx->GAHBCFG |= USB_OTG_GAHBCFG_GINT;
+ * __HAL_UNLOCK
+ *
+ */
vuint32_t pad_28;
vuint32_t pad_2c;
- vuint32_t ahb1enr;
- vuint32_t ahb2enr;
+ vuint32_t _ahb1enr;
+ vuint32_t _ahb2enr;
vuint32_t ahbdnr;
vuint32_t pad_3c;
#define STM_RCC_DCKCFGR2_SDIOSEL_CK_48MHZ 0
#define STM_RCC_DCKCFGR2_SDIOSEL_SYSTEM_CLOCK 1
#define STM_RCC_DCKCFGR2_CK48MSEL 27
-#define STM_RCC_DCKCFGR2_CK48MSEL_PLL_Q 1
+#define STM_RCC_DCKCFGR2_CK48MSEL_PLL_Q 0
#define STM_RCC_DCKCFGR2_CK48MSEL_PLLI2S_Q 1
#define STM_RCC_DCKCFGR2_I2CFMP1SEL 22
#define STM_RCC_DCKCFGR2_I2CFMP1SEL_APB 0
#define STM_RCC_DCKCFGR2_I2CFMP1SEL_HSI 2
#define STM_RCC_DCKCFGR2_I2CFMP1SEL_APB_ALSO 3
+static inline void
+stm_rcc_ahb1_clk_enable(uint32_t bit)
+{
+ stm_rcc._ahb1enr |= bit;
+ uint32_t value = stm_rcc._ahb1enr;
+ (void) value;
+}
+
+static inline void
+stm_rcc_ahb1_clk_disable(uint32_t bit)
+{
+ stm_rcc._ahb1enr &= ~bit;
+ uint32_t value = stm_rcc._ahb1enr;
+ (void) value;
+}
+
+static inline void
+stm_rcc_ahb2_clk_enable(uint32_t bit)
+{
+ stm_rcc._ahb2enr |= bit;
+ uint32_t value = stm_rcc._ahb2enr;
+ (void) value;
+}
+
+static inline void
+stm_rcc_ahb2_clk_disable(uint32_t bit)
+{
+ stm_rcc._ahb2enr &= ~bit;
+ uint32_t value = stm_rcc._ahb2enr;
+ (void) value;
+}
+
struct stm_ictr {
vuint32_t ictr;
};
#define isr(name) void stm_ ## name ## _isr(void)
+isr(halt);
+isr(ignore);
isr(nmi);
isr(hardfault);
isr(memmanage);
PRODUCT_DEF=-DALTOS_FLASH
IDPRODUCT=0x000a
-CFLAGS = $(PRODUCT_DEF) $(STMF0_CFLAGS) -g -Os
+CFLAGS = $(PRODUCT_DEF) $(STMF0_CFLAGS)
LDFLAGS=$(CFLAGS) -L$(TOPDIR)/stmf0 -Wl,-Taltos-loader.ld
$(BIN): $(PROG)
$(MAKEBIN) --output=$@ --base=$(FLASH_ADDR) $(PROG)
-
-ao_product.h: ao-make-product.5c $(TOPDIR)/Version
- $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@
$(OBJ): $(INC)
TOPDIR=..
endif
-include $(TOPDIR)/Makedefs
+include $(TOPDIR)/Makefile.defs
-vpath % $(TOPDIR)/stmf0:$(TOPDIR)/product:$(TOPDIR)/drivers:$(TOPDIR)/kernel:$(TOPDIR)/util:$(TOPDIR)/kalman:$(TOPDIR)/aes:$(TOPDIR):$(TOPDIR)/math
-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
+vpath % $(TOPDIR)/stmf0:$(AO_VPATH)
-.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)
-WARN_FLAGS=-Wall -Wextra -Werror -Wcast-align
-
-AO_CFLAGS=-I. -I$(TOPDIR)/stmf0 -I$(TOPDIR)/kernel -I$(TOPDIR)/drivers \
- -DNEWLIB_INTEGER_PRINTF_SCANF \
- -I$(TOPDIR)/product -I$(TOPDIR) -I$(TOPDIR)/math \
- -isystem $(NEWLIB_NANO)/arm-none-eabi/include
-
-STMF0_CFLAGS=-std=gnu99 -mlittle-endian -mcpu=cortex-m0 -mthumb\
- -ffreestanding -nostdlib $(AO_CFLAGS) $(WARN_FLAGS)
-
-NICKLE=nickle
+STMF0_CFLAGS=-mlittle-endian -mcpu=cortex-m0 -mthumb\
+ -I$(TOPDIR)/stmf0 $(AO_CFLAGS) $(NEWLIB_CFLAGS)
LIBS=-L$(NEWLIB_NANO)/arm-none-eabi/lib/thumb/v6-m -lc -lm -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 $@ $<
include $(TOPDIR)/stmf0/Makefile-stmf0.defs
+LDFLAGS=$(CFLAGS) -L$(TOPDIR)/stmf0 -Wl,-Taltos.ld -n
+
LOADER=flash-loader/$(PROGNAME)-altos-flash-$(VERSION).elf
MAKEBIN=$(TOPDIR)/../ao-tools/ao-makebin/ao-makebin
FLASH_ADDR=0x08000000
-LDFLAGS=$(CFLAGS) -L$(TOPDIR)/stmf0 -Wl,-Taltos.ld -n
-
.DEFAULT_GOAL=all
#define AO_LED_TYPE uint16_t
-#ifndef AO_TICK_TYPE
-#define AO_TICK_TYPE uint16_t
-#define AO_TICK_SIGNED int16_t
-#endif
-
#define AO_PORT_TYPE uint16_t
/* Various definitions to make GCC look more like SDCC */
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")
extern const uint32_t ao_radio_cal;
void
-ao_adc_init();
+ao_adc_init(void);
/* ADC maximum reported value */
#define AO_ADC_MAX 4095
}
static inline void
-ao_arch_memory_barrier() {
+ao_arch_memory_barrier(void) {
asm volatile("" ::: "memory");
}
static inline void
ao_arch_init_stack(struct ao_task *task, void *start)
{
- uint32_t *sp = (uint32_t *) ((void *) task->stack + AO_STACK_SIZE);
+ uint32_t *sp = &task->stack32[AO_STACK_SIZE >> 2];
uint32_t a = (uint32_t) start;
int i;
/* PRIMASK with interrupts enabled */
ARM_PUSH32(sp, 0);
- task->sp = sp;
+ task->sp32 = sp;
}
static inline void ao_arch_save_regs(void) {
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_cur_task->sp32 = (sp);
+ if (sp < &ao_cur_task->stack32[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) );
+ asm("mov sp, %0" : : "r" (ao_cur_task->sp32) );
/* Restore PRIMASK */
asm("pop {r0}");
asm("pop {r0-r7,pc}\n");
}
+static inline void ao_sleep_mode(void) {
+
+ /*
+ WFI (Wait for Interrupt) or WFE (Wait for Event) while:
+ – Set SLEEPDEEP in Cortex ® -M0 System Control register
+ – Set PDDS bit in Power Control register (PWR_CR)
+ – Clear WUF bit in Power Control/Status register (PWR_CSR)
+ */
+
+ ao_arch_block_interrupts();
+
+ /* Enable power interface clock */
+ stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_PWREN);
+ ao_arch_nop();
+ stm_scb.scr |= (1 << STM_SCB_SCR_SLEEPDEEP);
+ ao_arch_nop();
+ stm_pwr.cr |= (1 << STM_PWR_CR_PDDS) | (1 << STM_PWR_CR_LPDS);
+ ao_arch_nop();
+ stm_pwr.cr |= (1 << STM_PWR_CR_CWUF);
+ ao_arch_nop();
+ ao_arch_nop();
+ ao_arch_nop();
+ ao_arch_nop();
+ ao_arch_nop();
+ asm("wfi");
+ ao_arch_nop();
+}
+
#ifndef HAS_SAMPLE_PROFILE
#define HAS_SAMPLE_PROFILE 0
#endif
ao_usb_write2(uint16_t len);
#endif /* AO_USB_DIRECTIO */
+void start(void);
+
+void
+ao_debug_out(char c);
+
#endif /* _AO_ARCH_FUNCS_H_ */
ch_mask(STM_DMA_INDEX(3)));
}
-void stm_dma1_ch4_5_6_isr(void) {
+void stm_dma_ch4_5_6_isr(void) {
ao_dma_isr(STM_DMA_INDEX(4), STM_DMA_INDEX(6),
ch_mask(STM_DMA_INDEX(4)) |
ch_mask(STM_DMA_INDEX(5)) |
ao_exti_set_mode(struct stm_gpio *gpio, uint8_t pin, uint8_t mode);
void
-ao_exti_set_callback(struct stm_gpio *gpio, uint8_t pin, void (*callback)());
+ao_exti_set_callback(struct stm_gpio *gpio, uint8_t pin, void (*callback)(void));
void
ao_exti_enable(struct stm_gpio *gpio, uint8_t pin);
}
void
-ao_exti_set_callback(struct stm_gpio *gpio, uint8_t pin, void (*callback)()) {
+ao_exti_set_callback(struct stm_gpio *gpio, uint8_t pin, void (*callback)(void)) {
(void) gpio;
ao_exti_callback[pin] = callback;
}
isr(cec_can)
isr(usb)
+#undef isr
+#undef isr_halt
+
#define i(addr,name) [(addr)/4] = stm_ ## name ## _isr
__attribute__ ((section(".interrupt")))
}
#endif
+void
+ao_serial_shutdown(void)
+{
+#if HAS_SERIAL_1
+ stm_rcc.apb2enr &= ~(1 << STM_RCC_APB2ENR_USART1EN);
+#endif
+#if HAS_SERIAL_2
+ stm_rcc.apb1enr &= ~(1 << STM_RCC_APB1ENR_USART2EN);
+#endif
+}
+
void
ao_serial_init(void)
{
uint8_t id = AO_SPI_INDEX(spi_index);
struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
+ switch (id) {
+#if SPI_1_POWER_MANAGE
+ case 0:
+ stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_SPI1EN);
+ break;
+#endif
+#if SPI_2_POWER_MANAGE
+ case 1:
+ stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_SPI2EN);
+ break;
+#endif
+ }
if (spi_index != ao_spi_index[id]) {
/* Disable old config
struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
stm_spi->cr1 = 0;
+ switch (id) {
+#if SPI_1_POWER_MANAGE
+ case 0:
+ stm_rcc.apb2enr &= ~(1 << STM_RCC_APB2ENR_SPI1EN);
+ break;
+#endif
+#if SPI_2_POWER_MANAGE
+ case 1:
+ stm_rcc.apb1enr &= ~(1 << STM_RCC_APB1ENR_SPI2EN);
+ break;
+#endif
+ }
ao_mutex_put(&ao_spi_mutex[id]);
}
stm_flash.cr &= ~(1 << STM_FLASH_CR_PG);
}
+static bool
+ao_storage_is_erased(uint32_t pos)
+{
+ uint16_t *flash = _ao_flash_addr(pos);
+ uint32_t i = ao_storage_block >> 1;
+
+ while (i--)
+ if (*flash++ != 0xffff)
+ return false;
+ return true;
+}
+
uint8_t
ao_storage_erase(uint32_t pos)
{
+ if (ao_storage_is_erased(pos))
+ return 1;
+
ao_arch_block_interrupts();
ao_flash_unlock();
return ao_tick_count;
}
+uint64_t
+ao_time_ns(void)
+{
+ AO_TICK_TYPE before, after;
+ uint32_t cvr;
+
+ do {
+ before = ao_tick_count;
+ cvr = stm_systick.cvr;
+ after = ao_tick_count;
+ } while (before != after);
+
+ return (uint64_t) after * (1000000000ULL / AO_HERTZ) +
+ (uint64_t) cvr * (1000000000ULL / AO_SYSTICK);
+}
+
#if AO_DATA_ALL
volatile uint8_t ao_data_interval = 1;
volatile uint8_t ao_data_count;
/* Enable 1 wait state so the CPU can run at 48MHz */
stm_flash.acr |= (STM_FLASH_ACR_LATENCY_1 << STM_FLASH_ACR_LATENCY);
- /* Enable power interface clock */
- stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_PWREN);
-
/* HCLK to 48MHz -> AHB prescaler = /1 */
cfgr = stm_rcc.cfgr;
cfgr &= ~(STM_RCC_CFGR_HPRE_MASK << STM_RCC_CFGR_HPRE);
* Set current device address and mark the
* interface as active
*/
-void
+static void
ao_usb_set_address(uint8_t address)
{
debug("ao_usb_set_address %02x\n", address);
}
#if AO_POWER_MANAGEMENT
-void
+static void
ao_usb_suspend(void)
{
stm_usb.cntr |= (1 << STM_USB_CNTR_FSUSP);
ao_clock_suspend();
}
-void
+static void
ao_usb_wakeup(void)
{
ao_clock_resume();
_rx_dbg1("out_recv count", ao_usb_rx_count);
}
-int
+static int
_ao_usb_pollchar(void)
{
uint8_t c;
extern struct stm_pwr stm_pwr;
+#define stm_pwr (*(struct stm_pwr *) 0x40007000)
+
#define STM_PWR_CR_DBP (8)
#define STM_PWR_CR_PLS (5)
#define STM_PWR_CR_CSBF (3)
#define STM_PWR_CR_CWUF (2)
#define STM_PWR_CR_PDDS (1)
-#define STM_PWR_CR_LPSDSR (0)
+#define STM_PWR_CR_LPDS (0)
#define STM_PWR_CSR_EWUP3 (10)
#define STM_PWR_CSR_EWUP2 (9)
extern struct stm_scb stm_scb;
+#define stm_scb (*(struct stm_scb *) 0xe000ed00)
+
#define STM_SCB_AIRCR_VECTKEY 16
#define STM_SCB_AIRCR_VECTKEY_KEY 0x05fa
#define STM_SCB_AIRCR_PRIGROUP 8
#define STM_SCB_AIRCR_VECTCLRACTIVE 1
#define STM_SCB_AIRCR_VECTRESET 0
-#define isr(name) void stm_ ## name ## _isr(void);
-
-isr(nmi)
-isr(hardfault)
-isr(memmanage)
-isr(busfault)
-isr(usagefault)
-isr(svc)
-isr(debugmon)
-isr(pendsv)
-isr(systick)
-isr(wwdg)
-isr(pvd)
-isr(tamper_stamp)
-isr(rtc_wkup)
-isr(flash)
-isr(rcc)
-isr(exti0)
-isr(exti1)
-isr(exti2)
-isr(exti3)
-isr(exti4)
-isr(dma1_channel1)
-isr(dma1_channel2)
-isr(dma1_channel3)
-isr(dma1_channel4)
-isr(dma1_channel5)
-isr(dma1_channel6)
-isr(dma1_channel7)
-isr(adc1)
-isr(usb_hp)
-isr(usb_lp)
-isr(dac)
-isr(comp)
-isr(exti9_5)
-isr(lcd)
-isr(tim9)
-isr(tim10)
-isr(tim11)
-isr(tim2)
-isr(tim3)
-isr(tim4)
-isr(i2c1_ev)
-isr(i2c1_er)
-isr(i2c2_ev)
-isr(i2c2_er)
-isr(spi1)
-isr(spi2)
-isr(usart1)
-isr(usart2)
-isr(usart3)
-isr(exti15_10)
-isr(rtc_alarm)
-isr(usb_fs_wkup)
-isr(tim6)
-isr(tim7)
-
-#undef isr
+#define STM_SCB_SCR_SEVONPEND 4
+#define STM_SCB_SCR_SLEEPDEEP 2
+#define STM_SCB_SCR_SLEEPONEXIT 1
#define STM_ISR_WWDG_POS 0
#define STM_ISR_PVD_VDDIO2_POS 1
extern struct stm_usart stm_usart1;
extern struct stm_usart stm_usart2;
+#define isr_decl(name) \
+ void stm_ ## name ## _isr(void)
+
+isr_decl(halt);
+isr_decl(ignore);
+isr_decl(nmi);
+isr_decl(hardfault);
+isr_decl(memmanage);
+isr_decl(busfault);
+isr_decl(usagefault);
+isr_decl(svc);
+isr_decl(debugmon);
+isr_decl(pendsv);
+isr_decl(systick);
+isr_decl(wwdg);
+isr_decl(pvd);
+isr_decl(rtc);
+isr_decl(flash);
+isr_decl(rcc_crs);
+isr_decl(exti0_1);
+isr_decl(exti2_3);
+isr_decl(exti4_15);
+isr_decl(tsc);
+isr_decl(dma_ch1);
+isr_decl(dma_ch2_3);
+isr_decl(dma_ch4_5_6);
+isr_decl(adc_comp);
+isr_decl(tim1_brk_up_trg_com);
+isr_decl(tim1_cc);
+isr_decl(tim2);
+isr_decl(tim3);
+isr_decl(tim6_dac);
+isr_decl(tim7);
+isr_decl(tim14);
+isr_decl(tim15);
+isr_decl(tim16);
+isr_decl(tim17);
+isr_decl(i2c1);
+isr_decl(i2c2);
+isr_decl(spi1);
+isr_decl(spi2);
+isr_decl(usart1);
+isr_decl(usart2);
+isr_decl(usart3_4_5_6_7_8);
+isr_decl(cec_can);
+isr_decl(usb);
+
#endif /* _STM32F0_H_ */
PRODUCT_DEF=-DTELEMETRUM_V_2_0
IDPRODUCT=0x000b
-CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF) -Os -g
+CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF)
PROGNAME=teleballoon-v2.0
PROG=$(PROGNAME)-$(VERSION).elf
all: $(PROG) $(HEX)
$(PROG): Makefile $(OBJ) altos.ld
- $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
-
-../altitude-pa.h: make-altitude-pa
- nickle $< > $@
+ $(call quiet,CC) $(LDFLAGS) -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:
PRODUCT_DEF=-DTELEBT_V_3_0
IDPRODUCT=0x000e
-CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF) -Os -g
+CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF)
PROGNAME=telebt-v3.0
PROG=$(PROGNAME)-$(VERSION).elf
all: $(PROG) $(HEX)
$(PROG): Makefile $(OBJ) altos.ld
- $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
+ $(call quiet,CC) $(LDFLAGS) -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:
PRODUCT_DEF=-DTELEBT_V_4_0
IDPRODUCT=0x000e
-CFLAGS = $(PRODUCT_DEF) $(STMF0_CFLAGS) -Os -g
+CFLAGS = $(PRODUCT_DEF) $(STMF0_CFLAGS)
PROGNAME=telebt-v4.0
PROG=$(PROGNAME)-$(VERSION).elf
all: $(PROG) $(HEX)
$(PROG): Makefile $(OBJ) altos.ld
- $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
+ $(call quiet,CC) $(LDFLAGS) -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:
PRODUCT_DEF=-DTELEDONGLE
IDPRODUCT=0x000c
-CFLAGS = $(PRODUCT_DEF) $(LPC_CFLAGS) -Os -g
+CFLAGS = $(PRODUCT_DEF) $(LPC_CFLAGS)
PROGNAME=teledongle-v3.0
PROG=$(PROGNAME)-$(VERSION).elf
all: $(PROG) $(HEX)
$(PROG): Makefile $(OBJ) altos.ld
- $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
+ $(call quiet,CC) $(LDFLAGS) -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) > $@
-
load: $(PROG)
lpc-load $(PROG)
PRODUCT_DEF=-DTELEFIREEIGHT_V_1_0
IDPRODUCT=0x000f
-CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) -Os -g
+CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF)
PROGNAME = telefireeight-v1.0
PROG = $(PROGNAME)-$(VERSION).elf
all: $(PROG) $(HEX)
$(PROG): Makefile $(OBJ) altos.ld
- $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
+ $(call quiet,CC) $(LDFLAGS) -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:
#include <ao_exti.h>
#include <ao_radio_cmac_cmd.h>
-void
+int
main(void)
{
ao_clock_init();
--- /dev/null
+telefireeight-*
+ao_product.h
--- /dev/null
+#
+# TeleFire build file
+#
+
+include ../stm/Makefile.defs
+
+INC = \
+ ao.h \
+ ao_pins.h \
+ ao_arch.h \
+ ao_arch_funcs.h \
+ ao_pad.h \
+ ao_product.h \
+ ao_radio_spi.h \
+ ao_radio_cmac.h \
+ ao_cc1200_CC1200.h \
+ ao_cc1200.h \
+ stm32l.h
+#
+# Common AltOS sources
+#
+
+#PROFILE=ao_profile.c
+#PROFILE_DEF=-DAO_PROFILE=1
+
+ALTOS_SRC = \
+ ao_boot_chain.c \
+ ao_interrupt.c \
+ ao_product.c \
+ ao_romconfig.c \
+ ao_cmd.c \
+ ao_adc_stm.c \
+ ao_data.c \
+ ao_config.c \
+ ao_task.c \
+ ao_led.c \
+ ao_stdio.c \
+ ao_panic.c \
+ ao_timer.c \
+ ao_mutex.c \
+ ao_freq.c \
+ ao_dma_stm.c \
+ ao_spi_stm.c \
+ ao_eeprom_stm.c \
+ ao_usb_stm.c \
+ ao_exti_stm.c \
+ ao_cc1200.c \
+ ao_radio_cmac.c \
+ ao_aes.c \
+ ao_aes_tables.c \
+ ao_pad.c \
+ ao_radio_cmac_cmd.c
+
+PRODUCT_SRC = \
+ ao_telefireeight.c
+
+PRODUCT=TeleFireEight-v2.0
+PRODUCT_DEF=-DTELEFIREEIGHT_V_2_0
+IDPRODUCT=0x000f
+
+CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF)
+
+PROGNAME = telefireeight-v2.0
+PROG = $(PROGNAME)-$(VERSION).elf
+HEX = $(PROGNAME)-$(VERSION).ihx
+
+SRC = $(ALTOS_SRC) $(PRODUCT_SRC)
+OBJ=$(SRC:.c=.o)
+
+all: $(PROG) $(HEX)
+
+$(PROG): Makefile $(OBJ) altos.ld
+ $(call quiet,CC) $(LDFLAGS) -o $(PROG) $(OBJ) $(LIBS)
+
+$(OBJ): $(INC)
+
+distclean: clean
+
+clean:
+ rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx $(PROGNAME).map
+ rm -f ao_product.h
+
+install:
+
+uninstall:
+
--- /dev/null
+/*
+ * Copyright © 2019 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.
+ */
+
+#ifndef _AO_PINS_H_
+#define _AO_PINS_H_
+
+#define HAS_RADIO 1
+#define HAS_RADIO_RATE 1
+#define HAS_TELEMETRY 0
+#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 AO_DATA_RING 32
+#define USE_EEPROM_CONFIG 1
+#define USE_STORAGE_CONFIG 0
+#define HAS_AES 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)
+
+#define AO_CC1200_FOSC 40000000
+
+/* 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_SPI_1 1
+#define SPI_1_PA5_PA6_PA7 0
+#define SPI_1_PB3_PB4_PB5 0
+#define SPI_1_PE13_PE14_PE15 1
+#define SPI_1_GPIO (&stm_gpioe)
+#define SPI_1_OSPEEDR STM_OSPEEDR_10MHz
+
+#define HAS_SPI_2 0
+#define SPI_2_PB13_PB14_PB15 0
+#define SPI_2_PD1_PD3_PD4 0
+
+#define HAS_I2C_1 0
+
+#define HAS_I2C_2 0
+
+/*
+ * Radio is a cc1200 connected via SPI
+ */
+
+#define AO_RADIO_CAL_DEFAULT 5695733
+
+#define AO_CC1200_SPI_CS_PORT (&stm_gpioe)
+#define AO_CC1200_SPI_CS_PIN 11
+#define AO_CC1200_SPI_BUS AO_SPI_1_PE13_PE14_PE15
+#define AO_CC1200_SPI stm_spi1
+#define AO_CC1200_SPI_SPEED AO_SPI_SPEED_FAST
+
+#define AO_CC1200_INT_PORT (&stm_gpioe)
+#define AO_CC1200_INT_PIN (12)
+
+#define AO_CC1200_INT_GPIO 2
+#define AO_CC1200_INT_GPIO_IOCFG CC1200_IOCFG2
+
+#define HAS_LED 1
+#define LED_TYPE uint16_t
+
+/* Continuity leds 1-8 */
+#define LED_0_PORT (&stm_gpiob)
+#define LED_0_PIN 13
+#define LED_1_PORT (&stm_gpiob)
+#define LED_1_PIN 12
+#define LED_2_PORT (&stm_gpiob)
+#define LED_2_PIN 11
+#define LED_3_PORT (&stm_gpiob)
+#define LED_3_PIN 10
+#define LED_4_PORT (&stm_gpioc)
+#define LED_4_PIN 9
+#define LED_5_PORT (&stm_gpioa)
+#define LED_5_PIN 8
+#define LED_6_PORT (&stm_gpioa)
+#define LED_6_PIN 9
+#define LED_7_PORT (&stm_gpioa)
+#define LED_7_PIN 10
+
+#define AO_LED_CONTINUITY(c) (1 << (c))
+#define AO_LED_CONTINUITY_MASK (0xff)
+
+/* ARM */
+#define LED_8_PORT (&stm_gpioe)
+#define LED_8_PIN 3
+
+#define AO_LED_ARMED AO_LED_8
+
+/* RF good/marginal/poor */
+#define LED_9_PORT (&stm_gpioe)
+#define LED_9_PIN 4
+#define LED_10_PORT (&stm_gpioe)
+#define LED_10_PIN 5
+#define LED_11_PORT (&stm_gpioe)
+#define LED_11_PIN 6
+
+#define AO_LED_GREEN AO_LED_9
+#define AO_LED_AMBER AO_LED_10
+#define AO_LED_RED AO_LED_11
+
+/* Alarm A */
+#define AO_SIREN
+#define AO_SIREN_PORT (&stm_gpiod)
+#define AO_SIREN_PIN 10
+
+/* Alarm B */
+#define AO_STROBE
+#define AO_STROBE_PORT (&stm_gpiod)
+#define AO_STROBE_PIN 11
+
+/* Pad selector is on PD0-7 */
+
+#define HAS_FIXED_PAD_BOX 1
+#define AO_PAD_SELECTOR_PORT (&stm_gpiod)
+#define AO_PAD_SELECTOR_PINS (0xff)
+
+#define SPI_CONST 0x00
+
+#define AO_PAD_NUM 8
+#define AO_PAD_PORT_0 (&stm_gpiod)
+#define AO_PAD_PORT_1 (&stm_gpiob)
+
+#define AO_PAD_PIN_0 9
+#define AO_PAD_0_PORT (&stm_gpiod)
+#define AO_ADC_SENSE_PAD_0 3
+#define AO_ADC_SENSE_PAD_0_PORT (&stm_gpioa)
+#define AO_ADC_SENSE_PAD_0_PIN 3
+
+#define AO_PAD_PIN_1 8
+#define AO_PAD_1_PORT (&stm_gpiod)
+#define AO_ADC_SENSE_PAD_1 2
+#define AO_ADC_SENSE_PAD_1_PORT (&stm_gpioa)
+#define AO_ADC_SENSE_PAD_1_PIN 2
+
+#define AO_PAD_PIN_2 15
+#define AO_PAD_2_PORT (&stm_gpiob)
+#define AO_ADC_SENSE_PAD_2 1
+#define AO_ADC_SENSE_PAD_2_PORT (&stm_gpioa)
+#define AO_ADC_SENSE_PAD_2_PIN 1
+
+#define AO_PAD_PIN_3 14
+#define AO_PAD_3_PORT (&stm_gpiob)
+#define AO_ADC_SENSE_PAD_3 0
+#define AO_ADC_SENSE_PAD_3_PORT (&stm_gpioa)
+#define AO_ADC_SENSE_PAD_3_PIN 0
+
+#define AO_PAD_PIN_4 12
+#define AO_PAD_4_PORT (&stm_gpiod)
+#define AO_ADC_SENSE_PAD_4 7
+#define AO_ADC_SENSE_PAD_4_PORT (&stm_gpioa)
+#define AO_ADC_SENSE_PAD_4_PIN 7
+
+#define AO_PAD_PIN_5 13
+#define AO_PAD_5_PORT (&stm_gpiod)
+#define AO_ADC_SENSE_PAD_5 6
+#define AO_ADC_SENSE_PAD_5_PORT (&stm_gpioa)
+#define AO_ADC_SENSE_PAD_5_PIN 6
+
+#define AO_PAD_PIN_6 14
+#define AO_PAD_6_PORT (&stm_gpiod)
+#define AO_ADC_SENSE_PAD_6 5
+#define AO_ADC_SENSE_PAD_6_PORT (&stm_gpioa)
+#define AO_ADC_SENSE_PAD_6_PIN 5
+
+#define AO_PAD_PIN_7 15
+#define AO_PAD_7_PORT (&stm_gpiod)
+#define AO_ADC_SENSE_PAD_7 4
+#define AO_ADC_SENSE_PAD_7_PORT (&stm_gpioa)
+#define AO_ADC_SENSE_PAD_7_PIN 4
+
+#define AO_ADC_PYRO 8
+#define AO_ADC_PYRO_PORT (&stm_gpiob)
+#define AO_ADC_PYRO_PIN 0
+
+#define AO_ADC_BATT 15
+#define AO_ADC_BATT_PORT (&stm_gpioc)
+#define AO_ADC_BATT_PIN 5
+
+#define AO_ADC_PIN0_PORT AO_ADC_SENSE_PAD_0_PORT
+#define AO_ADC_PIN0_PIN AO_ADC_SENSE_PAD_0_PIN
+
+#define AO_ADC_PIN1_PORT AO_ADC_SENSE_PAD_1_PORT
+#define AO_ADC_PIN1_PIN AO_ADC_SENSE_PAD_1_PIN
+
+#define AO_ADC_PIN2_PORT AO_ADC_SENSE_PAD_2_PORT
+#define AO_ADC_PIN2_PIN AO_ADC_SENSE_PAD_2_PIN
+
+#define AO_ADC_PIN3_PORT AO_ADC_SENSE_PAD_3_PORT
+#define AO_ADC_PIN3_PIN AO_ADC_SENSE_PAD_3_PIN
+
+#define AO_ADC_PIN4_PORT AO_ADC_SENSE_PAD_4_PORT
+#define AO_ADC_PIN4_PIN AO_ADC_SENSE_PAD_4_PIN
+
+#define AO_ADC_PIN5_PORT AO_ADC_SENSE_PAD_5_PORT
+#define AO_ADC_PIN5_PIN AO_ADC_SENSE_PAD_5_PIN
+
+#define AO_ADC_PIN6_PORT AO_ADC_SENSE_PAD_6_PORT
+#define AO_ADC_PIN6_PIN AO_ADC_SENSE_PAD_6_PIN
+
+#define AO_ADC_PIN7_PORT AO_ADC_SENSE_PAD_7_PORT
+#define AO_ADC_PIN7_PIN AO_ADC_SENSE_PAD_7_PIN
+
+#define AO_ADC_PIN8_PORT AO_ADC_PYRO_PORT
+#define AO_ADC_PIN8_PIN AO_ADC_PYRO_PIN
+
+#define AO_ADC_PIN9_PORT AO_ADC_BATT_PORT
+#define AO_ADC_PIN9_PIN AO_ADC_BATT_PIN
+
+#define AO_PAD_ALL_CHANNELS (0xff)
+
+/* 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_ADC_FIRST_PIN 0
+
+#define AO_NUM_ADC 10
+
+#define AO_ADC_SQ1 AO_ADC_SENSE_PAD_0
+#define AO_ADC_SQ2 AO_ADC_SENSE_PAD_1
+#define AO_ADC_SQ3 AO_ADC_SENSE_PAD_2
+#define AO_ADC_SQ4 AO_ADC_SENSE_PAD_3
+#define AO_ADC_SQ5 AO_ADC_SENSE_PAD_4
+#define AO_ADC_SQ6 AO_ADC_SENSE_PAD_5
+#define AO_ADC_SQ7 AO_ADC_SENSE_PAD_6
+#define AO_ADC_SQ8 AO_ADC_SENSE_PAD_7
+#define AO_ADC_SQ9 AO_ADC_PYRO
+#define AO_ADC_SQ10 AO_ADC_BATT
+
+#define AO_ADC_REFERENCE_DV 33
+
+#define AO_ADC_RCC_AHBENR ((1 << STM_RCC_AHBENR_GPIOAEN) | \
+ (1 << STM_RCC_AHBENR_GPIOBEN) | \
+ (1 << STM_RCC_AHBENR_GPIOCEN))
+
+
+#define AO_PAD_R_V_BATT_BATT_SENSE 200
+#define AO_PAD_R_BATT_SENSE_GND 22
+
+#define AO_PAD_R_V_BATT_V_PYRO 200
+#define AO_PAD_R_V_PYRO_PYRO_SENSE 200
+#define AO_PAD_R_PYRO_SENSE_GND 22
+
+#undef AO_PAD_R_V_PYRO_IGNITER
+#define AO_PAD_R_IGNITER_IGNITER_SENSE 200
+#define AO_PAD_R_IGNITER_SENSE_GND 22
+
+#define HAS_ADC_TEMP 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 " \
+ "4: %5d 5: %5d 6: %5d 7: %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.sense[4], \
+ (p)->adc.sense[5], \
+ (p)->adc.sense[6], \
+ (p)->adc.sense[7], \
+ (p)->adc.pyro, \
+ (p)->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; 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 <ao.h>
+#include <ao_pad.h>
+#include <ao_exti.h>
+#include <ao_radio_cmac_cmd.h>
+
+int
+main(void)
+{
+ ao_clock_init();
+
+ ao_led_init();
+ ao_led_on(LEDS_AVAILABLE);
+
+ ao_task_init();
+
+ ao_timer_init();
+ ao_spi_init();
+ ao_dma_init();
+ ao_exti_init();
+
+ ao_cmd_init();
+
+ ao_adc_init();
+
+ ao_eeprom_init();
+
+ ao_radio_init();
+
+ ao_usb_init();
+
+ ao_config_init();
+
+ ao_pad_init();
+
+// ao_radio_cmac_cmd_init();
+
+ ao_led_off(LEDS_AVAILABLE);
+
+ ao_start_scheduler();
+}
--- /dev/null
+*.elf
+*.ihx
--- /dev/null
+#
+# AltOS flash loader build
+#
+#
+
+TOPDIR=../..
+HARDWARE=telefireeight-v2.0
+include $(TOPDIR)/stm/Makefile-flash.defs
--- /dev/null
+/*
+ * Copyright © 2019 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.
+ */
+
+#ifndef _AO_PINS_H_
+#define _AO_PINS_H_
+
+/* External crystal at 8MHz */
+#define AO_HSE 8000000
+
+#include <ao_flash_stm_pins.h>
+
+#define AO_BOOT_PIN 1
+#define AO_BOOT_APPLICATION_GPIO stm_gpioe
+#define AO_BOOT_APPLICATION_PIN 2
+#define AO_BOOT_APPLICATION_VALUE 1
+#define AO_BOOT_APPLICATION_MODE AO_EXTI_MODE_PULL_UP
+
+#endif /* _AO_PINS_H_ */
--- /dev/null
+telefireone-*
+ao_product.h
ao_freq.c \
ao_dma_stm.c \
ao_spi_stm.c \
- ao_beep_stm.c \
ao_eeprom_stm.c \
ao_storage.c \
ao_m25.c \
PRODUCT_DEF=-DTELEFIREONE_V_1_0
IDPRODUCT=0x000f
-CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) -Os -g
+CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF)
PROGNAME = telefireone-v1.0
PROG = $(PROGNAME)-$(VERSION).elf
all: $(PROG) $(HEX)
$(PROG): Makefile $(OBJ) altos.ld
- $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
+ $(call quiet,CC) $(LDFLAGS) -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:
uninstall:
+echo:
+ echo $(PROG) $(VERSION)
#define HAS_FLIGHT 0
#define HAS_USB 1
-#define HAS_BEEP 1
+#define HAS_BEEP 0
#define BEEPER_CHANNEL 4
#define BEEPER_TIMER 3
#define HAS_GPS 0
#define HAS_EEPROM 1
#define HAS_LOG 1
#define HAS_PAD 1
-#define USE_INTERNAL_FLASH 1
+#define USE_INTERNAL_FLASH 0
#define IGNITE_ON_P0 0
#define PACKET_HAS_MASTER 0
#define PACKET_HAS_SLAVE 0
#define AO_DATA_RING 32
#define HAS_FIXED_PAD_BOX 1
+#define AO_LOG_FORMAT AO_LOG_FORMAT_TELEFIRETWO
+
#define LOG_ERASE_MARK 0x55
/* 8MHz High speed external crystal */
#define AO_ADC_FIRST_PIN 0
+#define AO_ADC_REFERENCE_DV 33
+
#define AO_NUM_ADC 5
#define AO_ADC_SQ1 AO_PAD_ADC_0
#define AO_ADC_SQ4 AO_PAD_ADC_THRUST
#define AO_ADC_SQ5 AO_PAD_ADC_PRESSURE
+#define AO_PAD_R_V_BATT_BATT_SENSE 200
+#define AO_PAD_R_BATT_SENSE_GND 22
+
+#define AO_PAD_R_V_BATT_V_PYRO 200
+#define AO_PAD_R_V_PYRO_PYRO_SENSE 200
+#define AO_PAD_R_PYRO_SENSE_GND 22
+
+#undef AO_PAD_R_V_PYRO_IGNITER
+#define AO_PAD_R_IGNITER_IGNITER_SENSE 200
+#define AO_PAD_R_IGNITER_SENSE_GND 22
+
#define AO_PYRO_R_PYRO_SENSE 200
#define AO_PYRO_R_SENSE_GND 22
{ 0, NULL },
};
-void
+int
main(void)
{
ao_clock_init();
- ao_led_init(LEDS_AVAILABLE);
+ ao_led_init();
ao_task_init();
--- /dev/null
+#
+# TeleFire build file
+#
+
+include ../stm/Makefile.defs
+
+INC = \
+ ao.h \
+ ao_pins.h \
+ ao_log.h \
+ ao_arch.h \
+ ao_arch_funcs.h \
+ ao_pad.h \
+ ao_product.h \
+ ao_radio_spi.h \
+ ao_radio_cmac.h \
+ ao_cc1200_CC1200.h \
+ ao_cc1200.h \
+ stm32l.h
+#
+# Common AltOS sources
+#
+
+#PROFILE=ao_profile.c
+#PROFILE_DEF=-DAO_PROFILE=1
+
+ALTOS_SRC = \
+ ao_boot_chain.c \
+ ao_interrupt.c \
+ ao_product.c \
+ ao_romconfig.c \
+ ao_cmd.c \
+ ao_adc_stm.c \
+ ao_data.c \
+ ao_config.c \
+ ao_task.c \
+ ao_led_stm.c \
+ ao_stdio.c \
+ ao_panic.c \
+ ao_timer.c \
+ ao_mutex.c \
+ ao_freq.c \
+ ao_dma_stm.c \
+ ao_spi_stm.c \
+ ao_eeprom_stm.c \
+ ao_storage.c \
+ ao_m25.c \
+ ao_usb_stm.c \
+ ao_exti_stm.c \
+ ao_cc1200.c \
+ ao_radio_cmac.c \
+ ao_aes.c \
+ ao_aes_tables.c \
+ ao_pad.c \
+ ao_radio_cmac_cmd.c \
+ ao_log.c \
+ ao_log_fireone.c \
+ ao_ads124s0x.c \
+ ao_max6691.c
+
+PRODUCT_SRC = \
+ ao_telefireone.c
+
+PRODUCT=TeleFireOne-v2.0
+PRODUCT_DEF=-DTELEFIREONE_V_2_0
+IDPRODUCT=0x000f
+
+# Include floating-point enabled printf
+
+NEWLIB_PRINTF_CFLAGS =
+
+CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF)
+
+PROGNAME = telefireone-v2.0
+PROG = $(PROGNAME)-$(VERSION).elf
+HEX = $(PROGNAME)-$(VERSION).ihx
+
+SRC = $(ALTOS_SRC) $(PRODUCT_SRC)
+OBJ=$(SRC:.c=.o)
+
+all: $(PROG) $(HEX)
+
+$(PROG): Makefile $(OBJ) altos.ld
+ $(call quiet,CC) $(LDFLAGS) -o $(PROG) $(OBJ) $(LIBS)
+
+$(OBJ): $(INC)
+
+distclean: clean
+
+clean:
+ rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx $(PROGNAME)-*.map
+ rm -f ao_product.h
+
+install:
+
+uninstall:
+
--- /dev/null
+/*
+ * Copyright © 2019 Bdale Garbee <bdale@gag.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.
+ */
+
+#ifndef _AO_PINS_H_
+#define _AO_PINS_H_
+
+#define HAS_RADIO 1
+#define HAS_RADIO_RATE 1
+#define HAS_TELEMETRY 0
+
+#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 1
+#define HAS_PAD 1
+#define IGNITE_ON_P0 0
+#define PACKET_HAS_MASTER 0
+#define PACKET_HAS_SLAVE 0
+#define AO_DATA_RING 32
+#define HAS_FIXED_PAD_BOX 1
+
+#define AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX (512 * 1024)
+#define AO_CONFIG_MAX_SIZE 1024
+#define LOG_ERASE_MARK 0x55
+#define LOG_MAX_ERASE 128
+#define AO_LOG_FORMAT AO_LOG_FORMAT_TELEMETRUM
+
+/* 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)
+
+#define AO_CC1200_FOSC 40000000
+
+/* 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_EEPROM 1
+#define USE_INTERNAL_FLASH 0
+#define USE_EEPROM_CONFIG 1
+#define USE_STORAGE_CONFIG 0
+#define HAS_USB 1
+#define HAS_RADIO 1
+#define HAS_RADIO_RATE 1
+#define HAS_TELEMETRY 0
+#define HAS_AES 1
+
+#define HAS_SPI_1 1 /* ADS124S0X */
+#define SPI_1_PA5_PA6_PA7 1
+#define SPI_1_PB3_PB4_PB5 0
+#define SPI_1_PE13_PE14_PE15 0
+#define SPI_1_OSPEEDR STM_OSPEEDR_10MHz
+
+#define HAS_SPI_2 1 /* CC1200 */
+#define SPI_2_PB13_PB14_PB15 1
+#define SPI_2_PD1_PD3_PD4 0
+#define SPI_2_GPIO (&stm_gpiob)
+#define SPI_2_SCK 13
+#define SPI_2_MISO 14
+#define SPI_2_MOSI 15
+#define SPI_2_OSPEEDR STM_OSPEEDR_10MHz
+
+#define HAS_I2C_1 0
+
+#define HAS_I2C_2 0
+
+#define PACKET_HAS_SLAVE 0
+#define PACKET_HAS_MASTER 0
+
+#define FAST_TIMER_FREQ 10000 /* .1ms for debouncing */
+
+/*
+ * ADS124S0X analog to digital converter
+ */
+
+#define AO_ADS124S0X_SPI_CS_PORT (&stm_gpioa)
+#define AO_ADS124S0X_SPI_CS_PIN 4
+#define AO_ADS124S0X_SPI_CS_MASK (1 << AO_ADS124S0X_SPI_CS_PIN)
+#define AO_ADS124S0X_SPI_BUS (AO_SPI_1_PA5_PA6_PA7 | AO_SPI_MODE_1)
+#define AO_ADS124S0X_SPI_SPEED AO_SPI_SPEED_8MHz
+
+#define AO_ADS124S0X_DRDY_PORT (&stm_gpioc)
+#define AO_ADS124S0X_DRDY_PIN 13
+
+#define AO_ADS124S0X_START_PORT (&stm_gpioc)
+#define AO_ADS124S0X_START_PIN 14
+
+#define AO_ADS124S0X_RESET_PORT (&stm_gpioc)
+#define AO_ADS124S0X_RESET_PIN 15
+
+#define AO_ADS124S0X_CHANNELS 4 /* how many inputs in use */
+
+/*
+ * SPI Flash memory
+ */
+
+#define M25_MAX_CHIPS 1
+#define AO_M25_SPI_CS_PORT (&stm_gpioa)
+#define AO_M25_SPI_CS_MASK (1 << 15)
+#define AO_M25_SPI_BUS AO_SPI_2_PB13_PB14_PB15
+
+/*
+ * Radio is a cc1200 connected via SPI
+ */
+
+#define AO_RADIO_CAL_DEFAULT 5695733
+
+#define AO_FEC_DEBUG 0
+#define AO_CC1200_SPI_CS_PORT (&stm_gpioa)
+#define AO_CC1200_SPI_CS_PIN 3
+#define AO_CC1200_SPI_BUS AO_SPI_2_PB13_PB14_PB15
+#define AO_CC1200_SPI stm_spi2
+#define AO_CC1200_SPI_SPEED AO_SPI_SPEED_FAST
+
+#define AO_CC1200_INT_PORT (&stm_gpiob)
+#define AO_CC1200_INT_PIN (11)
+
+#define AO_CC1200_INT_GPIO 2
+#define AO_CC1200_INT_GPIO_IOCFG CC1200_IOCFG2
+
+#define LED_PORT_0 (&stm_gpioa)
+#define LED_PORT_1 (&stm_gpiob)
+
+#define LED_PORT_0_ENABLE STM_RCC_AHBENR_GPIOAEN
+#define LED_PORT_1_ENABLE STM_RCC_AHBENR_GPIOBEN
+
+/* Port A, pins 8-10 */
+#define LED_PORT_0_SHIFT 8
+#define LED_PORT_0_MASK 0x7
+#define LED_PIN_GREEN 0
+#define LED_PIN_AMBER 1
+#define LED_PIN_RED 2
+#define AO_LED_RED (1 << LED_PIN_RED)
+#define AO_LED_AMBER (1 << LED_PIN_AMBER)
+#define AO_LED_GREEN (1 << LED_PIN_GREEN)
+
+/* Port B, pins 5-6 */
+#define LED_PORT_1_SHIFT 0
+#define LED_PORT_1_MASK (0x3 << 5)
+#define LED_PIN_CONT_0 5
+#define LED_PIN_ARMED 6
+
+#define AO_LED_ARMED (1 << LED_PIN_ARMED)
+#define AO_LED_CONTINUITY(c) (1 << (4 - (c)))
+#define AO_LED_CONTINUITY_MASK (0x1 << 4)
+
+#define LEDS_AVAILABLE (LED_PORT_0_MASK|LED_PORT_1_MASK)
+
+/* Alarm A */
+#define AO_SIREN
+#define AO_SIREN_PORT (&stm_gpiob)
+#define AO_SIREN_PIN 8
+
+/* Alarm B */
+#define AO_STROBE
+#define AO_STROBE_PORT (&stm_gpiob)
+#define AO_STROBE_PIN 9
+
+#define SPI_CONST 0x00
+
+/*
+ * ADC reference in decivolts
+ */
+#define AO_ADC_REFERENCE_DV 33
+
+#define AO_PAD_NUM 1
+#define AO_PAD_PORT (&stm_gpioa)
+
+#define AO_PAD_PIN_0 1
+#define AO_PAD_ADC_0 0
+
+#define AO_PAD_ALL_PINS ((1 << AO_PAD_PIN_0))
+#define AO_PAD_ALL_CHANNELS ((1 << 0))
+
+/* 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 2
+#define AO_PAD_ADC_BATT 8
+
+// #define AO_PAD_ADC_THRUST 3 /* FIXME - external ADC now! */
+// #define AO_PAD_ADC_PRESSURE 18 /* FIXME - external ADC now! */
+
+#define AO_ADC_FIRST_PIN 0
+
+#define AO_NUM_ADC 3
+
+#define AO_ADC_SQ1 AO_PAD_ADC_0
+#define AO_ADC_SQ2 AO_PAD_ADC_PYRO
+#define AO_ADC_SQ3 AO_PAD_ADC_BATT
+// #define AO_ADC_SQ4 AO_PAD_ADC_THRUST
+// #define AO_ADC_SQ5 AO_PAD_ADC_PRESSURE
+
+#define AO_PAD_R_V_BATT_BATT_SENSE 200
+#define AO_PAD_R_BATT_SENSE_GND 22
+
+#define AO_PAD_R_V_BATT_V_PYRO 200
+#define AO_PAD_R_V_PYRO_PYRO_SENSE 200
+#define AO_PAD_R_PYRO_SENSE_GND 22
+
+#undef AO_PAD_R_V_PYRO_IGNITER
+#define AO_PAD_R_IGNITER_IGNITER_SENSE 200
+#define AO_PAD_R_IGNITER_SENSE_GND 22
+
+#define HAS_ADC_TEMP 0
+
+struct ao_adc {
+ int16_t sense[AO_PAD_NUM];
+ int16_t pyro;
+ int16_t batt;
+ int16_t thrust;
+ int16_t pressure;
+};
+
+#define AO_ADC_DUMP(p) \
+ printf ("tick: %5u 0: %5d pyro: %5d batt %5d\n", \
+ (p)->tick, \
+ (p)->adc.sense[0], \
+ (p)->adc.pyro, \
+ (p)->adc.batt)
+
+#define AO_ADC_PINS ((1 << AO_PAD_ADC_0) | \
+ (1 << AO_PAD_ADC_PYRO) | \
+ (1 << AO_PAD_ADC_BATT))
+
+/* MAX6691 thermistor chip */
+#define HAS_MAX6691 1
+#define AO_MAX6691_GPIO (&stm_gpiob)
+#define AO_MAX6691_PIN 3
+#define AO_MAX6691_TIMER (&stm_tim2)
+#define AO_MAX6691_TIMER_ENABLE STM_RCC_APB1ENR_TIM2EN
+#define AO_MAX6691_CH 2
+#define AO_MAX6691_DMA STM_DMA_INDEX(7)
+
+#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; 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 <ao.h>
+#include <ao_log.h>
+#include <ao_pad.h>
+#include <ao_exti.h>
+#include <ao_radio_cmac_cmd.h>
+#include <ao_eeprom.h>
+#include <ao_ads124s0x.h>
+#include <ao_max6691.h>
+
+static void
+set_logging(void)
+{
+ ao_log_running = ao_cmd_hex();
+ ao_wakeup(&ao_log_running);
+}
+
+const struct ao_cmds ao_firetwo_cmds[] = {
+ { set_logging, "L <0 off, 1 on>\0Log sensors to flash" },
+ { 0, NULL },
+};
+
+void
+main(void)
+{
+ ao_clock_init();
+
+ ao_led_init();
+
+ ao_task_init();
+
+ ao_timer_init();
+ ao_spi_init();
+ ao_dma_init();
+ ao_exti_init();
+
+ ao_cmd_register(&ao_firetwo_cmds[0]);
+ ao_cmd_init();
+
+ ao_adc_init();
+
+ ao_max6691_init();
+
+ ao_eeprom_init();
+ ao_storage_init();
+ ao_log_init();
+
+ ao_radio_init();
+
+ ao_usb_init();
+
+ ao_config_init();
+
+ ao_pad_init();
+
+// ao_radio_cmac_cmd_init();
+
+ ao_ads124s0x_init();
+
+ ao_start_scheduler();
+}
--- /dev/null
+*.elf
+*.ihx
--- /dev/null
+#
+# AltOS flash loader build
+#
+#
+
+TOPDIR=../..
+HARDWARE=telefireone-v2.0
+include $(TOPDIR)/stm/Makefile-flash.defs
--- /dev/null
+/*
+ * Copyright © 2019 Bdale Garbee <bdale@gag.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.
+ */
+
+#ifndef _AO_PINS_H_
+#define _AO_PINS_H_
+
+/* External crystal at 8MHz */
+#define AO_HSE 8000000
+
+#include <ao_flash_stm_pins.h>
+
+#define AO_BOOT_PIN 1
+#define AO_BOOT_APPLICATION_GPIO stm_gpiob
+#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_ */
PRODUCT_DEF=-DTELEFIRETWO_V_0_1
IDPRODUCT=0x000f
-CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) -Os -g
+CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF)
PROGNAME = telefiretwo-v0.1
PROG = $(PROGNAME)-$(VERSION).elf
all: $(PROG) $(HEX)
$(PROG): Makefile $(OBJ) altos.ld
- $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
+ $(call quiet,CC) $(LDFLAGS) -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:
#include <ao_exti.h>
#include <ao_radio_cmac_cmd.h>
-void
+int
main(void)
{
ao_clock_init();
PRODUCT_DEF=-DTELEFIRETWO_V_0_2
IDPRODUCT=0x000f
-CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) -Os -g
+CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF)
PROGNAME = telefiretwo-v0.2
PROG = $(PROGNAME)-$(VERSION).elf
PRODUCT_DEF=-DTELEGPS
IDPRODUCT=0x0025
-CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF) -Os -g
+CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF)
PROGNAME=telegps-v0.1
PROG=$(PROGNAME)-$(VERSION).elf
PRODUCT_DEF=-DTELEGPS
IDPRODUCT=0x0025
-CFLAGS = $(PRODUCT_DEF) $(LPC_CFLAGS) $(PROFILE_DEF) -Os -g
+CFLAGS = $(PRODUCT_DEF) $(LPC_CFLAGS) $(PROFILE_DEF)
PROGNAME=telegps-v0.3
PROG=$(PROGNAME)-$(VERSION).elf
all: $(PROG) $(HEX)
$(PROG): Makefile $(OBJ) altos.ld
- $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
+ $(call quiet,CC) $(LDFLAGS) -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:
PRODUCT_DEF=-DTELEGPS
IDPRODUCT=0x0025
-CFLAGS = $(PRODUCT_DEF) $(LPC_CFLAGS) $(PROFILE_DEF) -Os -g
+CFLAGS = $(PRODUCT_DEF) $(LPC_CFLAGS) $(PROFILE_DEF)
PROGNAME=telegps-v1.0
PROG=$(PROGNAME)-$(VERSION).elf
all: $(PROG) $(HEX)
$(PROG): Makefile $(OBJ) altos.ld
- $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
+ $(call quiet,CC) $(LDFLAGS) -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:
#
#
-include ../stmf0/Makefile.defs
+TOPDIR=..
+
+include $(TOPDIR)/stmf0/Makefile.defs
INC = \
ao.h \
PRODUCT_DEF=-DTELEGPS
IDPRODUCT=0x0025
-CFLAGS = $(PRODUCT_DEF) $(STMF0_CFLAGS) $(PROFILE_DEF) -g -Os
+CFLAGS = $(PRODUCT_DEF) $(STMF0_CFLAGS) $(PROFILE_DEF)
PROGNAME=telegps-v2.0
PROG=$(PROGNAME)-$(VERSION).elf
$(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:
--- /dev/null
+ao_product.h
+telelco*.elf
PRODUCT_DEF=-DTELELCO
IDPRODUCT=0x0023
-CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) -Os -g
+CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF)
PROGNAME=telelco-v0.2
PROG=$(PROGNAME)-$(VERSION).elf
all: $(PROG) $(HEX)
$(PROG): Makefile $(OBJ) altos.ld
- $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
-
-../altitude.h: make-altitude
- nickle $< > $@
+ $(call quiet,CC) $(LDFLAGS) -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:
ao_radio_cmac_cmd.c
PRODUCT=TeleLCO-v0.2
-PRODUCT_DEF=-DTELEMEGA
+PRODUCT_DEF=-DTELELCO
IDPRODUCT=0x0023
-CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) -Os -g
+CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF)
PROGNAME=telelco-v0.2
PROG=$(PROGNAME)-$(VERSION).elf
all: $(PROG) $(HEX)
$(PROG): Makefile $(OBJ) altos.ld
- $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
-
-../altitude.h: make-altitude
- nickle $< > $@
+ $(call quiet,CC) $(LDFLAGS) -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:
PRODUCT_DEF=-DTELELCO
IDPRODUCT=0x0023
-CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) -Os -g
+CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF)
PROGNAME=telelco-v0.3
PROG=$(PROGNAME)-$(VERSION).elf
all: $(PROG) $(HEX)
$(PROG): Makefile $(OBJ) altos.ld
- $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
-
-../altitude.h: make-altitude
- nickle $< > $@
+ $(call quiet,CC) $(LDFLAGS) -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:
PRODUCT_DEF=-DTELELCO
IDPRODUCT=0x0023
-CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) -Os -g
+CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF)
PROGNAME=telelco-v2.0
PROG=$(PROGNAME)-$(VERSION).elf
all: $(PROG) $(HEX)
$(PROG): Makefile $(OBJ) altos.ld
- $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
+ $(call quiet,CC) $(LDFLAGS) -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:
* visually inspect the system for correct operation
*/
static void
-ao_lco_display_test()
+ao_lco_display_test(void)
{
ao_mutex_get(&ao_lco_display_mutex);
ao_seven_segment_set(AO_LCO_PAD_DIGIT, 8 | 0x10);
}
#if DEBUG
-void
+static void
ao_lco_set_debug(void)
{
uint16_t r = ao_cmd_decimal();
PRODUCT_DEF=-DTELELCOTWO
IDPRODUCT=0x0023
-CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) -Os -g
+CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF)
PROGNAME=telelcotwo-v0.1
PROG=$(PROGNAME)-$(VERSION).elf
all: $(PROG) $(HEX)
$(PROG): Makefile $(OBJ) altos.ld
- $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
+ $(call quiet,CC) $(LDFLAGS) -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:
PRODUCT_DEF=-DTELEMEGA
IDPRODUCT=0x0023
-CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF) -Os -g
+CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF)
PROGNAME=telemega-v0.1
PROG=$(PROGNAME)-$(VERSION).elf
all: $(PROG) $(HEX)
$(PROG): Makefile $(OBJ) altos.ld
- $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
-
-../altitude-pa.h: make-altitude-pa
- nickle $< > $@
+ $(call quiet,CC) $(LDFLAGS) -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:
PRODUCT_DEF=-DTELEMEGA
IDPRODUCT=0x0023
-CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF) -Os -g
+CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF)
PROGNAME=telemega-v1.0
PROG=$(PROGNAME)-$(VERSION).elf
all: $(PROG) $(HEX)
$(PROG): Makefile $(OBJ) altos.ld
- $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
-
-../altitude-pa.h: make-altitude-pa
- nickle $< > $@
+ $(call quiet,CC) $(LDFLAGS) -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:
PRODUCT_DEF=-DTELEMEGA
IDPRODUCT=0x0023
-CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF) -Os -g
+CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF)
PROGNAME=telemega-v2.0
PROG=$(PROGNAME)-$(VERSION).elf
all: $(PROG) $(HEX)
$(PROG): Makefile $(OBJ) altos.ld
- $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
-
-../altitude-pa.h: make-altitude-pa
- nickle $< > $@
+ $(call quiet,CC) $(LDFLAGS) -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:
PRODUCT_DEF=-DTELEMEGA
IDPRODUCT=0x0023
-CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF) -Os -g
+CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF)
PROGNAME=telemega-v3.0
PROG=$(PROGNAME)-$(VERSION).elf
all: $(PROG) $(HEX)
$(PROG): Makefile $(OBJ) altos.ld
- $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
-
-../altitude-pa.h: make-altitude-pa
- nickle $< > $@
+ $(call quiet,CC) $(LDFLAGS) -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:
PRODUCT_DEF=-DTELEMETRUM_V_2_0
IDPRODUCT=0x000b
-CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF) -Os -g
+CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF)
PROGNAME=telemetrum-v2.0
PROG=$(PROGNAME)-$(VERSION).elf
all: $(PROG) $(HEX)
$(PROG): Makefile $(OBJ) altos.ld
- $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
-
-../altitude-pa.h: make-altitude-pa
- nickle $< > $@
+ $(call quiet,CC) $(LDFLAGS) -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:
ao_kalman.h \
ao_product.h \
ao_ms5607.h \
- ao_mma655x.h \
+ ao_adxl375.h \
ao_cc1200_CC1200.h \
ao_profile.h \
ao_task.h \
ao_fec_rx.c \
ao_data.c \
ao_ms5607.c \
- ao_mma655x.c \
+ ao_adxl375.c \
ao_adc_stm.c \
ao_beep_stm.c \
ao_storage.c \
PRODUCT_DEF=-DTELEMETRUM_V_3_0
IDPRODUCT=0x000b
-CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF) -Os -g
+CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF)
PROGNAME=telemetrum-v3.0
PROG=$(PROGNAME)-$(VERSION).elf
all: $(PROG) $(HEX)
$(PROG): Makefile $(OBJ) altos.ld
- $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
-
-../altitude-pa.h: make-altitude-pa
- nickle $< > $@
+ $(call quiet,CC) $(LDFLAGS) -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:
#define HAS_HIGHG_ACCEL 1
-/*
- * mma655x
- */
+/* ADXL375 */
+
+#define HAS_ADXL375 1
+#define AO_ADXL375_SPI_INDEX (AO_SPI_1_PB3_PB4_PB5 | AO_SPI_MODE_3)
+#define AO_ADXL375_CS_PORT (&stm_gpiob)
+#define AO_ADXL375_CS_PIN 9
+#define AO_ADXL375_SPI_SPEED AO_SPI_SPEED_4MHz
-#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 AO_ADXL375_AXIS x
+#define AO_ADXL375_INVERT 1
#define NUM_CMDS 16
#include <ao.h>
#include <ao_ms5607.h>
-#include <ao_mma655x.h>
+#include <ao_adxl375.h>
#include <ao_log.h>
#include <ao_exti.h>
#include <ao_packet.h>
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_adxl375_init();
ao_eeprom_init();
PRODUCT_DEF=-DTELEMINI_V_3_0
IDPRODUCT=0x0027
-CFLAGS = $(PRODUCT_DEF) $(STMF0_CFLAGS) -g -Os
+CFLAGS = $(PRODUCT_DEF) $(STMF0_CFLAGS)
PROGNAME=telemini-v3.0
PROG=$(PROGNAME)-$(VERSION).elf
all: $(PROG) $(HEX)
$(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) > $@
+ $(call quiet,CC) $(LDFLAGS) -o $(PROG) $(OBJ) $(LIBS)
$(OBJ): $(INC)
ao_disable_port(AO_RECOVERY_PORT);
}
-void
+int
main(void)
{
ao_check_recovery();
--- /dev/null
+ao_product.h
+telestatic-*.elf
--- /dev/null
+#
+# TeleStatic build file
+#
+
+include ../stm/Makefile.defs
+
+INC = \
+ ao.h \
+ ao_pins.h \
+ ao_log.h \
+ ao_arch.h \
+ ao_arch_funcs.h \
+ ao_pad.h \
+ ao_product.h \
+ ao_radio_spi.h \
+ ao_radio_cmac.h \
+ ao_cc1200_CC1200.h \
+ ao_cc1200.h \
+ stm32l.h
+#
+# Common AltOS sources
+#
+
+#PROFILE=ao_profile.c
+#PROFILE_DEF=-DAO_PROFILE=1
+
+ALTOS_SRC = \
+ ao_boot_chain.c \
+ ao_interrupt.c \
+ ao_product.c \
+ ao_romconfig.c \
+ ao_cmd.c \
+ ao_adc_stm.c \
+ ao_data.c \
+ ao_config.c \
+ ao_task.c \
+ ao_led.c \
+ ao_stdio.c \
+ ao_panic.c \
+ ao_timer.c \
+ ao_mutex.c \
+ ao_freq.c \
+ ao_dma_stm.c \
+ ao_spi_stm.c \
+ ao_eeprom_stm.c \
+ ao_storage.c \
+ ao_m25.c \
+ ao_usb_stm.c \
+ ao_exti_stm.c \
+ ao_cc1200.c \
+ ao_radio_cmac.c \
+ ao_aes.c \
+ ao_aes_tables.c \
+ ao_pad.c \
+ ao_radio_cmac_cmd.c \
+ ao_log.c \
+ ao_log_telestatic.c \
+ ao_max6691.c
+
+PRODUCT_SRC = \
+ ao_telestatic.c
+
+PRODUCT=TeleStatic-v3.0
+PRODUCT_DEF=-DTELESTATIC_V_3_0
+IDPRODUCT=0x000f
+
+# Include floating-point enabled printf
+
+NEWLIB_PRINTF_CFLAGS =
+
+CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF)
+
+PROGNAME = telestatic-v3.0
+PROG = $(PROGNAME)-$(VERSION).elf
+HEX = $(PROGNAME)-$(VERSION).ihx
+
+SRC = $(ALTOS_SRC) $(PRODUCT_SRC)
+OBJ=$(SRC:.c=.o)
+
+all: $(PROG) $(HEX)
+
+$(PROG): Makefile $(OBJ) altos.ld
+ $(call quiet,CC) $(LDFLAGS) -o $(PROG) $(OBJ) $(LIBS)
+
+$(OBJ): $(INC)
+
+distclean: clean
+
+clean:
+ rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx $(PROGNAME)-*.map
+ rm -f ao_product.h
+
+install:
+
+uninstall:
+
--- /dev/null
+/*
+ * Copyright © 2019 Bdale Garbee <bdale@gag.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.
+ */
+
+#ifndef _AO_PINS_H_
+#define _AO_PINS_H_
+
+#define HAS_RADIO 1
+#define HAS_RADIO_RATE 1
+#define HAS_TELEMETRY 0
+
+#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 1
+#define HAS_PAD 1
+#define IGNITE_ON_P0 0
+#define PACKET_HAS_MASTER 0
+#define PACKET_HAS_SLAVE 0
+#define AO_DATA_RING 32
+#define HAS_FIXED_PAD_BOX 1
+
+#define AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX (512 * 1024)
+#define AO_CONFIG_MAX_SIZE 1024
+#define LOG_ERASE_MARK 0x55
+#define LOG_MAX_ERASE 128
+#define AO_LOG_FORMAT AO_LOG_FORMAT_TELEMETRUM
+
+/* 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)
+
+#define AO_CC1200_FOSC 40000000
+
+/* 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_EEPROM 1
+#define USE_INTERNAL_FLASH 0
+#define USE_EEPROM_CONFIG 1
+#define USE_STORAGE_CONFIG 0
+#define HAS_USB 1
+#define HAS_RADIO 1
+#define HAS_RADIO_RATE 1
+#define HAS_TELEMETRY 0
+#define HAS_AES 1
+
+#define HAS_SPI_1 1 /* ADS131A0X */
+#define SPI_1_PA5_PA6_PA7 1
+#define SPI_1_PB3_PB4_PB5 0
+#define SPI_1_PE13_PE14_PE15 0
+#define SPI_1_OSPEEDR STM_OSPEEDR_10MHz
+
+#define HAS_SPI_2 1 /* CC1200 and W25Q64 */
+#define SPI_2_PB13_PB14_PB15 1
+#define SPI_2_PD1_PD3_PD4 0
+#define SPI_2_GPIO (&stm_gpiob)
+#define SPI_2_SCK 13
+#define SPI_2_MISO 14
+#define SPI_2_MOSI 15
+#define SPI_2_OSPEEDR STM_OSPEEDR_10MHz
+
+#define HAS_I2C_1 0
+
+#define HAS_I2C_2 0
+
+#define PACKET_HAS_SLAVE 0
+#define PACKET_HAS_MASTER 0
+
+#define FAST_TIMER_FREQ 10000 /* .1ms for debouncing */
+
+/*
+ * ADS131A0X analog to digital converter
+ */
+
+#define HAS_ADS131A0X 0
+#define AO_ADS131A0X_SPI_CS_PORT (&stm_gpioa)
+#define AO_ADS131A0X_SPI_CS_PIN 4
+#define AO_ADS131A0X_SPI_CS_MASK (1 << AO_ADS131A0X_SPI_CS_PIN)
+#define AO_ADS131A0X_SPI_BUS (AO_SPI_1_PA5_PA6_PA7 | AO_SPI_MODE_1)
+#define AO_ADS131A0X_SPI_SPEED AO_SPI_SPEED_8MHz
+
+#define AO_ADS131A0X_DRDY_PORT (&stm_gpioc)
+#define AO_ADS131A0X_DRDY_PIN 13
+
+#define AO_ADS131A0X_DONE_PORT (&stm_gpioc)
+#define AO_ADS131A0X_DONE_PIN 14
+
+#define AO_ADS131A0X_CHANNELS 4 /* how many inputs in use */
+
+/*
+ * SPI Flash memory
+ */
+
+#define M25_MAX_CHIPS 1
+#define AO_M25_SPI_CS_PORT (&stm_gpioa)
+#define AO_M25_SPI_CS_MASK (1 << 1)
+#define AO_M25_SPI_BUS AO_SPI_2_PB13_PB14_PB15
+
+/*
+ * Radio is a cc1200 connected via SPI
+ */
+
+#define AO_RADIO_CAL_DEFAULT 5695733
+
+#define AO_FEC_DEBUG 0
+#define AO_CC1200_SPI_CS_PORT (&stm_gpioa)
+#define AO_CC1200_SPI_CS_PIN 3
+#define AO_CC1200_SPI_BUS AO_SPI_2_PB13_PB14_PB15
+#define AO_CC1200_SPI stm_spi2
+#define AO_CC1200_SPI_SPEED AO_SPI_SPEED_FAST
+
+#define AO_CC1200_INT_PORT (&stm_gpiob)
+#define AO_CC1200_INT_PIN (11)
+
+#define AO_CC1200_INT_GPIO 2
+#define AO_CC1200_INT_GPIO_IOCFG CC1200_IOCFG2
+
+#define HAS_LED 1
+
+#define LED_0_PORT (&stm_gpioa)
+#define LED_0_PIN 8
+#define AO_LED_RED (1 << 0)
+
+#define LED_1_PORT (&stm_gpioa)
+#define LED_1_PIN 9
+#define AO_LED_AMBER (1 << 1)
+
+#define LED_2_PORT (&stm_gpioa)
+#define LED_2_PIN 10
+#define AO_LED_GREEN (1 << 2)
+
+#define LED_3_PORT (&stm_gpiob)
+#define LED_3_PIN 5
+#define AO_LED_ARMED (1 << 3)
+
+#define LED_4_PORT (&stm_gpiob)
+#define LED_4_PIN 6
+#define AO_LED_CONTINUITY(c) (1 << 4)
+
+/* Alarm A */
+#define AO_SIREN
+#define AO_SIREN_PORT (&stm_gpiob)
+#define AO_SIREN_PIN 8
+
+/* Alarm B */
+#define AO_STROBE
+#define AO_STROBE_PORT (&stm_gpiob)
+#define AO_STROBE_PIN 9
+
+#define SPI_CONST 0x00
+
+/*
+ * ADC reference in decivolts
+ */
+#define AO_ADC_REFERENCE_DV 33
+
+#define AO_PAD_NUM 1
+#define AO_PAD_PORT (&stm_gpioa)
+#define AO_PAD_PIN_0 1
+
+#define AO_PAD_ADC_0 0
+
+#define AO_PAD_ALL_PINS ((1 << AO_PAD_PIN_0))
+#define AO_PAD_ALL_CHANNELS ((1 << 0))
+
+/* 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 2
+#define AO_PAD_ADC_BATT 8
+
+#define AO_ADC_FIRST_PIN 0
+
+#define AO_NUM_ADC 3
+
+#define AO_ADC_SQ1 AO_PAD_ADC_0
+#define AO_ADC_SQ2 AO_PAD_ADC_PYRO
+#define AO_ADC_SQ3 AO_PAD_ADC_BATT
+
+#define AO_PAD_R_V_BATT_BATT_SENSE 200
+#define AO_PAD_R_BATT_SENSE_GND 22
+
+#define AO_PAD_R_V_BATT_V_PYRO 200
+#define AO_PAD_R_V_PYRO_PYRO_SENSE 200
+#define AO_PAD_R_PYRO_SENSE_GND 22
+
+#undef AO_PAD_R_V_PYRO_IGNITER
+#define AO_PAD_R_IGNITER_IGNITER_SENSE 200
+#define AO_PAD_R_IGNITER_SENSE_GND 22
+
+#define HAS_ADC_TEMP 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 pyro: %5d batt %5d\n", \
+ (p)->tick, \
+ (p)->adc.sense[0], \
+ (p)->adc.pyro, \
+ (p)->adc.batt)
+
+#define AO_ADC_PINS ((1 << AO_PAD_ADC_0) | \
+ (1 << AO_PAD_ADC_PYRO) | \
+ (1 << AO_PAD_ADC_BATT))
+
+/* MAX6691 thermistor chip */
+#define HAS_MAX6691 1
+#define AO_MAX6691_GPIO (&stm_gpiob)
+#define AO_MAX6691_PIN 3
+#define AO_MAX6691_TIMER (&stm_tim2)
+#define AO_MAX6691_TIMER_ENABLE STM_RCC_APB1ENR_TIM2EN
+#define AO_MAX6691_CH 2
+#define AO_MAX6691_DMA STM_DMA_INDEX(7)
+
+#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; 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 <ao.h>
+#include <ao_log.h>
+#include <ao_pad.h>
+#include <ao_exti.h>
+#include <ao_radio_cmac_cmd.h>
+#include <ao_eeprom.h>
+#include <ao_max6691.h>
+
+static void
+set_logging(void)
+{
+ ao_log_running = ao_cmd_hex();
+ ao_wakeup(&ao_log_running);
+}
+
+const struct ao_cmds ao_firetwo_cmds[] = {
+ { set_logging, "L <0 off, 1 on>\0Log sensors to flash" },
+ { 0, NULL },
+};
+
+void
+main(void)
+{
+ ao_clock_init();
+
+ ao_led_init();
+
+ ao_task_init();
+
+ ao_timer_init();
+ ao_spi_init();
+ ao_dma_init();
+ ao_exti_init();
+
+ ao_cmd_register(&ao_firetwo_cmds[0]);
+ ao_cmd_init();
+
+ ao_adc_init();
+
+ ao_max6691_init();
+
+ ao_eeprom_init();
+ ao_storage_init();
+ ao_log_init();
+
+ ao_radio_init();
+
+ ao_usb_init();
+
+ ao_config_init();
+
+ ao_pad_init();
+
+#if HAS_ADS131A0X
+ ao_ads131a0x_init();
+#endif
+
+ ao_start_scheduler();
+}
--- /dev/null
+*.elf
+*.ihx
--- /dev/null
+#
+# AltOS flash loader build
+#
+#
+
+TOPDIR=../..
+HARDWARE=telestatic-v3.0
+include $(TOPDIR)/stm/Makefile-flash.defs
--- /dev/null
+/*
+ * Copyright © 2019 Bdale Garbee <bdale@gag.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.
+ */
+
+#ifndef _AO_PINS_H_
+#define _AO_PINS_H_
+
+/* External crystal at 8MHz */
+#define AO_HSE 8000000
+
+#include <ao_flash_stm_pins.h>
+
+#define AO_BOOT_PIN 1
+#define AO_BOOT_APPLICATION_GPIO stm_gpioc
+#define AO_BOOT_APPLICATION_PIN 15
+#define AO_BOOT_APPLICATION_VALUE 1
+#define AO_BOOT_APPLICATION_MODE AO_EXTI_MODE_PULL_UP
+
+#endif /* _AO_PINS_H_ */
void
ao_radio_send_aprs(ao_radio_fill_func fill);
+#if 0
static void
aprs_bit_debug(uint8_t tx_bit)
{
{
fprintf(stderr, "byte %02x\n", tx_byte);
}
+
#define APRS_BIT_DEBUG(x) aprs_bit_debug(x)
#define APRS_BYTE_DEBUG(y) aprs_byte_debug(y)
+#endif
#include <ao_aprs.c>
*/
+#if 0
static void
audio_gap(int secs)
{
ao_aprs_bit(0);
#endif
}
+#endif
// This is where we go after reset.
int main(int argc, char **argv)
#define HAS_USB 1
#define HAS_GPS 1
+int16_t
+ao_time(void);
+
+void
+ao_dump_state(void);
+
+#define ao_tick_count (ao_time())
+#define ao_wakeup(wchan) ao_dump_state()
+
#include <ao_data.h>
#include <ao_log.h>
#include <ao_telemetry.h>
#define ao_led_on(l)
#define ao_led_off(l)
#define ao_timer_set_adc_interval(i)
-#define ao_wakeup(wchan) ao_dump_state()
#define ao_cmd_register(c)
#define ao_usb_disable()
#define ao_telemetry_set_interval(x)
double emulator_error_max = 4;
double emulator_height_error_max = 20; /* noise in the baro sensor */
-void
-ao_dump_state(void);
-
void
ao_sleep(void *wchan);
const char *help;
};
-#define ao_xmemcpy(d,s,c) memcpy(d,s,c)
-#define ao_xmemset(d,v,c) memset(d,v,c)
-#define ao_xmemcmp(d,s,c) memcmp(d,s,c)
-
#define AO_NEED_ALTITUDE_TO_PRES 1
#if TELEMEGA || TELEMETRUM_V2 || EASYMINI
#include "ao_convert_pa.c"
struct ao_config ao_config;
-#define x (x)
-
-
extern int16_t ao_ground_accel, ao_flight_accel;
extern int16_t ao_accel_2g;
#if TELEMEGA
" angle %5d "
"accel_x %8.3f accel_y %8.3f accel_z %8.3f gyro_x %8.3f gyro_y %8.3f gyro_z %8.3f mag_x %8d mag_y %8d, mag_z %8d mag_angle %4d "
+ "avg_accel %8.3f "
#endif
"\n",
time,
ao_data_static.hmc5883.x,
ao_data_static.hmc5883.y,
ao_data_static.hmc5883.z,
- ao_mag_angle
+ ao_mag_angle,
+ ao_coast_avg_accel / 16.0
#endif
);
#endif
PRODUCT_DEF=-DTMGPS_V_2_0
IDPRODUCT=0x0025
-CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF) -Os -g
+CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF)
PROGNAME=tmgps-v2.0
PROG=$(PROGNAME)-$(VERSION).elf
PRODUCT_DEF=-DVIDTIME
IDPRODUCT=0x002b
-CFLAGS = $(PRODUCT_DEF) $(STMF0_CFLAGS) -Os -g
+CFLAGS = $(PRODUCT_DEF) $(STMF0_CFLAGS)
PROGNAME=vidtime-v1.0
PROG=$(PROGNAME)-$(VERSION).elf
JAVAROOT=classes
-AM_JAVACFLAGS=-target 1.6 -encoding UTF-8 -Xlint:deprecation -Xlint:unchecked -source 6
+AM_JAVACFLAGS=$(JAVAC_VERSION_FLAGS) -encoding UTF-8 -Xlint:deprecation -Xlint:unchecked
man_MANS=telegps.1
$(ICONJAR) \
-C classes org \
-C ../libaltos libaltosJNI
+if STRIP_NONDETERMINISM
+ $(STRIP_NONDETERMINISM) $@
+endif
$(FATJAR): classtelegps.stamp Manifest-fat.txt $(ALTOSLIB_CLASS) $(ALTOSUILIB_CLASS) $(JFREECHART_CLASS) $(JCOMMON_CLASS) $(JAVA_ICONS)
jar cfm $@ Manifest-fat.txt \
$(ICONJAR) \
-C classes org \
-C ../libaltos libaltosJNI
+if STRIP_NONDETERMINISM
+ $(STRIP_NONDETERMINISM) $@
+endif
libaltos.so: build-libaltos
-rm -f "$@"
void graph() {
AltosDataChooser chooser = new AltosDataChooser(this);
AltosRecordSet set = chooser.runDialog();
- if (set == null)
- return;
- try {
- new TeleGPSGraphUI(set, chooser.file());
- } catch (InterruptedException ie) {
- } catch (IOException ie) {
- }
+ graph_file(this, set, chooser.file());
}
public void graph_flights(AltosEepromList list) {
for (AltosEepromLog log : list) {
if (log.file != null) {
AltosRecordSet set = record_set(log.file);
- if (set != null) {
- try {
- new TeleGPSGraphUI(set, log.file);
- } catch (InterruptedException ie) {
- } catch (IOException ie) {
- }
- }
+ graph_file(this, set, log.file);
}
}
}
return new AltosReplayReader(set, file);
}
- static boolean process_graph(File file) {
- AltosRecordSet set = record_set(file);
+ private static boolean graph_file(TeleGPS telegps, AltosRecordSet set, File file) {
if (set == null)
return false;
+ if (!set.valid()) {
+ JOptionPane.showMessageDialog(telegps,
+ String.format("Failed to parse file %s", file),
+ "Graph Failed",
+ JOptionPane.ERROR_MESSAGE);
+ return false;
+ }
try {
new TeleGPSGraphUI(set, file);
- } catch (Exception e) {
+ } catch (IOException e) {
+ System.out.printf("Exception %s\n", e.toString());
+ } catch (InterruptedException e) {
+ System.out.printf("Exception %s\n", e.toString());
return false;
}
return true;
}
+ static boolean process_graph(File file) {
+ AltosRecordSet set = record_set(file);
+ return graph_file(null, set, file);
+ }
+
static boolean process_replay(File file) {
AltosReplayReader new_reader = replay_file(file);
if (new_reader == null)
void fill_map(AltosFlightSeries flight_series) {
boolean any_gps = false;
AltosGPSTimeValue gtv_last = null;
+ double gps_pad_altitude = flight_series.cal_data().gps_pad_altitude;;
if (flight_series.gps_series != null) {
for (AltosGPSTimeValue gtv : flight_series.gps_series) {
gps.nsat >= 4) {
if (map == null)
map = new AltosUIMap();
- map.show(gps, (int) flight_series.value_before(AltosFlightSeries.state_name, gtv.time));
+ double gps_height = gps.alt - gps_pad_altitude;
+ int state = (int) flight_series.value_before(AltosFlightSeries.state_name, gtv.time);
+ map.show(gps, gtv.time, state, gps_height);
this.gps = gps;
has_gps = true;
}
}
if (gtv_last != null) {
int state = (int) flight_series.value_after(AltosFlightSeries.state_name, gtv_last.time);
+ double gps_height = gps.alt - gps_pad_altitude;
if (state == AltosLib.ao_flight_landed)
- map.show(gtv_last.gps, state);
+ map.show(gtv_last.gps, gtv_last.time, state, gps_height);
}
}
super(file.getName());
AltosCalData cal_data = set.cal_data();
+ pane = new JTabbedPane();
+
flight_series = new AltosUIFlightSeries(cal_data);
- set.capture_series(flight_series);
- flight_series.finish();
- pane = new JTabbedPane();
+ enable = new AltosUIEnable(this);
- graph = new AltosGraph(enable, stats, flight_series);
+ set.capture_series(flight_series);
+
+ flight_series.finish();
stats = new AltosFlightStats(flight_series);
- enable = new AltosUIEnable(this);
+ graph = new AltosGraph(enable, stats, flight_series);
statsTable = new AltosFlightStatsTable(stats);