From: Bdale Garbee Date: Wed, 9 Jun 2021 04:57:38 +0000 (-0600) Subject: Merge branch 'branch-1.9' into debian X-Git-Tag: debian/1.9.7-1~2 X-Git-Url: https://git.gag.com/?a=commitdiff_plain;h=20afd87c9591197ed742abce63682f619fc1f185;hp=a35243ed78012f877a36bf747047750dffd6c710;p=fw%2Faltos Merge branch 'branch-1.9' into debian --- diff --git a/ChangeLog b/ChangeLog index f7f62ff3..0a092e36 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,653 @@ +commit 8750dde659cec836fa6354651d5967b7aac1dff0 +Merge: dcd1feb8 24215a4a +Author: Bdale Garbee +Date: Tue Jun 8 22:56:04 2021 -0600 + + Merge branch 'master' into branch-1.9 + +commit 24215a4a2049e51c335b76767f9ed13d186ac408 +Author: Bdale Garbee +Date: Tue Jun 8 22:51:28 2021 -0600 + + doc: update copyright year assertions + +commit ec00f55171a6c5c827c1296178be43d311801be8 +Author: Keith Packard +Date: Mon Apr 12 18:39:48 2021 -0700 + + Version 1.9.7 + + Signed-off-by: Keith Packard + +commit b5ab12ca11272479330a1d630da15cbf0d76735c +Author: Keith Packard +Date: Wed May 19 11:01:16 2021 -0700 + + doc: Update 1.9.7 release notes + + Signed-off-by: Keith Packard + +commit 1d9aaab9209a7afea60a8b394e4d3d5325f0f01e +Author: Keith Packard +Date: Mon Jun 7 16:14:25 2021 -0700 + + altosdroid: Bump to version 29 + + Signed-off-by: Keith Packard + +commit 3104c3d2b1e781592f5d6841ba1ef2ba6c49642b +Author: Keith Packard +Date: Sat May 15 20:19:56 2021 -0700 + + altosdroid: Update target API to 29 + + Required by current Android store + + Signed-off-by: Keith Packard + +commit 82ef65a98e8e018fe8aa0665fd8a4af3fff3097a +Author: Keith Packard +Date: Tue May 11 22:28:32 2021 -0700 + + altosdroid: Revert getResource().getColor to old API + + This should keep it compatible with API version 21 + + Signed-off-by: Keith Packard + +commit 76847aadc1ea770099c6be05727dfa232e53205c +Merge: daa635de 7643f408 +Author: Bdale Garbee +Date: Mon Jun 7 17:11:01 2021 -0600 + + Merge branch 'master' of ssh://git.gag.com/scm/git/fw/altos + +commit 7643f408834a872ed5d7ae67770b1b7c98f3b90c +Author: Keith Packard +Date: Sun May 30 15:08:25 2021 -0700 + + Version 1.9.6.5 + + Signed-off-by: Keith Packard + +commit b45adfbc0eb769800068c2d432e9db52425ee316 +Author: Keith Packard +Date: Wed May 19 10:52:47 2021 -0700 + + altoslib: Protect has_monitor_battery from unset product + + AltosDroid can query has_monitor_battery before the product data has + been set. + + Signed-off-by: Keith Packard + +commit 9a427131788a3e477629a0de26f0f41b5e98333b +Author: Keith Packard +Date: Wed May 19 10:51:44 2021 -0700 + + altosdroid: Don't start bluetooth if address is null + + If the address.address string is null, don't bother starting the + bluetooth service. + + Signed-off-by: Keith Packard + +commit 9eb0fbd7eff5694064f9d123220b523a98fef0a4 +Author: Keith Packard +Date: Wed May 19 10:50:22 2021 -0700 + + altosdroid: protect USB read/write when connection is null + + Check to see if connection is valid before attempting to read/write to + it. + + Signed-off-by: Keith Packard + +commit 55a820e517f9705bc80c653b456ce5d8b3a634bc +Author: Keith Packard +Date: Wed May 19 10:48:58 2021 -0700 + + altosdroid: Synchronize access to the 'rockets' list for online maps + + Online maps gets rockets added by the telem code and the same data are + used to create the maps UI. Synchronise access to that object to prevent + simutaneous operations. + + Signed-off-by: Keith Packard + +commit 09a2a37b31b816236f023ba2a1d767646d5c8f34 +Author: Keith Packard +Date: Wed May 19 10:47:37 2021 -0700 + + altosdroid: Safeguard preferences code in case it's called too early + + Make sure there's a backend set up before accessing data as it seems + this code can be called before the preferences code is called before + the backend is created. + + Signed-off-by: Keith Packard + +commit 0a7cc99d9db45c6c4ba929acf5b57e22d826c82a +Author: Keith Packard +Date: Tue May 18 23:26:12 2021 -0700 + + altosdroid: Skip clicks on BT device entries that are too short + + Maybe these are some kind of extra object? In any case, nothing that + we care about, so just ignore the click. + + Signed-off-by: Keith Packard + +commit daa635de77da3a1926ceb2e2d91e31ec169e173c +Merge: a2e71a40 362f11ff +Author: Bdale Garbee +Date: Tue May 18 23:54:48 2021 -0600 + + Merge branch 'master' of ssh://git.gag.com/scm/git/fw/altos + +commit 362f11fffb63c5c4d4e2ccfc59c0e6ae83a55d01 +Author: Keith Packard +Date: Tue May 18 22:37:01 2021 -0700 + + altoslib: Fix accel value flipping for TM v3.0 + + TM v3.0 uses the same log file format value as TM v2.0 but has a + different accelerometer, which requires a different function for + inverting the raw values. Detect v2.0 devices and use the old function + for them while using the new function for all others. + + Signed-off-by: Keith Packard + +commit a575eebbf87243c3a314929a2469db5bac0c7b42 +Author: Keith Packard +Date: Mon May 17 23:09:29 2021 -0700 + + altosuilib: Zap all flash when upgrading TeleGPS from pre-1.9.7 + + Old versions of TeleGPS firmware would end up spraying log data all + over flash as they mis-computed the place to append new log data. + + When the right hardware is detected, a warning dialog will pop up and, + if agreed to, the log storage flash will be completely erased before + the firmware upgrade happens. + + Signed-off-by: Keith Packard + +commit 565778b66e59069fc6a6d6518f28354eae954dc1 +Author: Keith Packard +Date: Mon May 17 22:38:14 2021 -0700 + + altos: Simplify discovery of log end position + + Binary search using log block indices rather than byte positions. This + makes the code much easier to understand as there isn't a mystic modulus. + + Signed-off-by: Keith Packard + +commit 8dec0d1be5a2d7633045c5c0e86b32a9e6b60299 +Author: Keith Packard +Date: Mon May 17 22:33:21 2021 -0700 + + altos/telegps-*: Fix log end discovery at startup + + We need to find the first unwritten log block to start appending data, + but the code was actually looking for the first empty 256-byte chunk, + which meant that we'd leave a gap of erased data after the previous + log. AltosUI would stop at that point and not recover the remaining + stored data. + + Signed-off-by: Keith Packard + +commit a2e71a40e53602c0cebe4c36d3658201dc0c2bae +Author: Bdale Garbee +Date: Wed May 12 00:27:55 2021 -0600 + + ao-bringup: fix easymotor script to use .bin for dfu-util + +commit fa273e51e772540f61fffbdc4431fe07bcd57630 +Author: Keith Packard +Date: Mon Apr 12 18:38:50 2021 -0700 + + doc: Update for 1.9.7 + + Add release notes + Add specs for EasyMotor + Update copyright year to 2021 + + Signed-off-by: Keith Packard + +commit c4708930ebfbc056bb4faae9b23720d3be401978 +Author: Keith Packard +Date: Mon Apr 12 18:39:48 2021 -0700 + + Version 1.9.7 + + Signed-off-by: Keith Packard + +commit b8437a3f994845dd84080cc20122494aaf901124 +Author: Bdale Garbee +Date: Mon Apr 12 18:36:45 2021 -0600 + + ao-bringup: add tools for flash/cal/test of EasyMotor v2 + +commit 1451e2fd2092d720b0d49b93ac01bed7e88b831f +Merge: 9c26fe3e b115522c +Author: Bdale Garbee +Date: Mon Apr 12 18:27:17 2021 -0600 + + Merge branch 'master' of ssh://git.gag.com/scm/git/fw/altos + +commit 9c26fe3e4fddfd2a3f3e5a7da68ef65422053063 +Author: Bdale Garbee +Date: Mon Apr 12 18:26:46 2021 -0600 + + ao-tools: update ao-flash-stm32f0x to work with openocd in Debian unstable + +commit b115522c41228b26133f322ea68ddb187c0b68cc +Author: Keith Packard +Date: Mon Apr 12 13:04:20 2021 -0700 + + doc: Fix typography in motortest doc + + 1. Use correct quotes. + 2. Eliminate double space after punctuation. + 3. Use elipses instead of three full stops. + + Signed-off-by: Keith Packard + +commit 410af114b4827e46a5a297dbb7c26dc087b932fb +Author: Bdale Garbee +Date: Mon Apr 12 14:02:32 2021 -0600 + + altos: include EasyMotor v2 firmware in upcoming release + +commit 21da0503635a643529d457dccd7e12eb39029fdb +Author: Bdale Garbee +Date: Mon Apr 12 13:51:06 2021 -0600 + + docs: minor text tweak in motor testing docs + +commit c6bcfa5ede86a718105cc334099e4a6b028b08c3 +Author: Keith Packard +Date: Wed Mar 31 09:23:14 2021 -0700 + + altoslib: Write IMU headers to CSV file when present + + The IMU data were being written, but somehow the header was not + included. + + Signed-off-by: Keith Packard + +commit d6be8a279ad233d998c6df8b2efafa34dd5a9a98 +Author: Keith Packard +Date: Sun Mar 28 18:03:56 2021 -0700 + + Version 1.9.6.4 + + Signed-off-by: Keith Packard + +commit da8d7fde56bfd7db02598d2880653fa71846abf7 +Author: Keith Packard +Date: Sun Mar 28 18:03:03 2021 -0700 + + JavaApplicationStub hacks for Big Sur tabbing mode + + Java does not support the 'tabbing' stuff that's in Big Sur, so + disable it. + + Signed-off-by: Keith Packard + +commit 81a6f20fca5df08f3ac08d83a79439502c209df0 +Author: Keith Packard +Date: Sat Mar 27 09:37:49 2021 -0700 + + Add local hacks to JavaApplicationStub + + Fix font rendering. + Add app directory to java.library.path. + + Signed-off-by: Keith Packard + +commit f2d45e21175453a69112fde22bf5b662d9e32adb +Author: Keith Packard +Date: Mon Mar 22 00:06:14 2021 -0700 + + Update JavaApplicationStub to latest release + + Signed-off-by: Keith Packard + +commit c6ef894263068839782716fece54154effd3d0fe +Author: Keith Packard +Date: Mon Mar 22 00:02:33 2021 -0700 + + Add Mac OS X 11 support to JavaApplicationStub + +commit 1d29a584c8387798fb1558fd54a09b1d8fbe90b7 +Author: Keith Packard +Date: Sun Mar 21 23:10:25 2021 -0700 + + altosuilib: Show launch sites at all visible locations on map + + Take each launch site and draw it at every location on the map it + occurs (in case the map shows more than the full globe). This also + automatically handles scrolling the map more than one "rotation". + + Signed-off-by: Keith Packard + +commit 07eecc0ff6e1104f911e5f83d67f3e14dc68c59c +Author: Keith Packard +Date: Sat Feb 27 12:51:56 2021 -0800 + + Version 1.9.6.2 + + Fix micropeak Download on Mac OS X + + Signed-off-by: Keith Packard + +commit 38b360b0b7080b06998d1cac1d6d09957fa44844 +Author: Keith Packard +Date: Sat Feb 27 13:38:54 2021 -0800 + + altosui: open /Library/AltusMetrum on Mac OS X after install + + This helps the user find the documentation. + + Signed-off-by: Keith Packard + +commit 997931d545c977250918a2d608f8c5756de2afcf +Author: Keith Packard +Date: Sat Feb 27 13:23:16 2021 -0800 + + micropeak: Stick docs in Doc dir on Mac OS X + + Follows altosui and telegps installation + + Signed-off-by: Keith Packard + +commit c07b0cd5881ae4e101c41ffa7a1dc6980c3ef357 +Author: Keith Packard +Date: Sat Feb 27 13:22:39 2021 -0800 + + altosui: Show dialog box if sudo fails on Mac OS X + + If the user types the wrong password three times, sudo will give up + and return an error. + + Signed-off-by: Keith Packard + +commit 82bad3d62b91e67f6089e403c4bd4983bf65e449 +Author: Keith Packard +Date: Sat Feb 27 12:51:13 2021 -0800 + + micropeak: Use a menu for 'Download' on Mac OS X + + Attempts to add buttons to the menu bar fail leaving no access to the + download command. + + Signed-off-by: Keith Packard + +commit 0c33e88479ce5fe578cec4296d6196356175d40a +Author: Bdale Garbee +Date: Mon Feb 15 14:27:30 2021 -0700 + + doc: add motortest docs to publish targets + +commit b8e21caf9602b55e9a042f8f0b3cfed1d8975c15 +Author: Bdale Garbee +Date: Mon Feb 15 14:25:47 2021 -0700 + + doc: have motortest documents actually get built by default + +commit 6ac9b490efca17b15317965026c56b4a37d6be82 +Author: Bdale Garbee +Date: Mon Feb 15 14:12:46 2021 -0700 + + doc: make doc be about motor testing in general, not just EasyMotor + +commit afc90f63c6a0c2a511fddc97b72537e0a6f40cfd +Author: Bdale Garbee +Date: Sat Jan 30 11:48:01 2021 -0700 + + doc: add a brief note about TeleBT appearing inert until paired + +commit 7f4059bbe74ecf86842134739ec521dcb646f04f +Author: Bdale Garbee +Date: Sun Jan 17 19:29:28 2021 -0700 + + doc: first draft of manual for EasyMotor + +commit 3af81a45be69b4693396de4a5e2c386be566b933 +Author: Keith Packard +Date: Fri Dec 4 14:58:15 2020 -0800 + + altoslib: Add all known launch sites and names to map preload + + This shows all of the known launch sites and their names in the map + preload screen. + + Signed-off-by: Keith Packard + +commit a4c40ba682acc3ed1808d5a170ddae4114740a39 +Author: Bdale Garbee +Date: Sat Nov 21 11:22:01 2020 -0700 + + doc: add documentation on how to re-flash a TeleMini v3 over USB + +commit 6550585af6d80306d037661be66004ccf8d09013 +Merge: c992792b 42226344 +Author: Bdale Garbee +Date: Sat Nov 21 11:00:43 2020 -0700 + + Merge branch 'master' of ssh://git.gag.com/scm/git/fw/altos + +commit 42226344f0b5443fdd93034dd51e608370717c46 +Author: Keith Packard +Date: Thu Nov 5 21:59:27 2020 -0800 + + ao-tools/ao-dump-up: Recognize MicroTest data + + Spit out a special message when MicroTest data is read to make testing + µPusb easier. + + Signed-off-by: Keith Packard + +commit a9d4856d3f03fae159c120d8d8030c78eaf15253 +Author: Keith Packard +Date: Thu Nov 5 21:58:04 2020 -0800 + + altos: Add 'microtest' -- micropeak load for testing µPusb + + This is custom MicroPeak firmware that just repeatedly generates + constant flight log data which can be used to validate µPusb boards. + + Signed-off-by: Keith Packard + +commit 898ef1a085f9d4541c3987d8d4f0daac0093ed49 +Author: Keith Packard +Date: Thu Oct 29 11:41:55 2020 -0700 + + Version 1.9.6.1 + + Intermediate release containing altoslib fixes for TeleMega v4.0 in + Antenna Down configuration. + + Signed-off-by: Keith Packard + +commit 6dc5b468f84f04f28ea83757cee0486f654fb234 +Author: Keith Packard +Date: Thu Oct 29 11:40:25 2020 -0700 + + altoslib: Delay accel cal value adjustment until data all read + + Instead of trying to compute these values as soon as the necessary + data are available, delay until all data are available as which data + are necessary depends on the target device, and some target devices + don't have some of the data values at all. + + Signed-off-by: Keith Packard + +commit ceca79d6b20cf623e7a7214e400347fc0bc019dd +Author: Keith Packard +Date: Thu Oct 29 11:38:55 2020 -0700 + + altoslib: Fix accel inversion for TeleMega v4.0 + + TeleMega v4.0 uses the adxl375, just like EasyMega v2.0 + + Signed-off-by: Keith Packard + +commit 4358d83ba96b072cabd344e287fa77005968690f +Author: Keith Packard +Date: Thu Oct 29 11:37:03 2020 -0700 + + altoslib: Avoid sending negative accel cal values to flight computer + + Pre-1.9.7 firmware does not handle negative values. Instead, send + large positive values which will wrap around to negative values inside + the flight computer. + + Signed-off-by: Keith Packard + +commit d1a2932e080041cfe107e00e7b23213026d1fb81 +Author: Keith Packard +Date: Wed Oct 28 14:32:16 2020 -0700 + + ao-bringup: Delay before testing easymini for 0.25 seconds + + EasyMini isn't quite ready to play when the USB is first detected as + the sensors haven't yet been initialized. Wait for 0.25 seconds to + give the board time to finish initializing. + + Signed-off-by: Keith Packard + +commit 6a1d6499fd7ca2b3a9702e21af2a7584ef2b6480 +Author: Keith Packard +Date: Mon Oct 26 21:53:54 2020 -0700 + + altos: Don't wait after igniter in manual mode + + There's no reason to delay between igniter firings in manual mode, and + it slows down testing. + + Signed-off-by: Keith Packard + +commit c992792ba6a76a0bc1d31ccdcffa2d6ca52a9e55 +Author: Bdale Garbee +Date: Mon Nov 16 10:50:49 2020 -0700 + + put notes in Releasing about keeping doc/header.inc up to date + +commit 427e67f9e8914327243c0fdd1379365fe4e03623 +Author: Bdale Garbee +Date: Mon Nov 16 10:47:53 2020 -0700 + + TeleLaunch docs should use telelaunch.txt, update copyright year, lose "draft" + +commit 6e001281b01176963836d7b7d0bd6973b788dd63 +Author: Keith Packard +Date: Fri Oct 23 17:05:37 2020 -0700 + + altoslib, altosui: Don't show apogee/main for EasyTimer Fire Igniter + + Don't create igniter lines for a device which doesn't have them. + + Signed-off-by: Keith Packard + +commit a214f039e8404da7529b6799ab6a907c3744e1bc +Author: Keith Packard +Date: Fri Oct 23 16:14:13 2020 -0700 + + altos/easytimer-v1: Switch from including adxl375 to bmx160 + + These aren't really necessary at all as ao_data includes them, but + it's nice to have them listed for documentation purposes. + + Signed-off-by: Keith Packard + +commit 1a3c0805f88c50f27dd4e78b9be2a4c3ef9e46c8 +Author: Keith Packard +Date: Fri Oct 23 16:13:47 2020 -0700 + + altos/easymotor-v2: Increase default flight log size + + Switch to 4 flights by default, with 2MB per flight. + + Signed-off-by: Keith Packard + +commit a9014be707c4325b55e0f2797796e7c96aea1e03 +Author: Keith Packard +Date: Fri Oct 23 16:12:36 2020 -0700 + + altosui: Match against basestations when determining remote + + These two cases were matching against !altimeters instead, which isn't + true for EasyMotor or EasyTimer. + + Signed-off-by: Keith Packard + +commit 40c6aa050654d43f20c6a9c6bd67541e1747ae38 +Author: Keith Packard +Date: Fri Oct 23 16:10:43 2020 -0700 + + altoslib, altosuilib: Get Idle Monitor working with EasyTimer and EasyMotor + + This involve splitting out the gyro and mag sensor handling from the + 3-d accel stuff, displaying only information that is present. The IMU + support now allows for using the along axis as the primary + acceleration indicator. The Adxl375 now allows using all three axes as + the 3d accelerometer. + + Signed-off-by: Keith Packard + +commit b6c066d7261d398cb7bfe6503518022194431337 +Author: Keith Packard +Date: Fri Oct 23 16:02:07 2020 -0700 + + altoslib: Set all 3 axes of accel cal data when present + + Use the new accel cal function in altos to set all three axes + + Signed-off-by: Keith Packard + +commit f7c8f0b14cf19804106860a5689cf1f37df20669 +Author: Keith Packard +Date: Fri Oct 23 16:00:01 2020 -0700 + + altos: Make accel cal take three axes when present + + This allows AltosUI to save/restore all of the accel calibration + values instead of just the primary axis. + + Signed-off-by: Keith Packard + +commit ecf782359d3038399049ec5cc0a2b3071e14c78f +Author: Keith Packard +Date: Thu Oct 22 20:48:26 2020 -0700 + + libaltos: Add windows override for EasyTimer USB ID + + Windows doesn't use the product name from the device, instead it uses + whatever was in the .ini file, which was "TeleTerra" for the EasyTimer ID. + + Signed-off-by: Keith Packard + +commit 365bfb9c0720d537c7d65baf871d5dcd7c08de35 +Author: Keith Packard +Date: Thu Oct 22 20:52:03 2020 -0700 + + Update 1.9.6 release date. Add note to Releasing about date + + Need to update the release date as well as the release version; that's + where all of the dates in the various docs comes from. + + Signed-off-by: Keith Packard + +commit dcd1feb83e5534ea3135358456b748f242878b46 +Author: Bdale Garbee +Date: Thu Oct 22 16:19:33 2020 -0600 + + releaseing 1.9.6 + commit 38bcc2b8b2b560271902eb8a3eba467866a38628 Merge: 628da1fe c16cb712 Author: Bdale Garbee diff --git a/Makefile.am b/Makefile.am index 328d5700..fa38cf2f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -53,6 +53,7 @@ fat_altos = \ src/easymega-v1.0/easymega-v1.0-$(VERSION).ihx \ src/easymega-v2.0/easymega-v2.0-$(VERSION).ihx \ src/easymini-v1.0/easymini-v1.0-$(VERSION).ihx \ + src/easymotor-v2/easymotor-v2-$(VERSION).ihx \ src/easytimer-v1/easytimer-v1-$(VERSION).ihx \ src/telebt-v3.0/telebt-v3.0-$(VERSION).ihx \ src/telebt-v4.0/telebt-v4.0-$(VERSION).ihx \ diff --git a/Releasing b/Releasing index c29e61c3..b54e236f 100644 --- a/Releasing +++ b/Releasing @@ -27,6 +27,8 @@ These are Keith's notes on how to do a release - make sure doc/Makefile points at that too + - confirm doc/header.inc has correct copyright year + These are Bdale's notes on how to do a release. - make sure Debian build environment is up to date @@ -59,6 +61,7 @@ These are Bdale's notes on how to do a release. - make sure there is a doc/release-notes-.inc - make sure that doc/*.txt have the right copyright year and the new release is included + - confirm doc/header.inc has correct copyright year - make absolutely sure checked-out tree is "clean" - make absolutely sure any commits Keith might have pushed to branches like debian are already pulled @@ -106,6 +109,7 @@ These are Bdale's notes on how to do a release. src/easymega-v2.0/{*.elf,*.ihx,*.map} \ src/easymini-v1.0/{*.elf,*.ihx,*.map} \ src/easymini-v2.0/{*.elf,*.ihx,*.map} \ + src/easymotor-v2/{*.elf,*.ihx,*.map} \ src/easytimer-v1/{*.elf,*.ihx,*.map} \ src/telebt-v3.0/{*.elf,*.ihx,*.map} \ src/telebt-v4.0/{*.elf,*.ihx,*.map} \ @@ -125,6 +129,7 @@ These are Bdale's notes on how to do a release. src/easymega-v2.0/flash-loader/*.elf \ src/easymini-v1.0/flash-loader/*.elf \ src/easymini-v2.0/flash-loader/{*.elf,*.bin,*.map} \ + src/easymotor-v2/flash-loader/*.elf \ src/easytimer-v1/flash-loader/*.elf \ src/telebt-v3.0/flash-loader/*.elf \ src/telebt-v4.0/flash-loader/{*.elf,*.bin,*.map} \ diff --git a/altosdroid/app/build.gradle.in b/altosdroid/app/build.gradle.in index 5dbd30ee..763b1657 100644 --- a/altosdroid/app/build.gradle.in +++ b/altosdroid/app/build.gradle.in @@ -18,7 +18,7 @@ android { defaultConfig { applicationId "org.altusmetrum.AltosDroid" minSdkVersion 21 - targetSdkVersion 28 + targetSdkVersion 29 versionCode @ANDROID_VERSION@ versionName "@VERSION@" } diff --git a/altosdroid/app/src/main/java/org/altusmetrum/AltosDroid/AltosDroid.java b/altosdroid/app/src/main/java/org/altusmetrum/AltosDroid/AltosDroid.java index e564e784..404b63ac 100644 --- a/altosdroid/app/src/main/java/org/altusmetrum/AltosDroid/AltosDroid.java +++ b/altosdroid/app/src/main/java/org/altusmetrum/AltosDroid/AltosDroid.java @@ -630,7 +630,7 @@ public class AltosDroid extends FragmentActivity implements AltosUnitsListener, 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, getTheme()); + mAgeOldColor = getResources().getColor(R.color.old_color); } private void ensureBluetooth() { diff --git a/altosdroid/app/src/main/java/org/altusmetrum/AltosDroid/AltosDroidPreferences.java b/altosdroid/app/src/main/java/org/altusmetrum/AltosDroid/AltosDroidPreferences.java index f49f1100..4d9204d9 100644 --- a/altosdroid/app/src/main/java/org/altusmetrum/AltosDroid/AltosDroidPreferences.java +++ b/altosdroid/app/src/main/java/org/altusmetrum/AltosDroid/AltosDroidPreferences.java @@ -72,6 +72,8 @@ public class AltosDroidPreferences extends AltosPreferences { } public static void set_active_device(DeviceAddress address) { + if (backend == null) + return; synchronized(backend) { active_device_address = address; if (active_device_address != null) { @@ -86,6 +88,9 @@ public class AltosDroidPreferences extends AltosPreferences { } public static DeviceAddress active_device() { + if (backend == null) + return null; + synchronized(backend) { return active_device_address; } @@ -94,6 +99,8 @@ public class AltosDroidPreferences extends AltosPreferences { static LinkedList map_source_listeners; public static void set_map_source(int map_source) { + if (backend == null) + return; synchronized(backend) { AltosDroidPreferences.map_source = map_source; backend.putInt(mapSourcePreference, map_source); @@ -107,12 +114,17 @@ public class AltosDroidPreferences extends AltosPreferences { } public static int map_source() { + if (backend == null) + return MAP_SOURCE_ONLINE; synchronized(backend) { return map_source; } } public static void register_map_source_listener(AltosDroidMapSourceListener l) { + if (backend == null) + return; + synchronized(backend) { if (map_source_listeners == null) map_source_listeners = new LinkedList(); @@ -121,18 +133,25 @@ public class AltosDroidPreferences extends AltosPreferences { } public static void unregister_map_source_listener(AltosDroidMapSourceListener l) { + if (backend == null) + return; synchronized(backend) { map_source_listeners.remove(l); } } public static int font_size() { + if (backend == null) + return font_size_medium; + synchronized (backend) { return font_size; } } public static void set_font_size(int new_font_size) { + if (backend == null) + return; synchronized (backend) { if (font_size != new_font_size) { font_size = new_font_size; @@ -144,12 +163,18 @@ public class AltosDroidPreferences extends AltosPreferences { public static int tracker_sort() { + if (backend == null) + return 0; + synchronized(backend) { return tracker_sort; } } public static void set_tracker_sort(int new_tracker_sort) { + if (backend == null) + return; + synchronized(backend) { if (tracker_sort != new_tracker_sort) { tracker_sort = new_tracker_sort; diff --git a/altosdroid/app/src/main/java/org/altusmetrum/AltosDroid/AltosMapOffline.java b/altosdroid/app/src/main/java/org/altusmetrum/AltosDroid/AltosMapOffline.java index cca958c5..60c209e1 100644 --- a/altosdroid/app/src/main/java/org/altusmetrum/AltosDroid/AltosMapOffline.java +++ b/altosdroid/app/src/main/java/org/altusmetrum/AltosDroid/AltosMapOffline.java @@ -223,12 +223,20 @@ public class AltosMapOffline extends View implements ScaleGestureDetector.OnScal MapMark(double lat, double lon, int state) { super(lat, lon, state); } + + MapMark(double lat, double lon, int state, String label) { + super(lat, lon, state, label); + } } public AltosMapMark new_mark(double lat, double lon, int state) { return new MapMark(lat, lon, state); } + public AltosMapMark new_mark(double lat, double lon, int state, String label) { + return new MapMark(lat, lon, state, label); + } + public int width() { return getWidth(); } diff --git a/altosdroid/app/src/main/java/org/altusmetrum/AltosDroid/AltosMapOnline.java b/altosdroid/app/src/main/java/org/altusmetrum/AltosDroid/AltosMapOnline.java index c35bbb4d..76cd990b 100644 --- a/altosdroid/app/src/main/java/org/altusmetrum/AltosDroid/AltosMapOnline.java +++ b/altosdroid/app/src/main/java/org/altusmetrum/AltosDroid/AltosMapOnline.java @@ -174,10 +174,12 @@ public class AltosMapOnline implements AltosDroidMapInterface, GoogleMap.OnMarke } private RocketOnline[] sorted_rockets() { - RocketOnline[] rocket_array = rockets.values().toArray(new RocketOnline[0]); + synchronized(rockets) { + RocketOnline[] rocket_array = rockets.values().toArray(new RocketOnline[0]); - Arrays.sort(rocket_array); - return rocket_array; + Arrays.sort(rocket_array); + return rocket_array; + } } public void onMapClick(LatLng lat_lng) { @@ -260,22 +262,26 @@ public class AltosMapOnline implements AltosDroidMapInterface, GoogleMap.OnMarke 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); + synchronized(rockets) { + 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); + synchronized(rockets) { + RocketOnline rocket = rockets.get(serial); + rocket.remove(); + rockets.remove(serial); + } } public void set_visible(boolean visible) { @@ -286,13 +292,15 @@ public class AltosMapOnline implements AltosDroidMapInterface, GoogleMap.OnMarke 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.containsKey(serial)) - remove_rocket(serial); - } + synchronized(rockets) { + for (int serial : rockets.keySet()) { + if (!telem_state.containsKey(serial)) + remove_rocket(serial); + } - for (int serial : telem_state.keySet()) { - set_rocket(serial, telem_state.get(serial)); + for (int serial : telem_state.keySet()) { + set_rocket(serial, telem_state.get(serial)); + } } } diff --git a/altosdroid/app/src/main/java/org/altusmetrum/AltosDroid/AltosUsb.java b/altosdroid/app/src/main/java/org/altusmetrum/AltosDroid/AltosUsb.java index 35514483..ad47707d 100644 --- a/altosdroid/app/src/main/java/org/altusmetrum/AltosDroid/AltosUsb.java +++ b/altosdroid/app/src/main/java/org/altusmetrum/AltosDroid/AltosUsb.java @@ -210,12 +210,16 @@ public class AltosUsb extends AltosDroidLink { } int read(byte[] buffer, int len) { + if (connection == null) + return 0; int ret = connection.bulkTransfer(in, buffer, len, -1); AltosDebug.debug("read(%d) = %d\n", len, ret); return ret; } int write(byte[] buffer, int len) { + if (connection == null) + return 0; int ret = connection.bulkTransfer(out, buffer, len, -1); AltosDebug.debug("write(%d) = %d\n", len, ret); return ret; diff --git a/altosdroid/app/src/main/java/org/altusmetrum/AltosDroid/DeviceListActivity.java b/altosdroid/app/src/main/java/org/altusmetrum/AltosDroid/DeviceListActivity.java index 1c3e1dba..60fba9d3 100644 --- a/altosdroid/app/src/main/java/org/altusmetrum/AltosDroid/DeviceListActivity.java +++ b/altosdroid/app/src/main/java/org/altusmetrum/AltosDroid/DeviceListActivity.java @@ -152,11 +152,16 @@ public class DeviceListActivity extends Activity { // 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) { + // Get the device MAC address, which is the last 17 chars in the View + String info = ((TextView) v).getText().toString(); + + /* Ignore clicks on items that are too short */ + if (info.length() <= 17) + return; + // 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'); diff --git a/altosdroid/app/src/main/java/org/altusmetrum/AltosDroid/TelemetryService.java b/altosdroid/app/src/main/java/org/altusmetrum/AltosDroid/TelemetryService.java index 31616c82..2c2095df 100644 --- a/altosdroid/app/src/main/java/org/altusmetrum/AltosDroid/TelemetryService.java +++ b/altosdroid/app/src/main/java/org/altusmetrum/AltosDroid/TelemetryService.java @@ -416,7 +416,7 @@ public class TelemetryService extends Service implements AltosIdleMonitorListene } private void start_altos_bluetooth(DeviceAddress address, boolean pause) { - if (bluetooth_adapter == null || !bluetooth_adapter.isEnabled()) + if (bluetooth_adapter == null || !bluetooth_adapter.isEnabled() || address.address == null) return; disconnect(false); diff --git a/altoslib/AltosAccelCal.java b/altoslib/AltosAccelCal.java index 38c4182c..8d0e9927 100644 --- a/altoslib/AltosAccelCal.java +++ b/altoslib/AltosAccelCal.java @@ -181,8 +181,20 @@ public class AltosAccelCal implements Runnable { plus, minus); if (config_data.pad_orientation != AltosLib.MISSING) link.printf("c o %d\n", config_data.pad_orientation); - if (plus != AltosLib.MISSING && minus != AltosLib.MISSING) - link.printf("c a %d %d\n", plus, minus); + if (plus != AltosLib.MISSING && minus != AltosLib.MISSING && plus != 0) { + if (plus < 0) + plus = 65536 + plus; + if (minus < 0) + minus = 65536 + minus; + if (config_data.accel_zero_along != AltosLib.MISSING) + link.printf("c a %d %d %d %d %d\n", + plus, minus, + config_data.accel_zero_along, + config_data.accel_zero_across, + config_data.accel_zero_through); + else + link.printf("c a %d %d\n", plus, minus); + } link.flush_output(); stop_link(); } diff --git a/altoslib/AltosAdxl375.java b/altoslib/AltosAdxl375.java index 621cceeb..5e490541 100644 --- a/altoslib/AltosAdxl375.java +++ b/altoslib/AltosAdxl375.java @@ -22,7 +22,7 @@ import java.util.concurrent.*; public class AltosAdxl375 implements Cloneable { - private int accel; + private int[] accels = new int[3]; private int axis; public static final int X_AXIS = 0; @@ -35,7 +35,8 @@ public class AltosAdxl375 implements Cloneable { if (axis == AltosLib.MISSING) throw new NumberFormatException("No ADXL375 axis specified"); if (items.length >= 3) { - accel = Integer.parseInt(items[2 + axis]); + for (int i = 0; i < 3; i++) + accels[i] = Integer.parseInt(items[2+i]); return true; } } @@ -45,22 +46,50 @@ public class AltosAdxl375 implements Cloneable { public AltosAdxl375 clone() { AltosAdxl375 n = new AltosAdxl375(axis); - n.accel = accel; + for (int i = 0; i < 3; i++) + n.accels[i] = accels[i]; return n; } - static public void provide_data(AltosDataListener listener, AltosLink link) throws InterruptedException, AltosUnknownProduct { + private int accel_along() { + return accels[axis]; + } + + private int accel_across() { + if (axis == X_AXIS) + return accels[Y_AXIS]; + else + return accels[X_AXIS]; + } + + private int accel_through() { + return accels[Z_AXIS]; + } + + static public void provide_data(AltosDataListener listener, AltosLink link, boolean three_axis, int imu_type) throws InterruptedException, AltosUnknownProduct { try { AltosCalData cal_data = listener.cal_data(); AltosAdxl375 adxl375 = new AltosAdxl375(link, cal_data.adxl375_axis); if (adxl375 != null) { - int accel = adxl375.accel; - if (cal_data.adxl375_inverted) + int accel = adxl375.accel_along(); + if (!cal_data.adxl375_inverted) accel = -accel; if (cal_data.pad_orientation == 1) accel = -accel; listener.set_acceleration(cal_data.acceleration(accel)); + if (three_axis) { + cal_data.set_imu_type(imu_type); + double accel_along = cal_data.accel_along(-accel); + double accel_across = cal_data.accel_across(adxl375.accel_across()); + double accel_through = cal_data.accel_through(adxl375.accel_through()); + listener.set_accel_ground(accel_along, + accel_across, + accel_through); + listener.set_accel(accel_along, + accel_across, + accel_through); + } } } catch (TimeoutException te) { } catch (NumberFormatException ne) { @@ -68,7 +97,8 @@ public class AltosAdxl375 implements Cloneable { } public AltosAdxl375() { - accel = AltosLib.MISSING; + for (int i = 0; i < 3; i++) + accels[i] = AltosLib.MISSING; axis = AltosLib.MISSING; } diff --git a/altoslib/AltosCSV.java b/altoslib/AltosCSV.java index 765eb445..16c57ec1 100644 --- a/altoslib/AltosCSV.java +++ b/altoslib/AltosCSV.java @@ -408,6 +408,10 @@ public class AltosCSV implements AltosWriter { out.printf(","); write_3d_accel_header(); } + if (has_imu) { + out.printf(","); + write_imu_header(); + } if (has_igniter) { out.printf(","); write_igniter_header(); diff --git a/altoslib/AltosConfigData.java b/altoslib/AltosConfigData.java index 83f3ca07..b6105f92 100644 --- a/altoslib/AltosConfigData.java +++ b/altoslib/AltosConfigData.java @@ -199,19 +199,32 @@ public class AltosConfigData { case AltosLib.AO_LOG_FORMAT_FULL: return 0x7fff - value; case AltosLib.AO_LOG_FORMAT_TELEMEGA_OLD: - case AltosLib.AO_LOG_FORMAT_TELEMETRUM: case AltosLib.AO_LOG_FORMAT_TELEMEGA: case AltosLib.AO_LOG_FORMAT_TELEMEGA_3: - case AltosLib.AO_LOG_FORMAT_TELEMEGA_4: return 4095 - value; + case AltosLib.AO_LOG_FORMAT_TELEMETRUM: + /* + * TeleMetrum v2 and later use the same log format, but + * have different accelerometers. This is the only place + * it matters in altoslib. + */ + if (product.startsWith("TeleMetrum-v2")) + return 4095 - value; + /* fall through */ + case AltosLib.AO_LOG_FORMAT_TELEMEGA_4: case AltosLib.AO_LOG_FORMAT_EASYMEGA_2: + case AltosLib.AO_LOG_FORMAT_EASYMOTOR: return -value; default: + if (product.startsWith("EasyTimer-")) + return -value; return AltosLib.MISSING; } } public boolean has_monitor_battery() { + if (product == null) + return false; if (product.startsWith("TeleBT")) return true; return false; @@ -318,6 +331,9 @@ public class AltosConfigData { /* Return + accel calibration relative to a specific pad orientation */ public int accel_cal_plus(int pad_orientation) { adjust_accel_cal(); + if (!accel_cal_adjusted) + return AltosLib.MISSING; + switch (pad_orientation) { case AltosLib.AO_PAD_ORIENTATION_ANTENNA_UP: case AltosLib.AO_PAD_ORIENTATION_WORDS_UPRIGHT: @@ -335,6 +351,9 @@ public class AltosConfigData { /* Return - accel calibration relative to a specific pad orientation */ public int accel_cal_minus(int pad_orientation) { adjust_accel_cal(); + if (!accel_cal_adjusted) + return AltosLib.MISSING; + switch (pad_orientation) { case AltosLib.AO_PAD_ORIENTATION_ANTENNA_UP: case AltosLib.AO_PAD_ORIENTATION_WORDS_UPRIGHT: @@ -354,10 +373,10 @@ public class AltosConfigData { */ private void adjust_accel_cal() { if (!accel_cal_adjusted && + product != null && pad_orientation != AltosLib.MISSING && accel_cal_plus != AltosLib.MISSING && - accel_cal_minus != AltosLib.MISSING && - log_format != AltosLib.AO_LOG_FORMAT_UNKNOWN) + accel_cal_minus != AltosLib.MISSING) { switch (pad_orientation) { case AltosLib.AO_PAD_ORIENTATION_ANTENNA_UP: @@ -536,9 +555,6 @@ public class AltosConfigData { } } } catch (Exception e) {} - - /* Fix accel cal as soon as all of the necessary values appear */ - adjust_accel_cal(); } public AltosConfigData() { @@ -636,6 +652,8 @@ public class AltosConfigData { return true; if (product.startsWith("TeleMega-v4")) return true; + if (product.startsWith("EasyMotor-v2")) + return true; } throw new AltosUnknownProduct(product); } @@ -648,6 +666,9 @@ public class AltosConfigData { return AltosAdxl375.X_AXIS; if (product.startsWith("TeleMega-v4")) return AltosAdxl375.X_AXIS; + if (product.startsWith("EasyMotor-v2")) + return AltosAdxl375.X_AXIS; + } throw new AltosUnknownProduct(product); } @@ -831,8 +852,22 @@ public class AltosConfigData { link.printf("c o %d\n", pad_orientation); int plus = accel_cal_plus(pad_orientation); int minus = accel_cal_minus(pad_orientation); - if (plus != AltosLib.MISSING && minus != AltosLib.MISSING) - link.printf("c a %d %d\n", plus, minus); + if (plus != AltosLib.MISSING && minus != AltosLib.MISSING) { + if (plus < 0) + plus = 65536 + plus; + if (minus < 0) + minus = 65536 + minus; + if (accel_zero_along != AltosLib.MISSING && + accel_zero_across != AltosLib.MISSING && + accel_zero_through != AltosLib.MISSING) + link.printf("c a %d %d %d %d %d\n", + plus, minus, + accel_zero_along, + accel_zero_across, + accel_zero_through); + else + link.printf("c a %d %d\n", plus, minus); + } /* HAS_LOG */ if (flight_log_max != 0 && flight_log_max != AltosLib.MISSING) @@ -893,5 +928,6 @@ public class AltosConfigData { read_link(link, "done"); break; } + adjust_accel_cal(); } } diff --git a/altoslib/AltosIMU.java b/altoslib/AltosIMU.java index 2944a2a5..f3c85e9a 100644 --- a/altoslib/AltosIMU.java +++ b/altoslib/AltosIMU.java @@ -56,7 +56,10 @@ public class AltosIMU implements Cloneable { } public static double convert_accel(double counts, int imu_type) { - return counts / counts_per_g(imu_type) * AltosConvert.gravity; + double cpg = counts_per_g(imu_type); + if (cpg == AltosLib.MISSING) + return AltosLib.MISSING; + return counts / cpg * AltosConvert.gravity; } public static final double GYRO_FULLSCALE_DEGREES_MPU = 2000.0; @@ -82,7 +85,10 @@ public class AltosIMU implements Cloneable { } public static double gyro_degrees_per_second(double counts, int imu_type) { - return counts / counts_per_degree(imu_type); + double cpd = counts_per_degree(imu_type); + if (cpd == AltosLib.MISSING) + return AltosLib.MISSING; + return counts / cpd; } public static final int imu_axis_x = 0; @@ -112,7 +118,10 @@ public class AltosIMU implements Cloneable { } public static double convert_gauss(double counts, int imu_type, int imu_axis) { - return counts / counts_per_gauss(imu_type, imu_axis); + double cpg = counts_per_gauss(imu_type, imu_axis); + if (cpg == AltosLib.MISSING) + return AltosLib.MISSING; + return counts / cpg; } public boolean parse_string(String line) { @@ -301,6 +310,15 @@ public class AltosIMU implements Cloneable { } } + private static boolean is_primary_accel(int imu_type) { + switch (imu_type) { + case imu_type_easytimer_v1: + return true; + default: + return false; + } + } + public static int mag_through_axis(int imu_type) { return imu_axis_z; } @@ -318,6 +336,7 @@ public class AltosIMU implements Cloneable { if (imu != null) { if (imu.gyro_x != AltosLib.MISSING) { + cal_data.set_gyro_zero(0, 0, 0); listener.set_gyro(cal_data.gyro_roll(imu.gyro_roll(imu_type)), cal_data.gyro_pitch(imu.gyro_pitch(imu_type)), cal_data.gyro_yaw(imu.gyro_yaw(imu_type))); @@ -328,6 +347,14 @@ public class AltosIMU implements Cloneable { listener.set_accel(cal_data.accel_along(imu.accel_along(imu_type)), cal_data.accel_across(imu.accel_across(imu_type)), cal_data.accel_through(imu.accel_through(imu_type))); + if (is_primary_accel(imu_type)) { + int accel = imu.accel_along(imu_type); + if (!cal_data.adxl375_inverted) + accel = -accel; + if (cal_data.pad_orientation == 1) + accel = -accel; + listener.set_acceleration(cal_data.acceleration(accel)); + } if (imu.mag_x != AltosLib.MISSING) { listener.set_mag(cal_data.mag_along(imu.mag_along(imu_type)), cal_data.mag_across(imu.mag_across(imu_type)), diff --git a/altoslib/AltosIdleFetch.java b/altoslib/AltosIdleFetch.java index 1ac075e3..c4a32788 100644 --- a/altoslib/AltosIdleFetch.java +++ b/altoslib/AltosIdleFetch.java @@ -38,6 +38,7 @@ class AltosIdler { static final int idle_mma655x = 8; static final int idle_ms5607 = 9; static final int idle_adxl375 = 10; + static final int idle_adxl375_easymotor_v2 = 11; static final int idle_sensor_tm = 100; static final int idle_sensor_metrum = 101; @@ -49,6 +50,7 @@ class AltosIdler { static final int idle_sensor_tgps2 = 107; static final int idle_sensor_tmini3 = 108; static final int idle_sensor_easytimer1 = 109; + static final int idle_sensor_easymotor2 = 110; public void provide_data(AltosDataListener listener, AltosLink link) throws InterruptedException, TimeoutException, AltosUnknownProduct { for (int idler : idlers) { @@ -81,7 +83,10 @@ class AltosIdler { AltosMma655x.provide_data(listener, link); break; case idle_adxl375: - AltosAdxl375.provide_data(listener, link); + AltosAdxl375.provide_data(listener, link, false, AltosLib.MISSING); + break; + case idle_adxl375_easymotor_v2: + AltosAdxl375.provide_data(listener, link, true, AltosIMU.imu_type_easymotor_v2); break; case idle_ms5607: AltosMs5607.provide_data(listener, link); @@ -116,6 +121,9 @@ class AltosIdler { case idle_sensor_easytimer1: AltosSensorEasyTimer1.provide_data(listener, link); break; + case idle_sensor_easymotor2: + AltosSensorEasyMotor2.provide_data(listener, link); + break; } } } @@ -219,6 +227,9 @@ public class AltosIdleFetch implements AltosDataProvider { new AltosIdler("EasyTimer-v1", AltosIdler.idle_imu_et_v1, AltosIdler.idle_sensor_easytimer1), + new AltosIdler("EasyMotor-v2", + AltosIdler.idle_adxl375_easymotor_v2, + AltosIdler.idle_sensor_easymotor2), }; AltosLink link; diff --git a/altoslib/AltosIgnite.java b/altoslib/AltosIgnite.java index d4acda37..d1ec5104 100644 --- a/altoslib/AltosIgnite.java +++ b/altoslib/AltosIgnite.java @@ -27,7 +27,8 @@ public class AltosIgnite { boolean remote; boolean close_on_exit; boolean link_started; - boolean have_npyro = false; + boolean has_pyro_info = false; + boolean has_standard = false; int npyro; AltosConfigData config_data; @@ -106,11 +107,14 @@ public class AltosIgnite { npyro = config_data.npyro; else npyro = 0; - have_npyro = true; + if (config_data != null) + has_standard = config_data.ignite_mode != AltosLib.MISSING; + + has_pyro_info = true; } public int npyro() throws InterruptedException, TimeoutException { - if (!have_npyro) { + if (!has_pyro_info) { start_link(); get_npyro(); stop_link(); @@ -118,6 +122,15 @@ public class AltosIgnite { return npyro; } + public boolean has_standard() throws InterruptedException, TimeoutException { + if (!has_pyro_info) { + start_link(); + get_npyro(); + stop_link(); + } + return has_standard; + } + public HashMap status() throws InterruptedException, TimeoutException { HashMap status = new HashMap(); diff --git a/altoslib/AltosLink.java b/altoslib/AltosLink.java index b713b3dc..9346563d 100644 --- a/altoslib/AltosLink.java +++ b/altoslib/AltosLink.java @@ -507,6 +507,20 @@ public abstract class AltosLink implements Runnable { return ret; } + public void synchronize(int timeout) throws InterruptedException { + printf("v\n"); + for (;;) { + String line = get_reply(timeout); + + if (line == null) + break; + if (line.startsWith("software-version")) + break; + if (line.startsWith("altos-loader")) + break; + } + } + public void to_loader() throws InterruptedException { printf("X\n"); flush_output(); diff --git a/altoslib/AltosMap.java b/altoslib/AltosMap.java index 519ecfdf..3877c7dc 100644 --- a/altoslib/AltosMap.java +++ b/altoslib/AltosMap.java @@ -82,7 +82,7 @@ public class AltosMap implements AltosMapTileListener, AltosMapStoreListener { static final long auto_scroll_delay = 20 * 1000; public AltosMapTransform transform; - AltosLatLon centre; + public AltosLatLon centre; public void reset() { // nothing @@ -289,10 +289,10 @@ public class AltosMap implements AltosMapTileListener, AltosMapStoreListener { centre(lat_lon); } - public AltosMapMark add_mark(double lat, double lon, int state) { + public AltosMapMark add_mark(double lat, double lon, int state, String label) { AltosMapMark mark; synchronized(marks) { - mark = map_interface.new_mark(lat, lon, state); + mark = map_interface.new_mark(lat, lon, state, label); if (mark != null) marks.add(mark); } @@ -300,6 +300,10 @@ public class AltosMap implements AltosMapTileListener, AltosMapStoreListener { return mark; } + public AltosMapMark add_mark(double lat, double lon, int state) { + return add_mark(lat, lon, state, null); + } + public void del_mark(AltosMapMark mark) { marks.remove(mark); } diff --git a/altoslib/AltosMapInterface.java b/altoslib/AltosMapInterface.java index 0ce49d12..560f85da 100644 --- a/altoslib/AltosMapInterface.java +++ b/altoslib/AltosMapInterface.java @@ -30,6 +30,8 @@ public interface AltosMapInterface { public abstract AltosMapMark new_mark(double lat, double lon, int state); + public abstract AltosMapMark new_mark(double lat, double lon, int state, String label); + public abstract AltosMapTile new_tile(AltosMapCache cache, AltosLatLon upper_left, AltosLatLon center, int zoom, int maptype, int px_size, int scale); public abstract int width(); diff --git a/altoslib/AltosMapMark.java b/altoslib/AltosMapMark.java index dcb75430..0676f54f 100644 --- a/altoslib/AltosMapMark.java +++ b/altoslib/AltosMapMark.java @@ -27,13 +27,23 @@ public abstract class AltosMapMark { public AltosLatLon lat_lon; public int state; + public String label; static public int stroke_width = 6; public abstract void paint(AltosMapTransform t); - public AltosMapMark (double lat, double lon, int state) { + public AltosMapMark (double lat, double lon, int state, String label) { lat_lon = new AltosLatLon(lat, lon); this.state = state; + this.label = label; + } + + public AltosMapMark (double lat, double lon, int state) { + this(lat, lon, state, null); + } + + public AltosMapMark () { + this(0, 0, 0); } } diff --git a/altoslib/AltosMapTransform.java b/altoslib/AltosMapTransform.java index ba9d1ae4..3f8f290c 100644 --- a/altoslib/AltosMapTransform.java +++ b/altoslib/AltosMapTransform.java @@ -29,6 +29,8 @@ public class AltosMapTransform { double offset_x, offset_y; + int width, height; + public AltosLatLon lat_lon (AltosPointDouble point) { double lat, lon; double rads; @@ -110,6 +112,39 @@ public class AltosMapTransform { return screen(point(lat, lon)); } + /* Return first longitude value which ends up on-screen */ + public double first_lon(double lon) { + /* Find a longitude left of the screen */ + for (;;) { + double x = lon * scale_x - offset_x; + if (x < 0) + break; + lon -= 360.0; + } + /* Find the first longitude on the screen */ + for (;;) { + double x = lon * scale_x - offset_x; + if (x >= 0) + break; + lon += 360.0; + } + return lon; + } + + /* Return last longitude value which ends up on-screen */ + public double last_lon(double lon) { + lon = first_lon(lon); + + for(;;) { + double next_lon = lon + 360.0; + double next_x = next_lon * scale_x - offset_x; + if (next_x >= width) + break; + lon = next_lon; + } + return lon; + } + private boolean has_location; public boolean has_location() { @@ -120,6 +155,9 @@ public class AltosMapTransform { scale_x = 256/360.0 * Math.pow(2, zoom); scale_y = 256/(2.0*Math.PI) * Math.pow(2, zoom); + this.width = width; + this.height = height; + AltosPointDouble centre_pt = point(centre_lat_lon); has_location = (centre_lat_lon.lat != 0 || centre_lat_lon.lon != 0); diff --git a/altoslib/AltosSensorEasyMotor2.java b/altoslib/AltosSensorEasyMotor2.java new file mode 100644 index 00000000..b3720a3b --- /dev/null +++ b/altoslib/AltosSensorEasyMotor2.java @@ -0,0 +1,63 @@ +/* + * Copyright © 2020 Keith Packard + * + * This program is free software; 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.altoslib_14; + +import java.util.concurrent.TimeoutException; + +class AltosSensorEasyMotor2 { + int tick; + int v_batt; + int motor_pressure; + + public AltosSensorEasyMotor2(AltosLink link) throws InterruptedException, TimeoutException { + String[] items = link.adc(); + for (int i = 0; i < items.length;) { + if (items[i].equals("tick:")) { + tick = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("motor_pressure:")) { + motor_pressure = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + if (items[i].equals("batt:")) { + v_batt = Integer.parseInt(items[i+1]); + i += 2; + continue; + } + i++; + } + } + + static public void provide_data(AltosDataListener listener, AltosLink link) throws InterruptedException { + try { + AltosSensorEasyMotor2 sensor_easymotor2 = new AltosSensorEasyMotor2(link); + + listener.set_battery_voltage(AltosConvert.easy_mini_2_voltage(sensor_easymotor2.v_batt)); + double pa = AltosConvert.easy_motor_2_motor_pressure(sensor_easymotor2.motor_pressure, + listener.cal_data().ground_motor_pressure); + listener.set_motor_pressure(pa); + + } catch (TimeoutException te) { + } + } +} + diff --git a/altoslib/Makefile.am b/altoslib/Makefile.am index 75af5252..9c8c6691 100644 --- a/altoslib/Makefile.am +++ b/altoslib/Makefile.am @@ -114,6 +114,7 @@ altoslib_JAVA = \ AltosSensorMetrum.java \ AltosSensorTGPS1.java \ AltosSensorTGPS2.java \ + AltosSensorEasyMotor2.java \ AltosState.java \ AltosStateName.java \ AltosStringInputStream.java \ diff --git a/altosui/AltosIdleMonitorUI.java b/altosui/AltosIdleMonitorUI.java index 50994bb2..ba894c71 100644 --- a/altosui/AltosIdleMonitorUI.java +++ b/altosui/AltosIdleMonitorUI.java @@ -209,7 +209,7 @@ public class AltosIdleMonitorUI extends AltosUIFrame implements AltosFlightDispl device = AltosDeviceUIDialog.show(in_owner, Altos.product_any); remote = false; - if (!device.matchProduct(Altos.product_altimeter)) + if (device.matchProduct(Altos.product_basestation)) remote = true; serial = device.getSerial(); diff --git a/altosui/AltosIgniteUI.java b/altosui/AltosIgniteUI.java index 8256722a..5a09252e 100644 --- a/altosui/AltosIgniteUI.java +++ b/altosui/AltosIgniteUI.java @@ -42,6 +42,7 @@ public class AltosIgniteUI ButtonGroup group; Boolean opened; + boolean has_standard; int npyro; final static int timeout = 1 * 1000; @@ -127,7 +128,7 @@ public class AltosIgniteUI public void run () { try { ignite = new AltosIgnite(link, - !device.matchProduct(Altos.product_altimeter)); + device.matchProduct(Altos.product_basestation)); } catch (Exception e) { send_exception(e); @@ -151,7 +152,7 @@ public class AltosIgniteUI } reply = "status"; } else if (command.equals("get_npyro")) { - reply = String.format("npyro %d", ignite.npyro()); + reply = String.format("npyro %d %d", ignite.npyro(), ignite.has_standard() ? 1 : 0); } else if (command.equals("quit")) { ignite.close(); break; @@ -212,9 +213,11 @@ public class AltosIgniteUI } else if (reply.equals("fired")) { fired(); } else if (reply.startsWith("npyro")) { - npyro = Integer.parseInt(reply.substring(6)); + String items[] = reply.split("\\s+"); + npyro = Integer.parseInt(items[1]); if (npyro == AltosLib.MISSING) npyro = 0; + has_standard = Integer.parseInt(items[2]) != 0; make_ui(); } } @@ -417,15 +420,21 @@ public class AltosIgniteUI y++; - igniters = new Igniter[2 + npyro]; + int nstandard = 0; + if (has_standard) + nstandard = 2; - igniters[0] = new Igniter(this, "Apogee", AltosIgnite.Apogee, y++); - igniters[1] = new Igniter(this, "Main", AltosIgnite.Main, y++); + igniters = new Igniter[nstandard + npyro]; + + if (has_standard) { + igniters[0] = new Igniter(this, "Apogee", AltosIgnite.Apogee, y++); + igniters[1] = new Igniter(this, "Main", AltosIgnite.Main, y++); + } for (int p = 0; p < npyro; p++) { String name = String.format("%d", p); String label = String.format("%c", 'A' + p); - igniters[2+p] = new Igniter(this, label, name, y++); + igniters[nstandard+p] = new Igniter(this, label, name, y++); } c.gridx = 0; diff --git a/altosui/AltosUI.app/Contents/MacOS/JavaApplicationStub b/altosui/AltosUI.app/Contents/MacOS/JavaApplicationStub index 145a260b..aa96638f 100755 --- a/altosui/AltosUI.app/Contents/MacOS/JavaApplicationStub +++ b/altosui/AltosUI.app/Contents/MacOS/JavaApplicationStub @@ -1,16 +1,4 @@ #!/bin/bash -# -# Fix fonts. I don't know why the getting the -# basename of the app set to . matters, but it does -# -case "$0" in - /*) - cd `dirname "$0"` - ./`basename "$0"` "$@" - exit $? - ;; -esac -export FREETYPE_PROPERTIES=truetype:interpreter-version=35 ################################################################################## # # # universalJavaApplicationStub # @@ -23,14 +11,14 @@ export FREETYPE_PROPERTIES=truetype:interpreter-version=35 # # # @author Tobias Fischer # # @url https://github.com/tofi86/universalJavaApplicationStub # -# @date 2018-08-24 # -# @version 3.0.4 # +# @date 2021-02-21 # +# @version 3.2.0 # # # ################################################################################## # # # The MIT License (MIT) # # # -# Copyright (c) 2014-2018 Tobias Fischer # +# Copyright (c) 2014-2021 Tobias Fischer # # # # Permission is hereby granted, free of charge, to any person obtaining a copy # # of this software and associated documentation files (the "Software"), to deal # @@ -52,7 +40,18 @@ export FREETYPE_PROPERTIES=truetype:interpreter-version=35 # # ################################################################################## - +# +# Fix fonts. I don't know why the getting the +# basename of the app set to . matters, but it does +# +case "$0" in + /*) + cd `dirname "$0"` + ./`basename "$0"` "$@" + exit $? + ;; +esac +export FREETYPE_PROPERTIES=truetype:interpreter-version=35 # function 'stub_logger()' # @@ -178,6 +177,8 @@ if [ $exitcode -eq 0 ]; then JavaFolder="${AppleJavaFolder}" ResourcesFolder="${AppleResourcesFolder}" + # set expandable variables + APP_ROOT="${AppPackageFolder}" APP_PACKAGE="${AppPackageFolder}" JAVAROOT="${AppleJavaFolder}" USER_HOME="$HOME" @@ -192,7 +193,7 @@ if [ $exitcode -eq 0 ]; then # AppPackageRoot is the standard WorkingDirectory when the script is started WorkingDirectory="${AppPackageRoot}" fi - # expand variables $APP_PACKAGE, $JAVAROOT, $USER_HOME + # expand variables $APP_PACKAGE, $APP_ROOT, $JAVAROOT, $USER_HOME WorkingDirectory=$(eval echo "${WorkingDirectory}") @@ -215,7 +216,7 @@ if [ $exitcode -eq 0 ]; then else JVMClassPath=${JVMClassPath_RAW} fi - # expand variables $APP_PACKAGE, $JAVAROOT, $USER_HOME + # expand variables $APP_PACKAGE, $APP_ROOT, $JAVAROOT, $USER_HOME JVMClassPath=$(eval echo "${JVMClassPath}") # read the JVM Options in either Array or String style @@ -225,6 +226,8 @@ if [ $exitcode -eq 0 ]; then else JVMDefaultOptions=${JVMDefaultOptions_RAW} fi + # expand variables $APP_PACKAGE, $APP_ROOT, $JAVAROOT, $USER_HOME (#84) + JVMDefaultOptions=$(eval echo "${JVMDefaultOptions}") # read StartOnMainThread and add as -XstartOnFirstThread JVMStartOnMainThread=$(plist_get_java ':StartOnMainThread') @@ -232,9 +235,14 @@ if [ $exitcode -eq 0 ]; then JVMDefaultOptions+=" -XstartOnFirstThread" fi - # read the JVM Arguments as an array and retain spaces + # read the JVM Arguments in either Array or String style (#76) and retain spaces IFS=$'\t\n' - MainArgs=($(xargs -n1 <<<$(plist_get_java ':Arguments'))) + MainArgs_RAW=$(plist_get_java ':Arguments' | xargs) + if [[ $MainArgs_RAW == *Array* ]] ; then + MainArgs=($(xargs -n1 <<<$(plist_get_java ':Arguments' | tr -d '\n' | sed -E 's/Array \{ *(.*) *\}/\1/g' | sed 's/ */ /g'))) + else + MainArgs=($(xargs -n1 <<<$(plist_get_java ':Arguments'))) + fi unset IFS # post processing of the array follows further below... @@ -252,7 +260,11 @@ else ResourcesFolder="${OracleResourcesFolder}" WorkingDirectory="${OracleJavaFolder}" + # set expandable variables APP_ROOT="${AppPackageFolder}" + APP_PACKAGE="${AppPackageFolder}" + JAVAROOT="${OracleJavaFolder}" + USER_HOME="$HOME" # read the MainClass name JVMMainClass="$(plist_get ':JVMMainClassName')" @@ -270,12 +282,12 @@ else JVMClassPath_RAW=$(plist_get ':JVMClassPath') if [[ $JVMClassPath_RAW == *Array* ]] ; then JVMClassPath=.$(plist_get ':JVMClassPath' | grep " " | sed 's/^ */:/g' | tr -d '\n' | xargs) - # expand variables $APP_PACKAGE, $JAVAROOT, $USER_HOME + # expand variables $APP_PACKAGE, $APP_ROOT, $JAVAROOT, $USER_HOME JVMClassPath=$(eval echo "${JVMClassPath}") elif [[ ! -z ${JVMClassPath_RAW} ]] ; then JVMClassPath=${JVMClassPath_RAW} - # expand variables $APP_PACKAGE, $JAVAROOT, $USER_HOME + # expand variables $APP_PACKAGE, $APP_ROOT, $JAVAROOT, $USER_HOME JVMClassPath=$(eval echo "${JVMClassPath}") else @@ -284,8 +296,11 @@ else # Do NOT expand the default 'AppName.app/Contents/Java/*' classpath (#42) fi - # read the JVM Default Options + # read the JVM Default Options by parsing the :JVMDefaultOptions + # and pulling all values starting with a dash (-) JVMDefaultOptions=$(plist_get ':JVMDefaultOptions' | grep -o " \-.*" | tr -d '\n' | xargs) + # expand variables $APP_PACKAGE, $APP_ROOT, $JAVAROOT, $USER_HOME (#99) + JVMDefaultOptions=$(eval echo "${JVMDefaultOptions}") # read the Main Arguments from JVMArguments key as an array and retain spaces (see #46 for naming details) IFS=$'\t\n' @@ -299,6 +314,18 @@ else fi +# (#75) check for undefined icons or icon names without .icns extension and prepare +# an osascript statement for those cases when the icon can be shown in the dialog +DialogWithIcon="" +if [ ! -z ${CFBundleIconFile} ]; then + if [[ ${CFBundleIconFile} == *.icns ]] && [[ -f "${ResourcesFolder}/${CFBundleIconFile}" ]] ; then + DialogWithIcon=" with icon path to resource \"${CFBundleIconFile}\" in bundle (path to me)" + elif [[ ${CFBundleIconFile} != *.icns ]] && [[ -f "${ResourcesFolder}/${CFBundleIconFile}.icns" ]] ; then + CFBundleIconFile+=".icns" + DialogWithIcon=" with icon path to resource \"${CFBundleIconFile}\" in bundle (path to me)" + fi +fi + # JVMVersion: post processing and optional splitting if [[ ${JVMVersion} == *";"* ]]; then @@ -309,14 +336,14 @@ fi stub_logger "[JavaRequirement] JVM minimum version: ${JVMVersion}" stub_logger "[JavaRequirement] JVM maximum version: ${JVMMaxVersion}" -# MainArgs: replace occurences of $APP_ROOT with its content +# MainArgs: expand variables $APP_PACKAGE, $APP_ROOT, $JAVAROOT, $USER_HOME MainArgsArr=() for i in "${MainArgs[@]}" do MainArgsArr+=("$(eval echo "$i")") done -# JVMOptions: replace occurences of $APP_ROOT with its content +# JVMOptions: expand variables $APP_PACKAGE, $APP_ROOT, $JAVAROOT, $USER_HOME JVMOptionsArr=() for i in "${JVMOptions[@]}" do @@ -327,14 +354,37 @@ done # internationalized messages ############################################ -LANG=$(defaults read -g AppleLocale) -stub_logger "[Language] $LANG" +# supported languages / available translations +stubLanguages="^(fr|de|zh|es|en)-" + +# read user preferred languages as defined in macOS System Preferences (#101) +stub_logger '[LanguageSearch] Checking preferred languages in macOS System Preferences...' +appleLanguages=($(defaults read -g AppleLanguages | grep '\s"' | tr -d ',' | xargs)) +stub_logger "[LanguageSearch] ... found [${appleLanguages[*]}]" + +language="" +for i in "${appleLanguages[@]}" +do + langValue="${i%-*}" + if [[ "$i" =~ $stubLanguages ]]; then + stub_logger "[LanguageSearch] ... selected '$i' ('$langValue') as the default language for the launcher stub" + language=${langValue} + break + fi +done +if [ -z "${language}" ]; then + language="en" + stub_logger "[LanguageSearch] ... selected fallback 'en' as the default language for the launcher stub" +fi +stub_logger "[Language] $language" -# French localization -if [[ $LANG == fr* ]] ; then + +case "${language}" in +# French +fr) MSG_ERROR_LAUNCHING="ERREUR au lancement de '${CFBundleName}'." MSG_MISSING_MAINCLASS="'MainClass' n'est pas spécifié.\nL'application Java ne peut pas être lancée." - MSG_JVMVERSION_REQ_INVALID="La syntaxe de la version Java demandée est invalide: %s\nVeuillez contacter le développeur de l'application." + MSG_JVMVERSION_REQ_INVALID="La syntaxe de la version de Java demandée est invalide: %s\nVeuillez contacter le développeur de l'application." MSG_NO_SUITABLE_JAVA="La version de Java installée sur votre système ne convient pas.\nCe programme nécessite Java %s" MSG_JAVA_VERSION_OR_LATER="ou ultérieur" MSG_JAVA_VERSION_LATEST="(dernière mise à jour)" @@ -342,10 +392,12 @@ if [[ $LANG == fr* ]] ; then MSG_NO_SUITABLE_JAVA_CHECK="Merci de bien vouloir installer la version de Java requise." MSG_INSTALL_JAVA="Java doit être installé sur votre système.\nRendez-vous sur java.com et suivez les instructions d'installation..." MSG_LATER="Plus tard" - MSG_VISIT_JAVA_DOT_COM="Visiter java.com" + MSG_VISIT_JAVA_DOT_COM="Java by Oracle" + MSG_VISIT_ADOPTOPENJDK="Java by AdoptOpenJDK" + ;; -# German localization -elif [[ $LANG == de* ]] ; then +# German +de) MSG_ERROR_LAUNCHING="FEHLER beim Starten von '${CFBundleName}'." MSG_MISSING_MAINCLASS="Die 'MainClass' ist nicht spezifiziert!\nDie Java-Anwendung kann nicht gestartet werden!" MSG_JVMVERSION_REQ_INVALID="Die Syntax der angeforderten Java-Version ist ungültig: %s\nBitte kontaktieren Sie den Entwickler der App." @@ -356,10 +408,12 @@ elif [[ $LANG == de* ]] ; then MSG_NO_SUITABLE_JAVA_CHECK="Stellen Sie sicher, dass die angeforderte Java-Version installiert ist." MSG_INSTALL_JAVA="Auf Ihrem System muss die 'Java'-Software installiert sein.\nBesuchen Sie java.com für weitere Installationshinweise." MSG_LATER="Später" - MSG_VISIT_JAVA_DOT_COM="java.com öffnen" + MSG_VISIT_JAVA_DOT_COM="Java von Oracle" + MSG_VISIT_ADOPTOPENJDK="Java von AdoptOpenJDK" + ;; -# Simplifyed Chinese localization -elif [[ $LANG == zh* ]] ; then +# Simplified Chinese +zh) MSG_ERROR_LAUNCHING="无法启动 '${CFBundleName}'." MSG_MISSING_MAINCLASS="没有指定 'MainClass'!\nJava程序无法启动!" MSG_JVMVERSION_REQ_INVALID="Java版本参数语法错误: %s\n请联系该应用的开发者。" @@ -370,10 +424,28 @@ elif [[ $LANG == zh* ]] ; then MSG_NO_SUITABLE_JAVA_CHECK="请确保系统中安装了所需的Java版本" MSG_INSTALL_JAVA="你需要在Mac中安装Java运行环境!\n访问 java.com 了解如何安装。" MSG_LATER="稍后" - MSG_VISIT_JAVA_DOT_COM="访问 java.com" - -# English default localization -else + MSG_VISIT_JAVA_DOT_COM="Java by Oracle" + MSG_VISIT_ADOPTOPENJDK="Java by AdoptOpenJDK" + ;; + +# Spanish +es) + MSG_ERROR_LAUNCHING="ERROR iniciando '${CFBundleName}'." + MSG_MISSING_MAINCLASS="¡'MainClass' no especificada!\n¡La aplicación Java no puede iniciarse!" + MSG_JVMVERSION_REQ_INVALID="La sintaxis de la versión Java requerida no es válida: %s\nPor favor, contacte con el desarrollador de la aplicación." + MSG_NO_SUITABLE_JAVA="¡No se encontró una versión de Java adecuada en su sistema!\nEste programa requiere Java %s" + MSG_JAVA_VERSION_OR_LATER="o posterior" + MSG_JAVA_VERSION_LATEST="(ultima actualización)" + MSG_JAVA_VERSION_MAX="superior a %s" + MSG_NO_SUITABLE_JAVA_CHECK="Asegúrese de instalar la versión Java requerida." + MSG_INSTALL_JAVA="¡Necesita tener JAVA instalado en su Mac!\nVisite java.com para consultar las instrucciones para su instalación..." + MSG_LATER="Más tarde" + MSG_VISIT_JAVA_DOT_COM="Java de Oracle" + MSG_VISIT_ADOPTOPENJDK="Java de AdoptOpenJDK" + ;; + +# English | default +en|*) MSG_ERROR_LAUNCHING="ERROR launching '${CFBundleName}'." MSG_MISSING_MAINCLASS="'MainClass' isn't specified!\nJava application cannot be started!" MSG_JVMVERSION_REQ_INVALID="The syntax of the required Java version is invalid: %s\nPlease contact the App developer." @@ -384,8 +456,10 @@ else MSG_NO_SUITABLE_JAVA_CHECK="Make sure you install the required Java version." MSG_INSTALL_JAVA="You need to have JAVA installed on your Mac!\nVisit java.com for installation instructions..." MSG_LATER="Later" - MSG_VISIT_JAVA_DOT_COM="Visit java.com" -fi + MSG_VISIT_JAVA_DOT_COM="Java by Oracle" + MSG_VISIT_ADOPTOPENJDK="Java by AdoptOpenJDK" + ;; +esac @@ -468,7 +542,7 @@ function get_comparable_java_version() { ################################################################################ function is_valid_requirement_pattern() { local java_req=$1 - java8pattern='1\.[4-8](\.0)?(\.0_[0-9]+)?[*+]?' + java8pattern='1\.[4-8](\.[0-9]+)?(\.0_[0-9]+)?[*+]?' java9pattern='(9|1[0-9])(-ea|[*+]|(\.[0-9]+){1,2}[*+]?)?' # test matches either old Java versioning scheme (up to 1.8) or new scheme (starting with 9) if [[ ${java_req} =~ ^(${java8pattern}|${java9pattern})$ ]]; then @@ -501,20 +575,28 @@ if [ -n "$JAVA_HOME" ] ; then if [[ $JAVA_HOME == /* ]] ; then # if "$JAVA_HOME" starts with a Slash it's an absolute path JAVACMD="$JAVA_HOME/bin/java" + stub_logger "[JavaSearch] ... parsing JAVA_HOME as absolute path to the executable '$JAVACMD'" else # otherwise it's a relative path to "$AppPackageFolder" JAVACMD="$AppPackageFolder/$JAVA_HOME/bin/java" + stub_logger "[JavaSearch] ... parsing JAVA_HOME as relative path inside the App bundle to the executable '$JAVACMD'" fi JAVACMD_version=$(get_comparable_java_version $(get_java_version_from_cmd "${JAVACMD}")) else - stub_logger "[JavaSearch] ... didn't found JAVA_HOME" + stub_logger "[JavaSearch] ... haven't found JAVA_HOME" fi # check for any other or a specific Java version # also if $JAVA_HOME exists but isn't executable if [ -z "${JAVACMD}" ] || [ ! -x "${JAVACMD}" ] ; then - stub_logger "[JavaSearch] Checking for JavaVirtualMachines on the system ..." + + # add a warning in the syslog if JAVA_HOME is not executable or not found (#100) + if [ -n "$JAVA_HOME" ] ; then + stub_logger "[JavaSearch] ... but no 'java' executable was found at the JAVA_HOME location!" + fi + + stub_logger "[JavaSearch] Searching for JavaVirtualMachines on the system ..." # reset variables JAVACMD="" JAVACMD_version="" @@ -525,7 +607,7 @@ if [ -z "${JAVACMD}" ] || [ ! -x "${JAVACMD}" ] ; then # log exit cause stub_logger "[EXIT 4] ${MSG_JVMVERSION_REQ_INVALID_EXPANDED}" # display error message with AppleScript - osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_JVMVERSION_REQ_INVALID_EXPANDED}\" with title \"${CFBundleName}\" buttons {\" OK \"} default button 1 with icon path to resource \"${CFBundleIconFile}\" in bundle (path to me)" + osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_JVMVERSION_REQ_INVALID_EXPANDED}\" with title \"${CFBundleName}\" buttons {\" OK \"} default button 1${DialogWithIcon}" # exit with error exit 4 fi @@ -535,7 +617,7 @@ if [ -z "${JAVACMD}" ] || [ ! -x "${JAVACMD}" ] ; then # log exit cause stub_logger "[EXIT 5] ${MSG_JVMVERSION_REQ_INVALID_EXPANDED}" # display error message with AppleScript - osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_JVMVERSION_REQ_INVALID_EXPANDED}\" with title \"${CFBundleName}\" buttons {\" OK \"} default button 1 with icon path to resource \"${CFBundleIconFile}\" in bundle (path to me)" + osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_JVMVERSION_REQ_INVALID_EXPANDED}\" with title \"${CFBundleName}\" buttons {\" OK \"} default button 1${DialogWithIcon}" # exit with error exit 5 fi @@ -543,15 +625,41 @@ if [ -z "${JAVACMD}" ] || [ ! -x "${JAVACMD}" ] ; then # find installed JavaVirtualMachines (JDK + JRE) allJVMs=() - # read JDK's from '/usr/libexec/java_home -V' command - while read -r line; do - version=$(echo $line | awk -F $',' '{print $1;}') - path=$(echo $line | awk -F $'" ' '{print $2;}') - path+="/bin/java" - allJVMs+=("$version:$path") - done < <(/usr/libexec/java_home -V 2>&1 | grep '^[[:space:]]') - # unset while loop variables - unset version path + + # read JDK's from '/usr/libexec/java_home --xml' command with PlistBuddy and a custom Dict iterator + # idea: https://stackoverflow.com/a/14085460/1128689 and https://scriptingosx.com/2018/07/parsing-dscl-output-in-scripts/ + javaXml=$(/usr/libexec/java_home --xml) + javaCounter=$(/usr/libexec/PlistBuddy -c "Print" /dev/stdin <<< $javaXml | grep "Dict" | wc -l | tr -d ' ') + + # iterate over all Dict entries + # but only if there are any JVMs at all (#93) + if [ "$javaCounter" -gt "0" ] ; then + for idx in $(seq 0 $((javaCounter - 1))) + do + version=$(/usr/libexec/PlistBuddy -c "print :$idx:JVMVersion" /dev/stdin <<< $javaXml) + path=$(/usr/libexec/PlistBuddy -c "print :$idx:JVMHomePath" /dev/stdin <<< $javaXml) + path+="/bin/java" + allJVMs+=("$version:$path") + done + # unset for loop variables + unset version path + fi + + # add SDKMAN! java versions (#95) + if [ -d ~/.sdkman/candidates/java/ ] ; then + for sdkjdk in ~/.sdkman/candidates/java/*/ + do + if [[ ${sdkjdk} =~ /current/$ ]] ; then + continue + fi + + sdkjdkcmd="${sdkjdk}bin/java" + version=$(get_java_version_from_cmd "${sdkjdkcmd}") + allJVMs+=("$version:$sdkjdkcmd") + done + # unset for loop variables + unset version + fi # add Apple JRE if available if [ -x "${apple_jre_plugin}" ] ; then @@ -571,6 +679,9 @@ if [ -z "${JAVACMD}" ] || [ ! -x "${JAVACMD}" ] ; then # determine JVMs matching the min/max version requirement + + stub_logger "[JavaSearch] Filtering the result list for JVMs matching the min/max version requirement ..." + minC=$(get_comparable_java_version ${JVMVersion}) maxC=$(get_comparable_java_version ${JVMMaxVersion}) matchingJVMs=() @@ -655,7 +766,7 @@ if [ -z "${JAVACMD}" ] || [ ! -x "${JAVACMD}" ] ; then # debug output for i in "${matchingJVMs[@]}" do - stub_logger "[JavaSearch] ... ... matches all requirements: $i" + stub_logger "[JavaSearch] ... matches all requirements: $i" done @@ -692,7 +803,13 @@ fi stub_logger "[JavaCommand] '$JAVACMD'" stub_logger "[JavaVersion] $(get_java_version_from_cmd "${JAVACMD}")${JAVACMD_version:+ / $JAVACMD_version}" +# Make sure tabbing mode is disabled for the selected java version + +CFBundleIdentifier=net.java.openjdk.$(get_java_version_from_cmd "${JAVACMD}").java +if [ x$(defaults read ${CFBundleIdentifier} AppleWindowTabbingMode) != "xnever" ]; then + defaults write ${CFBundleIdentifier} AppleWindowTabbingMode never +fi if [ -z "${JAVACMD}" ] || [ ! -x "${JAVACMD}" ] ; then @@ -712,9 +829,10 @@ if [ -z "${JAVACMD}" ] || [ ! -x "${JAVACMD}" ] ; then stub_logger "[EXIT 3] ${MSG_NO_SUITABLE_JAVA_EXPANDED}" # display error message with AppleScript - osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_NO_SUITABLE_JAVA_EXPANDED}\n${MSG_NO_SUITABLE_JAVA_CHECK}\" with title \"${CFBundleName}\" buttons {\" OK \", \"${MSG_VISIT_JAVA_DOT_COM}\"} default button \"${MSG_VISIT_JAVA_DOT_COM}\" with icon path to resource \"${CFBundleIconFile}\" in bundle (path to me)" \ + osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_NO_SUITABLE_JAVA_EXPANDED}\n${MSG_NO_SUITABLE_JAVA_CHECK}\" with title \"${CFBundleName}\" buttons {\" OK \", \"${MSG_VISIT_JAVA_DOT_COM}\", \"${MSG_VISIT_ADOPTOPENJDK}\"} default button 1${DialogWithIcon}" \ -e "set response to button returned of the result" \ - -e "if response is \"${MSG_VISIT_JAVA_DOT_COM}\" then open location \"http://java.com\"" + -e "if response is \"${MSG_VISIT_JAVA_DOT_COM}\" then open location \"https://www.java.com/download/\"" \ + -e "if response is \"${MSG_VISIT_ADOPTOPENJDK}\" then open location \"https://adoptopenjdk.net/releases.html\"" # exit with error exit 3 @@ -722,9 +840,10 @@ if [ -z "${JAVACMD}" ] || [ ! -x "${JAVACMD}" ] ; then # log exit cause stub_logger "[EXIT 1] ${MSG_ERROR_LAUNCHING}" # display error message with AppleScript - osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_INSTALL_JAVA}\" with title \"${CFBundleName}\" buttons {\"${MSG_LATER}\", \"${MSG_VISIT_JAVA_DOT_COM}\"} default button \"${MSG_VISIT_JAVA_DOT_COM}\" with icon path to resource \"${CFBundleIconFile}\" in bundle (path to me)" \ + osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_INSTALL_JAVA}\" with title \"${CFBundleName}\" buttons {\"${MSG_LATER}\", \"${MSG_VISIT_JAVA_DOT_COM}\", \"${MSG_VISIT_ADOPTOPENJDK}\"} default button 1${DialogWithIcon}" \ -e "set response to button returned of the result" \ - -e "if response is \"${MSG_VISIT_JAVA_DOT_COM}\" then open location \"http://java.com\"" + -e "if response is \"${MSG_VISIT_JAVA_DOT_COM}\" then open location \"https://www.java.com/download/\"" \ + -e "if response is \"${MSG_VISIT_ADOPTOPENJDK}\" then open location \"https://adoptopenjdk.net/releases.html\"" # exit with error exit 1 fi @@ -739,7 +858,7 @@ if [ -z "${JVMMainClass}" ]; then # log exit cause stub_logger "[EXIT 2] ${MSG_MISSING_MAINCLASS}" # display error message with AppleScript - osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_MISSING_MAINCLASS}\" with title \"${CFBundleName}\" buttons {\" OK \"} default button 1 with icon path to resource \"${CFBundleIconFile}\" in bundle (path to me)" + osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_MISSING_MAINCLASS}\" with title \"${CFBundleName}\" buttons {\" OK \"} default button 1${DialogWithIcon}" # exit with error exit 2 fi @@ -773,11 +892,11 @@ stub_logger "[WorkingDirectory] ${WorkingDirectory}" # - main class # - main class arguments # - passthrough arguments from Terminal or Drag'n'Drop to Finder icon -stub_logger "[Exec] \"$JAVACMD\" -cp \"${JVMClassPath}\" -splash:\"${ResourcesFolder}/${JVMSplashFile}\" -Xdock:icon=\"${ResourcesFolder}/${CFBundleIconFile}\" -Xdock:name=\"${CFBundleName}\" ${JVMOptionsArr:+$(printf "'%s' " "${JVMOptionsArr[@]}") }${JVMDefaultOptions:+$JVMDefaultOptions }${JVMMainClass}${MainArgsArr:+ $(printf "'%s' " "${MainArgsArr[@]}")}${ArgsPassthru:+ $(printf "'%s' " "${ArgsPassthru[@]}")}" +stub_logger "[Exec] \"$JAVACMD\" -cp \"${JVMClassPath}\" ${JVMSplashFile:+ -splash:\"${ResourcesFolder}/${JVMSplashFile}\"} -Xdock:icon=\"${ResourcesFolder}/${CFBundleIconFile}\" -Xdock:name=\"${CFBundleName}\" ${JVMOptionsArr:+$(printf "'%s' " "${JVMOptionsArr[@]}") }${JVMDefaultOptions:+$JVMDefaultOptions }${JVMMainClass}${MainArgsArr:+ $(printf "'%s' " "${MainArgsArr[@]}")}${ArgsPassthru:+ $(printf "'%s' " "${ArgsPassthru[@]}")}" exec "${JAVACMD}" \ -Djava.library.path="${AppleJavaFolder}" \ -cp "${JVMClassPath}" \ - -splash:"${ResourcesFolder}/${JVMSplashFile}" \ + ${JVMSplashFile:+ -splash:"${ResourcesFolder}/${JVMSplashFile}"} \ -Xdock:icon="${ResourcesFolder}/${CFBundleIconFile}" \ -Xdock:name="${CFBundleName}" \ ${JVMOptionsArr:+"${JVMOptionsArr[@]}" }\ diff --git a/altosui/Makefile.am b/altosui/Makefile.am index 78d3ec15..1cbb919f 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -146,6 +146,9 @@ 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 FIRMWARE_EMEGA=$(FIRMWARE_EMEGA_1_0) $(FIRMWARE_EMEGA_2_0) +FIRMWARE_EMOTOR_2=$(top_srcdir)/src/easymotor-v2/easymotor-v2-$(VERSION).ihx +FIRMWARE_EMOTOR=$(FIRMWARE_EMOTOR_2) + FIRMWARE_ETIMER_1=$(top_srcdir)/src/easytimer-v1/easytimer-v1-$(VERSION).ihx FIRMWARE_ETIMER=$(FIRMWARE_ETIMER_1) @@ -160,7 +163,7 @@ FIRMWARE_TFIRE8_1_0=$(top_srcdir)/src/telefireeight-v1.0/telefireeight-v1.0-$(VE FIRMWARE_TFIRE8_2_0=$(top_srcdir)/src/telefireeight-v2.0/telefireeight-v2.0-$(VERSION).ihx FIRMWARE_TFIRE8=$(FIRMWARE_TFIRE8_1_0) $(FIRMWARE_TFIRE8_2_0) -FIRMWARE=$(FIRMWARE_TM) $(FIRMWARE_TELEMINI) $(FIRMWARE_TD) $(FIRMWARE_TBT) $(FIRMWARE_TMEGA) $(FIRMWARE_EMINI) $(FIRMWARE_TGPS) $(FIRMWARE_EMEGA) $(FIRMWARE_ETIMER) $(FIRMWARE_TLCO) $(FIRMWARE_TFIRE8) +FIRMWARE=$(FIRMWARE_TM) $(FIRMWARE_TELEMINI) $(FIRMWARE_TD) $(FIRMWARE_TBT) $(FIRMWARE_TMEGA) $(FIRMWARE_EMINI) $(FIRMWARE_TGPS) $(FIRMWARE_EMEGA) $(FIRMWARE_EMOTOR) $(FIRMWARE_ETIMER) $(FIRMWARE_TLCO) $(FIRMWARE_TFIRE8) ALTUSMETRUM_DOC=$(top_srcdir)/doc/altusmetrum.pdf ALTOS_DOC=$(top_srcdir)/doc/altos.pdf diff --git a/altosui/altos-windows.nsi.in b/altosui/altos-windows.nsi.in index ad155a2c..196dd741 100644 --- a/altosui/altos-windows.nsi.in +++ b/altosui/altos-windows.nsi.in @@ -136,6 +136,7 @@ Section "Firmware" File "../src/easymini-v2.0/easymini-v2.0-${VERSION}.ihx" File "../src/easymega-v1.0/easymega-v1.0-${VERSION}.ihx" File "../src/easymega-v2.0/easymega-v2.0-${VERSION}.ihx" + File "../src/easymotor-v2/easymotor-v2-${VERSION}.ihx" File "../src/easytimer-v1/easytimer-v1-${VERSION}.ihx" File "../src/telelco-v2.0/telelco-v2.0-${VERSION}.ihx" File "../src/telefireeight-v1.0/telefireeight-v1.0-${VERSION}.ihx" diff --git a/altosui/install-macosx b/altosui/install-macosx index 8f0067e5..e97a002a 100755 --- a/altosui/install-macosx +++ b/altosui/install-macosx @@ -8,6 +8,13 @@ case `id -u` in ;; *) SUDO_ASKPASS="${dir}/ask-pass" sudo -A "$0" "$@" + case $? in + 0) + ;; + *) + osascript -e 'display dialog "Installation failed. Incorrect password?" buttons {"OK"} default button 1 with title "Installation Status"' > /dev/null + ;; + esac exit 0 ;; esac @@ -44,4 +51,5 @@ for file in *; do ;; esac done +open "${LIBRARY}" osascript -e 'display dialog "Installation of'"${INSTALLED}"' complete" with title "Installation Complete" buttons {"OK"} default button 1' >/dev/null diff --git a/altosuilib/AltosFlashUI.java b/altosuilib/AltosFlashUI.java index 6b78aea7..3665aaf1 100644 --- a/altosuilib/AltosFlashUI.java +++ b/altosuilib/AltosFlashUI.java @@ -80,6 +80,10 @@ public class AltosFlashUI "TeleShield" }; + private static final String[] log_erased_devices = { + "TeleGPS" + }; + private boolean is_pair_programmed() { if (file != null) { @@ -99,6 +103,17 @@ public class AltosFlashUI return false; } + private boolean is_log_erased() { + if (device != null) { + String name = device.toString(); + for (int i = 0; i < log_erased_devices.length; i++) { + if (name.startsWith(log_erased_devices[i])) + return true; + } + } + return false; + } + public void actionPerformed(ActionEvent e) { if (e.getSource() == cancel) { if (programmer != null) @@ -443,13 +458,20 @@ public class AltosFlashUI flash_task flasher; + boolean erase_answer; class open_task implements Runnable { AltosDevice device; Thread t; open_dialog dialog; + AltosLink link; public void do_exception(final Exception e) { + if (link != null) { + try { + link.close(); + } catch (Exception ex) {} + } SwingUtilities.invokeLater( new Runnable() { public void run() { @@ -467,27 +489,33 @@ public class AltosFlashUI }); } - public void do_failure() { - SwingUtilities.invokeLater( - new Runnable() { - public void run() { - try { dialog.open_failure(); } catch (Exception ex) { } - } - }); - } - - public void do_cancel() { + public boolean do_notify_erase(final AltosConfigData config_data) { + erase_answer = false; + final Semaphore erase_answer_done = new Semaphore(0); SwingUtilities.invokeLater( new Runnable() { public void run() { - try { dialog.open_cancel(); } catch (Exception ex) { } + int ret = JOptionPane.showConfirmDialog(dialog.owner, + String.format("Updating %s from firmware %s will erase stored data, continue?", + config_data.product, + config_data.version), + "Erase Stored Data?", + JOptionPane.YES_NO_OPTION); + erase_answer = ret == JOptionPane.YES_OPTION; + erase_answer_done.release(); } }); + try { + erase_answer_done.acquire(); + } catch (Exception ex) { + return false; + } + return erase_answer; } public void run () { + link = null; try { - AltosLink link = null; boolean new_device = false; for (;;) { @@ -510,6 +538,8 @@ public class AltosFlashUI throw new IOException(String.format("%s: open failed", device.toShortString())); + System.out.printf("Checking device ready\n"); + /* See if the link is usable already */ if (is_pair_programmed() || link.is_loader()) { System.out.printf("Device ready for use\n"); @@ -517,6 +547,24 @@ public class AltosFlashUI return; } + System.out.printf("Checking log erased\n"); + + if (is_log_erased()) { + System.out.printf("Fetching config data\n"); + AltosConfigData config_data = link.config_data(); + System.out.printf("version %s\n", config_data.version); + /* Completely erase TeleGPS flash when firmware is old */ + if (config_data.compare_version("1.9.7") < 0) + { + if (!do_notify_erase(config_data)) + throw new IOException(String.format("%s: not erasing log", + device.toShortString())); + System.out.printf("Erasing log\n"); + link.printf("Z DoIt\n"); + link.synchronize(120 * 1000); + } + } + java.util.List prev_devices = AltosUSBDevice.list(AltosLib.product_altusmetrum); @@ -569,7 +617,10 @@ public class AltosFlashUI do_exception(fe); } catch (IOException ie) { do_exception (ie); + } catch (TimeoutException te) { + do_exception (te); } catch (InterruptedException ie) { + do_exception (ie); } } @@ -614,18 +665,6 @@ public class AltosFlashUI done = true; } - public void open_failure() { - System.out.printf("open_failure\n"); - setVisible(false); - done = true; - } - - public void open_cancel() { - System.out.printf("open_cancel\n"); - setVisible(false); - done = true; - } - public AltosLink do_open(open_task open) throws InterruptedException { this.open = open; setVisible(true); diff --git a/altosuilib/AltosInfoTable.java b/altosuilib/AltosInfoTable.java index 226f112f..89d45303 100644 --- a/altosuilib/AltosInfoTable.java +++ b/altosuilib/AltosInfoTable.java @@ -275,16 +275,18 @@ public class AltosInfoTable extends JTable implements AltosFlightDisplay, Hierar info_add_row(3, "Accel along", "%8.1f m/s²", state.accel_along()); info_add_row(3, "Accel across", "%8.1f m/s²", state.accel_across()); info_add_row(3, "Accel through", "%8.1f m/s²", state.accel_through()); + } + if (state != null && state.gyro_roll() != AltosLib.MISSING) { info_add_row(3, "Gyro roll", "%8.1f °/s", state.gyro_roll()); info_add_row(3, "Gyro pitch", "%8.1f °/s", state.gyro_pitch()); info_add_row(3, "Gyro yaw", "%8.1f °/s", state.gyro_yaw()); - if (state.mag_along() != AltosLib.MISSING) { - /* Report mag in nanoteslas (1 G = 100000 nT (or γ)) */ - info_add_row(3, "Mag along", "%8.1f µT", state.mag_along() * 100.0); - info_add_row(3, "Mag across", "%8.1f µT", state.mag_across() * 100.0); - info_add_row(3, "Mag Through", "%8.1f µT", state.mag_through() * 100.0); - info_add_row(3, "Mag Bearing", "%8.1f°", Math.atan2(state.mag_across(), state.mag_through()) * 180/Math.PI); - } + } + if (state != null && state.mag_along() != AltosLib.MISSING) { + /* Report mag in nanoteslas (1 G = 100000 nT (or γ)) */ + info_add_row(3, "Mag along", "%8.1f µT", state.mag_along() * 100.0); + info_add_row(3, "Mag across", "%8.1f µT", state.mag_across() * 100.0); + info_add_row(3, "Mag Through", "%8.1f µT", state.mag_through() * 100.0); + info_add_row(3, "Mag Bearing", "%8.1f°", Math.atan2(state.mag_across(), state.mag_through()) * 180/Math.PI); } if (state != null && state.igniter_voltage != null) { diff --git a/altosuilib/AltosUIMap.java b/altosuilib/AltosUIMap.java index 5f1b7ae6..0a80959f 100644 --- a/altosuilib/AltosUIMap.java +++ b/altosuilib/AltosUIMap.java @@ -48,20 +48,48 @@ public class AltosUIMap extends JComponent implements AltosFlightDisplay, AltosM class MapMark extends AltosMapMark { public void paint(AltosMapTransform t) { - AltosPointDouble pt = t.screen(lat_lon); - - g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, - RenderingHints.VALUE_ANTIALIAS_ON); - g.setStroke(new BasicStroke(stroke_width, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); - - if (0 <= state && state < AltosUIMap.stateColors.length) - g.setColor(AltosUIMap.stateColors[state]); - else - g.setColor(AltosUIMap.stateColors[AltosLib.ao_flight_invalid]); + double lat = lat_lon.lat; + double lon; + double first_lon = t.first_lon(lat_lon.lon); + double last_lon = t.last_lon(lat_lon.lon); + for (lon = first_lon; lon <= last_lon; lon += 360.0) { + AltosPointDouble pt = t.screen(lat, lon); + + g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + g.setStroke(new BasicStroke(stroke_width, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); + + if (0 <= state && state < AltosUIMap.stateColors.length) + g.setColor(AltosUIMap.stateColors[state]); + else + g.setColor(AltosUIMap.stateColors[AltosLib.ao_flight_invalid]); + + g.drawOval((int)pt.x-5, (int)pt.y-5, 10, 10); + g.drawOval((int)pt.x-20, (int)pt.y-20, 40, 40); + g.drawOval((int)pt.x-35, (int)pt.y-35, 70, 70); + + if (label != null) { + Rectangle2D bounds; + bounds = line_font.getStringBounds(label, g.getFontRenderContext()); + float x = (float) pt.x; + float y = (float) pt.y + (float) bounds.getHeight() / 2.0f; + + g.setFont(line_font); + g.setColor(Color.WHITE); + for (int dy = -2; dy <= 2; dy += 2) + for (int dx = -2; dx <= 2; dx += 2) + g.drawString(label, x + dx, y + dy); + if (0 <= state && state < AltosUIMap.stateColors.length) + g.setColor(AltosUIMap.stateColors[state]); + else + g.setColor(AltosUIMap.stateColors[AltosLib.ao_flight_invalid]); + g.drawString(label, x, y); + } + } + } - g.drawOval((int)pt.x-5, (int)pt.y-5, 10, 10); - g.drawOval((int)pt.x-20, (int)pt.y-20, 40, 40); - g.drawOval((int)pt.x-35, (int)pt.y-35, 70, 70); + MapMark(double lat, double lon, int state, String label) { + super(lat, lon, state, label); } MapMark(double lat, double lon, int state) { @@ -403,6 +431,10 @@ public class AltosUIMap extends JComponent implements AltosFlightDisplay, AltosM return new MapMark(lat, lon, state); } + public AltosMapMark new_mark(double lat, double lon, int state, String label) { + return new MapMark(lat, lon, state, label); + } + 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); } @@ -476,6 +508,10 @@ public class AltosUIMap extends JComponent implements AltosFlightDisplay, AltosM map.add_mark(lat, lon, status); } + public void add_mark(double lat, double lon, int status, String label) { + map.add_mark(lat, lon, status, label); + } + public void clear_marks() { map.clear_marks(); } diff --git a/altosuilib/AltosUIMapPreload.java b/altosuilib/AltosUIMapPreload.java index 9ba27355..6d0d8b70 100644 --- a/altosuilib/AltosUIMapPreload.java +++ b/altosuilib/AltosUIMapPreload.java @@ -139,6 +139,7 @@ public class AltosUIMapPreload extends AltosUIFrame implements ActionListener, I JProgressBar pbar; JLabel site_list_label; + java.util.List sites; JComboBox site_list; JToggleButton load_button; @@ -227,10 +228,29 @@ public class AltosUIMapPreload extends AltosUIFrame implements ActionListener, I return 1 << AltosMap.maptype_hybrid; } + void add_mark(double lat, double lon, int state, String label) { + map.add_mark(lat, lon, state, label); + } + + void reset_marks() { + map.clear_marks(); + AltosLatLon centre = null; + String centre_name = null; + if (map != null && map.map != null) + centre = map.map.centre; + for (AltosLaunchSite site : sites) { + if (centre != null && centre.lat == site.latitude && centre.lon == site.longitude) + centre_name = site.name; + else + add_mark(site.latitude, site.longitude, AltosLib.ao_flight_main, site.name); + } + if (centre != null) + add_mark(centre.lat, centre.lon, AltosLib.ao_flight_boost, centre_name); + } + void center_map(double latitude, double longitude) { map.map.centre(new AltosLatLon(latitude, longitude)); - map.clear_marks(); - map.add_mark(latitude, longitude, AltosLib.ao_flight_boost); + reset_marks(); } void center_map() { @@ -294,6 +314,7 @@ public class AltosUIMapPreload extends AltosUIFrame implements ActionListener, I } public void notify_launch_sites(final java.util.List sites) { + this.sites = sites; SwingUtilities.invokeLater(new Runnable() { public void run() { int i = 1; @@ -301,6 +322,7 @@ public class AltosUIMapPreload extends AltosUIFrame implements ActionListener, I site_list.insertItemAt(site, i); i++; } + reset_marks(); } }); } diff --git a/ao-bringup/test-easymini b/ao-bringup/test-easymini index ddcfcd54..c4479680 100755 --- a/ao-bringup/test-easymini +++ b/ao-bringup/test-easymini @@ -21,6 +21,8 @@ while [ $found -eq 0 ]; do echo -e '\e[34m'Testing $product $serial $dev'\e[39m' echo "" + sleep 0.25 + ./test-igniters-nowait "$dev" drogue main echo "" @@ -42,7 +44,6 @@ while [ $found -eq 0 ]; do echo -e '\e[31m'"$PRODUCT-$VERSION serial $serial failed"'\e[39m' exit 1 fi - echo "" echo -e '\e[32m'"$PRODUCT-v$VERSION" serial "$serial" is ready to ship'\e[39m' @@ -57,6 +58,5 @@ while [ $found -eq 0 ]; do if [ $result -ne 2 ]; then exit $result fi - echo 'No device, sleeping...' - sleep 1 + sleep 0.25 done diff --git a/ao-bringup/test-easymotor b/ao-bringup/test-easymotor new file mode 100755 index 00000000..a99ca9d6 --- /dev/null +++ b/ao-bringup/test-easymotor @@ -0,0 +1,40 @@ +#!/bin/sh + +VERSION=2 +PRODUCT=EasyMotor +BASE=`echo $PRODUCT | tr 'A-Z' 'a-z'` + +echo "$PRODUCT-v$VERSION Test Program" +echo "Copyright 2021 by Bdale Garbee. Released under GPL v3" +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 "" + + 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 "$PRODUCT-v$VERSION" serial "$serial" is ready to ship + ret=0 + ;; + esac +done diff --git a/ao-bringup/turnon_easymotor b/ao-bringup/turnon_easymotor new file mode 100755 index 00000000..306e0ad9 --- /dev/null +++ b/ao-bringup/turnon_easymotor @@ -0,0 +1,75 @@ +#!/bin/sh + +PRODUCT=EasyMotor +VERSION=2 +REPO=~/altusmetrumllc/Binaries + +if [ -x /usr/bin/dfu-util ]; then + DFU_UTIL=/usr/bin/dfu-util +else + echo "Can't find dfu-util! 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 2021 by Bdale Garbee. Released under GPL v3" +echo +echo "Expectations:" +echo "\t$PRODUCT v$VERSION" +echo "\t\twith USB cable attached" +echo + +case $# in + 1) + SERIAL="$1" + echo "$PRODUCT-$VERSION serial number: $SERIAL" + ;; + 0) + echo -n "$PRODUCT-$VERSION serial number: " + read SERIAL + ;; + *) + echo "Usage: $0 " 1>&2 + exit 1; + ;; +esac + + +echo $DFU_UTIL + +$DFU_UTIL -v -v -R -a 0 -s 0x08000000:leave -D $REPO/loaders/easymotor-v$VERSION*.bin + +sleep 3 + +$USBLOAD --serial=$SERIAL $REPO/easymotor-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 + +failed=1 +while [ $failed = 1 ]; do + ../ao-tools/ao-cal-accel/ao-cal-accel $dev + failed=$? +done + +./test-easymotor + +exit $? diff --git a/ao-tools/ao-dump-up/ao-dump-up.c b/ao-tools/ao-dump-up/ao-dump-up.c index 6866ef59..31bae471 100644 --- a/ao-tools/ao-dump-up/ao-dump-up.c +++ b/ao-tools/ao-dump-up/ao-dump-up.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include "cc-usb.h" #include "cc.h" @@ -52,6 +53,29 @@ static int get_nonwhite(struct cc_usb *cc, int timeout) } } +static const uint8_t test_data[] = { + 0xfc, 0xfd, 0xfe, 0xff, 0xf8, 0xf9, 0xfa, 0xfb, 0x40, 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, + 0x17, 0x08, +}; + +static bool test_failed; +static int test_pos; + +static void +check_test(uint8_t b) +{ + if (test_pos >= sizeof (test_data) || test_data[test_pos++] != b) + test_failed = true; +} + static uint8_t get_hexc(struct cc_usb *cc) { @@ -94,6 +118,7 @@ get_hex(struct cc_usb *cc) int h = (a << 4) + b; file_crc = log_crc(file_crc, h); + check_test(h); return h; } @@ -191,8 +216,12 @@ main (int argc, char **argv) current_crc = swap16(~file_crc & 0xffff); crc = get_16(cc); /* crc */ putchar ('\n'); - if (crc == current_crc) - printf("CRC valid\n"); + if (crc == current_crc) { + if (!test_failed) + printf("\033[32mValid MicroTest Data\033[39m\n"); + else + printf("CRC valid\n"); + } else printf("CRC invalid\n"); cc_usb_close(cc); diff --git a/ao-tools/ao-flash/ao-flash-stm32f0x b/ao-tools/ao-flash/ao-flash-stm32f0x index 45643a4f..89e26643 100755 --- a/ao-tools/ao-flash/ao-flash-stm32f0x +++ b/ao-tools/ao-flash/ao-flash-stm32f0x @@ -10,7 +10,7 @@ trap "rm $cmds" 0 1 15 file="$1" echo "program $file verify reset" > $cmds openocd \ - -f interface/stlink-v2.cfg \ - -f target/stm32f0x_stlink.cfg \ + -f interface/stlink.cfg \ + -f target/stm32f0x.cfg \ -f $cmds \ -c shutdown diff --git a/configure.ac b/configure.ac index 67e84600..f389393a 100644 --- a/configure.ac +++ b/configure.ac @@ -18,13 +18,13 @@ dnl dnl Process this file with autoconf to create configure. AC_PREREQ(2.57) -AC_INIT([altos], 1.9.6) -ANDROID_VERSION=27 +AC_INIT([altos], 1.9.7) +ANDROID_VERSION=29 AC_CONFIG_SRCDIR([src/kernel/ao.h]) AM_INIT_AUTOMAKE([foreign dist-bzip2]) AM_MAINTAINER_MODE -RELEASE_DATE=2020-09-29 +RELEASE_DATE=2021-06-08 AC_SUBST(RELEASE_DATE) DOC_DATE=`LC_ALL=C date -d $RELEASE_DATE +'%d %b %Y'` diff --git a/doc/Makefile.am b/doc/Makefile.am index db742953..560c868f 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -17,6 +17,7 @@ FAKETIME=TZ=UTC faketime -f '$(RELEASE_DATE) 00:00:00 i0' endif RELNOTES_INC=\ + release-notes-1.9.7.inc \ release-notes-1.9.6.inc \ release-notes-1.9.5.inc \ release-notes-1.9.4.inc \ @@ -163,7 +164,17 @@ INC_FILES=\ ADOC_FILES=$(TXT_FILES:.txt=.adoc) $(INC_FILES:.inc=.adoc) -TELELAUNCH_TXT_FILES=altusmetrum.txt +MOTORTEST_TXT_FILES=motortest.txt + +MOTORTEST_INC_FILES=\ + motortest-configuration.inc \ + motortest-installation.inc \ + motortest-intro.inc \ + motortest-operation.inc + +MOTORTEST_ADOC_FILES=$(MOTORTEST_TXT_FILES:.txt=.adoc) $(MOTORTEST_INC_FILES:.inc=.adoc) + +TELELAUNCH_TXT_FILES=telelaunch.txt TELELAUNCH_INC_FILES=\ header.inc \ @@ -244,12 +255,12 @@ ONEFILE_HTML_FILES=$(ONEFILE_TXT_FILES:.txt=.html) AM_HTML=am.html -PUBLISH_HTML=altusmetrum.html micropeak.html telegps.html easymini.html telelaunch.html $(ONEFILE_HTML_FILES) +PUBLISH_HTML=altusmetrum.html micropeak.html telegps.html easymini.html motortest.html telelaunch.html $(ONEFILE_HTML_FILES) HTML=$(PUBLISH_HTML) $(RELNOTES_HTML) if ASCIIDOCTOR_PDF -PDF=altusmetrum.pdf micropeak.pdf telegps.pdf easymini.pdf telelaunch.pdf $(ONEFILE_PDF_FILES) \ +PDF=altusmetrum.pdf micropeak.pdf telegps.pdf easymini.pdf motortest.pdf telelaunch.pdf $(ONEFILE_PDF_FILES) \ $(OUTLINE_PDF_FILES) endif @@ -308,6 +319,8 @@ map-loading.adoc: $(MAP_SVG_FILES) altusmetrum.pdf altusmetrum.html: $(ADOC_FILES) $(IMAGES) +motortest.pdf motortest.html: $(MOTORTEST_ADOC_FILES) $(IMAGES) + telelaunch.pdf telelaunch.html: $(TELELAUNCH_ADOC_FILES) $(IMAGES) telegps.html telegps.pdf: $(TELEGPS_ADOC_FILES) $(IMAGES) @@ -345,7 +358,7 @@ publish-keithp: am.html $(DOC) $(FONTS) 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) $(TELELAUNCH_ADOC_FILES) + rm -f am.html $(HTML) $(PDF) $(ADOC_FILES) $(TELEGPS_ADOC_FILES) $(MICROPEAK_ADOC_FILES) $(TELELAUNCH_ADOC_FILES) $(MOTORTEST_ADOC_FILES) distclean: clean rm -f $(HTML) $(PDF) diff --git a/doc/altosdroid.inc b/doc/altosdroid.inc index dce81c3b..08e0b7e9 100644 --- a/doc/altosdroid.inc +++ b/doc/altosdroid.inc @@ -36,6 +36,10 @@ === Connecting to TeleBT over Bluetooth™ + Note that when turning TeleBT on, you may see a brief LED + flash, but there will be no "activity" indicated until you + pair with the device from AltosDroid. + Press the Android 'Menu' button or soft-key to see the configuration options available. Select the 'Connect a device' option and then the 'Scan for devices' entry diff --git a/doc/altusmetrum-theme.yml b/doc/altusmetrum-theme.yml index f3026222..bed7c141 100644 --- a/doc/altusmetrum-theme.yml +++ b/doc/altusmetrum-theme.yml @@ -51,7 +51,7 @@ footer: left: content: '{page-number}' right: - content: '© 2020 Bdale Garbee and Keith Packard. Creative Commons ShareAlike 3.0 License' + content: '© 2021 Bdale Garbee and Keith Packard. Creative Commons ShareAlike 3.0 License' verso: left: content: $footer_recto_right_content diff --git a/doc/altusmetrum.txt b/doc/altusmetrum.txt index c2492b0f..4b7699c5 100644 --- a/doc/altusmetrum.txt +++ b/doc/altusmetrum.txt @@ -5,7 +5,7 @@ Keith Packard ; Bdale Garbee ; Bob Finch; Anth :revdate: 1 Jan 1970 :icons: :icontype: svg -:copyright: Bdale Garbee and Keith Packard 2020 +:copyright: Bdale Garbee and Keith Packard 2021 :doctype: book :numbered: :stylesheet: am.css @@ -21,6 +21,7 @@ Keith Packard ; Bdale Garbee ; Bob Finch; Anth :easymega: 1 :telegps: 1 :easytimer: 1 +:easymotor: 1 :application: AltosUI :pdf-stylesdir: . :pdf-style: altusmetrum diff --git a/doc/easymini-release-notes.inc b/doc/easymini-release-notes.inc index 9dd0058e..dad66c28 100644 --- a/doc/easymini-release-notes.inc +++ b/doc/easymini-release-notes.inc @@ -1,5 +1,9 @@ [appendix] == Release Notes + :leveloffset: 2 + include::release-notes-1.9.7.adoc[] + + <<<< :leveloffset: 2 include::release-notes-1.9.6.adoc[] diff --git a/doc/easymini.txt b/doc/easymini.txt index 448f8060..d18b3ee5 100644 --- a/doc/easymini.txt +++ b/doc/easymini.txt @@ -3,7 +3,7 @@ Keith Packard ; Bdale Garbee :title-logo-image: image:../themes/background.png[] :revnumber: v{version} :revdate: 01 Jan 1970 -:copyright: Bdale Garbee and Keith Packard 2020 +:copyright: Bdale Garbee and Keith Packard 2021 :doctype: book :numbered: :toc: diff --git a/doc/header.inc b/doc/header.inc index 6bc616f5..cb80360b 100644 --- a/doc/header.inc +++ b/doc/header.inc @@ -7,7 +7,7 @@ endif::[] [license] == License -Copyright © 2018 Bdale Garbee and Keith Packard +Copyright © 2021 Bdale Garbee and Keith Packard This document is released under the terms of the link:http://creativecommons.org/licenses/by-sa/3.0/[Creative Commons ShareAlike 3.0 License] diff --git a/doc/micropeak.txt b/doc/micropeak.txt index 18a5afdf..afb935d7 100644 --- a/doc/micropeak.txt +++ b/doc/micropeak.txt @@ -2,7 +2,7 @@ Keith Packard ; Bdale Garbee :revnumber: v{version} :revdate: 01 Jan 1970 -:copyright: Bdale Garbee and Keith Packard 2020 +:copyright: Bdale Garbee and Keith Packard 2021 :stylesheet: am.css :linkcss: :toc: diff --git a/doc/motortest-configuration.inc b/doc/motortest-configuration.inc new file mode 100644 index 00000000..e75cebb9 --- /dev/null +++ b/doc/motortest-configuration.inc @@ -0,0 +1,18 @@ +== Configuration + + There is very little that must be configured to make EasyMotor work. + In fact, the default configuration from the factory is typically + sufficient without change. + + === Connecting to a Unit + + To change any EasyMotor configuration, you need to attach + a battery and a power switch, then use a micro USB cable + to connect the board to a computer running AltosUI. + + === Changing the Configuration + + All available configuration options can be set using the + “Configure Altimeter” menu selection within the AltosUI + program. + diff --git a/doc/motortest-installation.inc b/doc/motortest-installation.inc new file mode 100644 index 00000000..290c7b8f --- /dev/null +++ b/doc/motortest-installation.inc @@ -0,0 +1,51 @@ +== Installation + + EasyMotor needs to be rigidly attached in the airframe, and the + long axis of the circuit board needs to be aligned with the axis + of flight. By default, the round beeper on the board should be + “up” towards the nose cone, and the screw terminal strips should + be “down” towards the fins and motor nozzle end of the rocket. + + === Power Switch and Battery + + In addition to the circuit board itself, EasyMotor needs + a power switch and battery to operate. Unlike most other + Altus Metrum products, EasyMotor does not work with + single-cell LiPo batteries. That's because commonly + available inexpensive pressure sensors need 5V, which is + more than a single-cell LiPo provides. Any battery that + provides from 6.5 to about 15 volts should work. Good + choices are the common 9V alkaline battery, or the very + small and light A23 12V alkaline batteries. + + Because he often mounts EasyMotor to the motor's forward + bulkhead instead of to the airframe itself, Bdale often + uses a length of “shooter wire” from an e-match or used + motor igniter as a power switch, routing the wire out of + the typical fin can vent hole and using “twist and tape” + to power up the board. Whatever works! + + === Pressure Sensor + + The primary motivation for designing EasyMotor was to have + a reliable way of recording motor chamber pressure during + flight. To that end, EasyMotor supports attachment of a + low-cost analog pressure sensor. The board provides 5V + to power the sensor, and an input for measuring and + logging the output voltage from the sensor. + + The kind of sensor EasyMotor is designed to work with + takes 5V in and has a linear analog output that ranges + from 0.5V at 0 to 4.5V at the maximum pressure supported + by the sensor. Very inexpensive sensors that have a + “1/8 NPT” threaded input, a “Buick-style” 3-pin connector, + and typically ship with a short cable and mating + connector, are readily available on eBay and AliExpress. + + To log in-flight chamber pressure, a typical approach + might be to drill a 1/8" sampling hole all the way + through the center of the motor's forward closure, then + drill and tap partially through the closure with a “1/8 + NPT” pipe tap. Fill the touch hole with grease, screw in + the pressure sensor, and attach the sensor leads to + EasyMotor. diff --git a/doc/motortest-intro.inc b/doc/motortest-intro.inc new file mode 100644 index 00000000..fa30cb98 --- /dev/null +++ b/doc/motortest-intro.inc @@ -0,0 +1,27 @@ +== 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 motor testing products from Altus Metrum. +Our first such product is EasyMotor, an in-flight motor data collection +board for hobby rockets. EasyMotor is a small circuit board that is meant +to log motor chamber pressure and rocket acceleration during flight. With +this data it's possible to determine whether a research motor is performing +as expected. With additional information about masses and airframe drag, +it is even possible to closely estimate complete motor performance. + +With EasyMotor, the dilemma of “do I burn this on a test stand to learn more +about how it actually works, or do I go fly it” is no more! You can fly your +motor and get real performance data about it too! + +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. + diff --git a/doc/motortest-operation.inc b/doc/motortest-operation.inc new file mode 100644 index 00000000..e38fbe3a --- /dev/null +++ b/doc/motortest-operation.inc @@ -0,0 +1,14 @@ +== Operation + + Operating an EasyMotor board is pretty easy. Turn the power on + before launch, typically during the usual pre-flight electronics + checklist after the rocket is installed on a launch rail. + + The board will beep out a Morse code “P” every few seconds + indicating that it's in pad mode and ready to detect launch. + Once launch is detected, the board logs pressure and acceleration + data 100 times per second throughout the flight. + + After flight, AltosUI can be used to download the flight data, + then export it to a comma separated values (CSV) file. Such a + file can easily be loaded into a spreadsheet for analysis. diff --git a/doc/release-notes-1.9.7.inc b/doc/release-notes-1.9.7.inc new file mode 100644 index 00000000..61aee84c --- /dev/null +++ b/doc/release-notes-1.9.7.inc @@ -0,0 +1,29 @@ += Release Notes for Version 1.9.7 +include::release-head.adoc[] +:doctype: article + + Version 1.9.7 + + == AltOS + + * Fix TeleGPS logging so that new data are appended to an existing log correctly + + == AltosUI + + * Support Mac OS X 11 (Big Sur) + + * Support Monitor Idle on Easy Timer + + * Fix TeleMega v4.0 and TeleMetrum v3.0 configuration in Antenna Down mode + + * Show launch sites in Load Maps view + + * Add IMU header names to CSV files + + * Clean up TeleGPS log corruption due to firmware bugs during firmware update + + == AltosDroid + + * Support older devices back to Android version 5.1 + + * Fix a number of issues that could result in app crashes diff --git a/doc/release-notes.inc b/doc/release-notes.inc index 2348c4ac..7a4c3348 100644 --- a/doc/release-notes.inc +++ b/doc/release-notes.inc @@ -1,5 +1,9 @@ [appendix] == Release Notes + :leveloffset: 2 + include::release-notes-1.9.7.adoc[] + + <<<< :leveloffset: 2 include::release-notes-1.9.6.adoc[] diff --git a/doc/specs.inc b/doc/specs.inc index 5c2c83cc..639a2b9a 100644 --- a/doc/specs.inc +++ b/doc/specs.inc @@ -165,6 +165,17 @@ |3.7-12V endif::easytimer[] + ifdef::easymotor[] + |EasyMotor v2.0 + |- + |ADXL375 200g + |- + |- + |- + |- + |6.5-15V + endif::easymotor[] + |=== @@ -227,7 +238,7 @@ endif::easymega[] ifdef::easytimer[] - |EasyMini + |EasyTimer |Debug USB Battery |Pyro A Pyro B Battery |0.8 inch (2.03cm) @@ -235,4 +246,13 @@ |24mm coupler endif::easytimer[] + ifdef::easymotor[] + |EasyMotor + |Debug USB + |+5V Pres GND Switch Battery + |0.8 inch (2.03cm) + |1½ inch (3.81cm) + |24mm coupler + endif::easymotor[] + |=== diff --git a/doc/telegps-release-notes.inc b/doc/telegps-release-notes.inc index 03d3ed76..c87b10e4 100644 --- a/doc/telegps-release-notes.inc +++ b/doc/telegps-release-notes.inc @@ -1,5 +1,9 @@ [appendix] == Release Notes + :leveloffset: 2 + include::release-notes-1.9.7.adoc[] + + <<<< :leveloffset: 2 include::release-notes-1.9.6.adoc[] diff --git a/doc/telegps.txt b/doc/telegps.txt index b8911a8a..6db28476 100644 --- a/doc/telegps.txt +++ b/doc/telegps.txt @@ -3,7 +3,7 @@ Keith Packard ; Bdale Garbee :title-logo-image: image:../themes/background.png[] :revnumber: v{version} :revdate: 01 Jan 1970 -:copyright: Bdale Garbee and Keith Packard 2020 +:copyright: Bdale Garbee and Keith Packard 2021 :stylesheet: am.css :linkcss: :toc: diff --git a/doc/telelaunch-configuration.inc b/doc/telelaunch-configuration.inc index 0317613c..a2477633 100644 --- a/doc/telelaunch-configuration.inc +++ b/doc/telelaunch-configuration.inc @@ -59,7 +59,7 @@ memory. For example, the default 435.750 MHz would be configured using - c F 435750 + c F 435750 + c w Note that the 'f' parameter is a frequency calibration value diff --git a/doc/telelaunch.txt b/doc/telelaunch.txt index 7522b983..89f98dd4 100644 --- a/doc/telelaunch.txt +++ b/doc/telelaunch.txt @@ -5,8 +5,7 @@ Bdale Garbee :revdate: 01 Jan 1970 :icons: :icontype: svg -:revremark: initial draft -:copyright: Bdale Garbee 2020 +:copyright: Bdale Garbee 2021 :doctype: book :numbered: :stylesheet: am.css diff --git a/doc/telemetry.txt b/doc/telemetry.txt index 4152de33..0df96abd 100644 --- a/doc/telemetry.txt +++ b/doc/telemetry.txt @@ -2,7 +2,7 @@ Keith Packard ; Bdale Garbee :revnumber: v{version} :revdate: 01 Jan 1970 -:copyright: Bdale Garbee and Keith Packard 2020 +:copyright: Bdale Garbee and Keith Packard 2021 :stylesheet: am.css :linkcss: :doctype: article diff --git a/doc/updating-firmware.inc b/doc/updating-firmware.inc index b9216a22..e2e1388a 100644 --- a/doc/updating-firmware.inc +++ b/doc/updating-firmware.inc @@ -17,6 +17,15 @@ you have before trying to reprogram them. endif::telemega[] + TeleMini v3 can be updated directly over USB, but has no USB connector + on the board. Instead, the USB signals are present on a row of 6 + holes adjacent to the copyright assertion in the silk screen. Thus, + updating firmware on TeleMini v3 requires making up a special cable, + after which you can treat it just like TeleMetrum or TeleMega. Many + USB cables seem to follow the color code of red is +5V, black is GND, + green is USB +, and white is USB -. On TeleMini v3, pin 3 which has + a square copper pad is ground, pin 1 is USB -, and pin 2 is USB +. + You may wish to begin by ensuring you have current firmware images. These are distributed as part of the AltOS software bundle that also includes the AltosUI ground station program. @@ -28,7 +37,7 @@ ifdef::telemega[] - === Updating TeleMega, TeleMetrum v2 or newer, EasyMega, EasyMini, TeleDongle v3 or TeleBT v3 Firmware + === Updating TeleMega, TeleMetrum v2 or newer, TeleMini v3, EasyMega, EasyMini, TeleDongle v3 or TeleBT v3 Firmware endif::telemega[] ifndef::telemega[] @@ -44,7 +53,8 @@ the target device. Power up the device. . Using a Micro USB cable, connect the target device to your - computer's USB socket. + computer's USB socket. If the target is a TeleMini v3, + make up and attach a special USB cable. . Run AltosUI, and select 'Flash Image' from the File menu. diff --git a/libaltos/altos.dll b/libaltos/altos.dll index ed0e4772..3a3aca0e 100755 Binary files a/libaltos/altos.dll and b/libaltos/altos.dll differ diff --git a/libaltos/altos64.dll b/libaltos/altos64.dll index e0edc1df..c83c59e9 100755 Binary files a/libaltos/altos64.dll and b/libaltos/altos64.dll differ diff --git a/libaltos/libaltos_windows.c b/libaltos/libaltos_windows.c index b92df708..43e347c4 100644 --- a/libaltos/libaltos_windows.c +++ b/libaltos/libaltos_windows.c @@ -135,6 +135,7 @@ static struct { unsigned int vid, pid; char *name; } name_map[] = { + { .vid = 0xfffe, .pid = 0x000d, .name = "EasyTimer" }, { .vid = 0xfffe, .pid = 0x0028, .name = "EasyMega" }, { .vid = 0xfffe, .pid = 0x002c, .name = "EasyMotor" }, { .name = NULL }, diff --git a/micropeak/Makefile.am b/micropeak/Makefile.am index 816dd4b3..9a0328d7 100644 --- a/micropeak/Makefile.am +++ b/micropeak/Makefile.am @@ -315,7 +315,8 @@ $(MACOSX_DIST): $(MACOSX_FILES) cp -a MicroPeak.app macosx/ cp -a $(MACOSX_README) macosx/ReadMe-MicroPeak.rtf cp -a $(MACOSX_INSTALL) macosx - cp -a $(DOC) macosx + mkdir -p macosx/Doc + cp -a $(DOC) macosx/Doc cp -p Info.plist macosx/MicroPeak.app/Contents cp -p $(MACOSX_DRIVERS) macosx mkdir -p macosx/MicroPeak.app/Contents/Resources/Java diff --git a/micropeak/MicroPeak.app/Contents/MacOS/JavaApplicationStub b/micropeak/MicroPeak.app/Contents/MacOS/JavaApplicationStub index 145a260b..aa96638f 100755 --- a/micropeak/MicroPeak.app/Contents/MacOS/JavaApplicationStub +++ b/micropeak/MicroPeak.app/Contents/MacOS/JavaApplicationStub @@ -1,16 +1,4 @@ #!/bin/bash -# -# Fix fonts. I don't know why the getting the -# basename of the app set to . matters, but it does -# -case "$0" in - /*) - cd `dirname "$0"` - ./`basename "$0"` "$@" - exit $? - ;; -esac -export FREETYPE_PROPERTIES=truetype:interpreter-version=35 ################################################################################## # # # universalJavaApplicationStub # @@ -23,14 +11,14 @@ export FREETYPE_PROPERTIES=truetype:interpreter-version=35 # # # @author Tobias Fischer # # @url https://github.com/tofi86/universalJavaApplicationStub # -# @date 2018-08-24 # -# @version 3.0.4 # +# @date 2021-02-21 # +# @version 3.2.0 # # # ################################################################################## # # # The MIT License (MIT) # # # -# Copyright (c) 2014-2018 Tobias Fischer # +# Copyright (c) 2014-2021 Tobias Fischer # # # # Permission is hereby granted, free of charge, to any person obtaining a copy # # of this software and associated documentation files (the "Software"), to deal # @@ -52,7 +40,18 @@ export FREETYPE_PROPERTIES=truetype:interpreter-version=35 # # ################################################################################## - +# +# Fix fonts. I don't know why the getting the +# basename of the app set to . matters, but it does +# +case "$0" in + /*) + cd `dirname "$0"` + ./`basename "$0"` "$@" + exit $? + ;; +esac +export FREETYPE_PROPERTIES=truetype:interpreter-version=35 # function 'stub_logger()' # @@ -178,6 +177,8 @@ if [ $exitcode -eq 0 ]; then JavaFolder="${AppleJavaFolder}" ResourcesFolder="${AppleResourcesFolder}" + # set expandable variables + APP_ROOT="${AppPackageFolder}" APP_PACKAGE="${AppPackageFolder}" JAVAROOT="${AppleJavaFolder}" USER_HOME="$HOME" @@ -192,7 +193,7 @@ if [ $exitcode -eq 0 ]; then # AppPackageRoot is the standard WorkingDirectory when the script is started WorkingDirectory="${AppPackageRoot}" fi - # expand variables $APP_PACKAGE, $JAVAROOT, $USER_HOME + # expand variables $APP_PACKAGE, $APP_ROOT, $JAVAROOT, $USER_HOME WorkingDirectory=$(eval echo "${WorkingDirectory}") @@ -215,7 +216,7 @@ if [ $exitcode -eq 0 ]; then else JVMClassPath=${JVMClassPath_RAW} fi - # expand variables $APP_PACKAGE, $JAVAROOT, $USER_HOME + # expand variables $APP_PACKAGE, $APP_ROOT, $JAVAROOT, $USER_HOME JVMClassPath=$(eval echo "${JVMClassPath}") # read the JVM Options in either Array or String style @@ -225,6 +226,8 @@ if [ $exitcode -eq 0 ]; then else JVMDefaultOptions=${JVMDefaultOptions_RAW} fi + # expand variables $APP_PACKAGE, $APP_ROOT, $JAVAROOT, $USER_HOME (#84) + JVMDefaultOptions=$(eval echo "${JVMDefaultOptions}") # read StartOnMainThread and add as -XstartOnFirstThread JVMStartOnMainThread=$(plist_get_java ':StartOnMainThread') @@ -232,9 +235,14 @@ if [ $exitcode -eq 0 ]; then JVMDefaultOptions+=" -XstartOnFirstThread" fi - # read the JVM Arguments as an array and retain spaces + # read the JVM Arguments in either Array or String style (#76) and retain spaces IFS=$'\t\n' - MainArgs=($(xargs -n1 <<<$(plist_get_java ':Arguments'))) + MainArgs_RAW=$(plist_get_java ':Arguments' | xargs) + if [[ $MainArgs_RAW == *Array* ]] ; then + MainArgs=($(xargs -n1 <<<$(plist_get_java ':Arguments' | tr -d '\n' | sed -E 's/Array \{ *(.*) *\}/\1/g' | sed 's/ */ /g'))) + else + MainArgs=($(xargs -n1 <<<$(plist_get_java ':Arguments'))) + fi unset IFS # post processing of the array follows further below... @@ -252,7 +260,11 @@ else ResourcesFolder="${OracleResourcesFolder}" WorkingDirectory="${OracleJavaFolder}" + # set expandable variables APP_ROOT="${AppPackageFolder}" + APP_PACKAGE="${AppPackageFolder}" + JAVAROOT="${OracleJavaFolder}" + USER_HOME="$HOME" # read the MainClass name JVMMainClass="$(plist_get ':JVMMainClassName')" @@ -270,12 +282,12 @@ else JVMClassPath_RAW=$(plist_get ':JVMClassPath') if [[ $JVMClassPath_RAW == *Array* ]] ; then JVMClassPath=.$(plist_get ':JVMClassPath' | grep " " | sed 's/^ */:/g' | tr -d '\n' | xargs) - # expand variables $APP_PACKAGE, $JAVAROOT, $USER_HOME + # expand variables $APP_PACKAGE, $APP_ROOT, $JAVAROOT, $USER_HOME JVMClassPath=$(eval echo "${JVMClassPath}") elif [[ ! -z ${JVMClassPath_RAW} ]] ; then JVMClassPath=${JVMClassPath_RAW} - # expand variables $APP_PACKAGE, $JAVAROOT, $USER_HOME + # expand variables $APP_PACKAGE, $APP_ROOT, $JAVAROOT, $USER_HOME JVMClassPath=$(eval echo "${JVMClassPath}") else @@ -284,8 +296,11 @@ else # Do NOT expand the default 'AppName.app/Contents/Java/*' classpath (#42) fi - # read the JVM Default Options + # read the JVM Default Options by parsing the :JVMDefaultOptions + # and pulling all values starting with a dash (-) JVMDefaultOptions=$(plist_get ':JVMDefaultOptions' | grep -o " \-.*" | tr -d '\n' | xargs) + # expand variables $APP_PACKAGE, $APP_ROOT, $JAVAROOT, $USER_HOME (#99) + JVMDefaultOptions=$(eval echo "${JVMDefaultOptions}") # read the Main Arguments from JVMArguments key as an array and retain spaces (see #46 for naming details) IFS=$'\t\n' @@ -299,6 +314,18 @@ else fi +# (#75) check for undefined icons or icon names without .icns extension and prepare +# an osascript statement for those cases when the icon can be shown in the dialog +DialogWithIcon="" +if [ ! -z ${CFBundleIconFile} ]; then + if [[ ${CFBundleIconFile} == *.icns ]] && [[ -f "${ResourcesFolder}/${CFBundleIconFile}" ]] ; then + DialogWithIcon=" with icon path to resource \"${CFBundleIconFile}\" in bundle (path to me)" + elif [[ ${CFBundleIconFile} != *.icns ]] && [[ -f "${ResourcesFolder}/${CFBundleIconFile}.icns" ]] ; then + CFBundleIconFile+=".icns" + DialogWithIcon=" with icon path to resource \"${CFBundleIconFile}\" in bundle (path to me)" + fi +fi + # JVMVersion: post processing and optional splitting if [[ ${JVMVersion} == *";"* ]]; then @@ -309,14 +336,14 @@ fi stub_logger "[JavaRequirement] JVM minimum version: ${JVMVersion}" stub_logger "[JavaRequirement] JVM maximum version: ${JVMMaxVersion}" -# MainArgs: replace occurences of $APP_ROOT with its content +# MainArgs: expand variables $APP_PACKAGE, $APP_ROOT, $JAVAROOT, $USER_HOME MainArgsArr=() for i in "${MainArgs[@]}" do MainArgsArr+=("$(eval echo "$i")") done -# JVMOptions: replace occurences of $APP_ROOT with its content +# JVMOptions: expand variables $APP_PACKAGE, $APP_ROOT, $JAVAROOT, $USER_HOME JVMOptionsArr=() for i in "${JVMOptions[@]}" do @@ -327,14 +354,37 @@ done # internationalized messages ############################################ -LANG=$(defaults read -g AppleLocale) -stub_logger "[Language] $LANG" +# supported languages / available translations +stubLanguages="^(fr|de|zh|es|en)-" + +# read user preferred languages as defined in macOS System Preferences (#101) +stub_logger '[LanguageSearch] Checking preferred languages in macOS System Preferences...' +appleLanguages=($(defaults read -g AppleLanguages | grep '\s"' | tr -d ',' | xargs)) +stub_logger "[LanguageSearch] ... found [${appleLanguages[*]}]" + +language="" +for i in "${appleLanguages[@]}" +do + langValue="${i%-*}" + if [[ "$i" =~ $stubLanguages ]]; then + stub_logger "[LanguageSearch] ... selected '$i' ('$langValue') as the default language for the launcher stub" + language=${langValue} + break + fi +done +if [ -z "${language}" ]; then + language="en" + stub_logger "[LanguageSearch] ... selected fallback 'en' as the default language for the launcher stub" +fi +stub_logger "[Language] $language" -# French localization -if [[ $LANG == fr* ]] ; then + +case "${language}" in +# French +fr) MSG_ERROR_LAUNCHING="ERREUR au lancement de '${CFBundleName}'." MSG_MISSING_MAINCLASS="'MainClass' n'est pas spécifié.\nL'application Java ne peut pas être lancée." - MSG_JVMVERSION_REQ_INVALID="La syntaxe de la version Java demandée est invalide: %s\nVeuillez contacter le développeur de l'application." + MSG_JVMVERSION_REQ_INVALID="La syntaxe de la version de Java demandée est invalide: %s\nVeuillez contacter le développeur de l'application." MSG_NO_SUITABLE_JAVA="La version de Java installée sur votre système ne convient pas.\nCe programme nécessite Java %s" MSG_JAVA_VERSION_OR_LATER="ou ultérieur" MSG_JAVA_VERSION_LATEST="(dernière mise à jour)" @@ -342,10 +392,12 @@ if [[ $LANG == fr* ]] ; then MSG_NO_SUITABLE_JAVA_CHECK="Merci de bien vouloir installer la version de Java requise." MSG_INSTALL_JAVA="Java doit être installé sur votre système.\nRendez-vous sur java.com et suivez les instructions d'installation..." MSG_LATER="Plus tard" - MSG_VISIT_JAVA_DOT_COM="Visiter java.com" + MSG_VISIT_JAVA_DOT_COM="Java by Oracle" + MSG_VISIT_ADOPTOPENJDK="Java by AdoptOpenJDK" + ;; -# German localization -elif [[ $LANG == de* ]] ; then +# German +de) MSG_ERROR_LAUNCHING="FEHLER beim Starten von '${CFBundleName}'." MSG_MISSING_MAINCLASS="Die 'MainClass' ist nicht spezifiziert!\nDie Java-Anwendung kann nicht gestartet werden!" MSG_JVMVERSION_REQ_INVALID="Die Syntax der angeforderten Java-Version ist ungültig: %s\nBitte kontaktieren Sie den Entwickler der App." @@ -356,10 +408,12 @@ elif [[ $LANG == de* ]] ; then MSG_NO_SUITABLE_JAVA_CHECK="Stellen Sie sicher, dass die angeforderte Java-Version installiert ist." MSG_INSTALL_JAVA="Auf Ihrem System muss die 'Java'-Software installiert sein.\nBesuchen Sie java.com für weitere Installationshinweise." MSG_LATER="Später" - MSG_VISIT_JAVA_DOT_COM="java.com öffnen" + MSG_VISIT_JAVA_DOT_COM="Java von Oracle" + MSG_VISIT_ADOPTOPENJDK="Java von AdoptOpenJDK" + ;; -# Simplifyed Chinese localization -elif [[ $LANG == zh* ]] ; then +# Simplified Chinese +zh) MSG_ERROR_LAUNCHING="无法启动 '${CFBundleName}'." MSG_MISSING_MAINCLASS="没有指定 'MainClass'!\nJava程序无法启动!" MSG_JVMVERSION_REQ_INVALID="Java版本参数语法错误: %s\n请联系该应用的开发者。" @@ -370,10 +424,28 @@ elif [[ $LANG == zh* ]] ; then MSG_NO_SUITABLE_JAVA_CHECK="请确保系统中安装了所需的Java版本" MSG_INSTALL_JAVA="你需要在Mac中安装Java运行环境!\n访问 java.com 了解如何安装。" MSG_LATER="稍后" - MSG_VISIT_JAVA_DOT_COM="访问 java.com" - -# English default localization -else + MSG_VISIT_JAVA_DOT_COM="Java by Oracle" + MSG_VISIT_ADOPTOPENJDK="Java by AdoptOpenJDK" + ;; + +# Spanish +es) + MSG_ERROR_LAUNCHING="ERROR iniciando '${CFBundleName}'." + MSG_MISSING_MAINCLASS="¡'MainClass' no especificada!\n¡La aplicación Java no puede iniciarse!" + MSG_JVMVERSION_REQ_INVALID="La sintaxis de la versión Java requerida no es válida: %s\nPor favor, contacte con el desarrollador de la aplicación." + MSG_NO_SUITABLE_JAVA="¡No se encontró una versión de Java adecuada en su sistema!\nEste programa requiere Java %s" + MSG_JAVA_VERSION_OR_LATER="o posterior" + MSG_JAVA_VERSION_LATEST="(ultima actualización)" + MSG_JAVA_VERSION_MAX="superior a %s" + MSG_NO_SUITABLE_JAVA_CHECK="Asegúrese de instalar la versión Java requerida." + MSG_INSTALL_JAVA="¡Necesita tener JAVA instalado en su Mac!\nVisite java.com para consultar las instrucciones para su instalación..." + MSG_LATER="Más tarde" + MSG_VISIT_JAVA_DOT_COM="Java de Oracle" + MSG_VISIT_ADOPTOPENJDK="Java de AdoptOpenJDK" + ;; + +# English | default +en|*) MSG_ERROR_LAUNCHING="ERROR launching '${CFBundleName}'." MSG_MISSING_MAINCLASS="'MainClass' isn't specified!\nJava application cannot be started!" MSG_JVMVERSION_REQ_INVALID="The syntax of the required Java version is invalid: %s\nPlease contact the App developer." @@ -384,8 +456,10 @@ else MSG_NO_SUITABLE_JAVA_CHECK="Make sure you install the required Java version." MSG_INSTALL_JAVA="You need to have JAVA installed on your Mac!\nVisit java.com for installation instructions..." MSG_LATER="Later" - MSG_VISIT_JAVA_DOT_COM="Visit java.com" -fi + MSG_VISIT_JAVA_DOT_COM="Java by Oracle" + MSG_VISIT_ADOPTOPENJDK="Java by AdoptOpenJDK" + ;; +esac @@ -468,7 +542,7 @@ function get_comparable_java_version() { ################################################################################ function is_valid_requirement_pattern() { local java_req=$1 - java8pattern='1\.[4-8](\.0)?(\.0_[0-9]+)?[*+]?' + java8pattern='1\.[4-8](\.[0-9]+)?(\.0_[0-9]+)?[*+]?' java9pattern='(9|1[0-9])(-ea|[*+]|(\.[0-9]+){1,2}[*+]?)?' # test matches either old Java versioning scheme (up to 1.8) or new scheme (starting with 9) if [[ ${java_req} =~ ^(${java8pattern}|${java9pattern})$ ]]; then @@ -501,20 +575,28 @@ if [ -n "$JAVA_HOME" ] ; then if [[ $JAVA_HOME == /* ]] ; then # if "$JAVA_HOME" starts with a Slash it's an absolute path JAVACMD="$JAVA_HOME/bin/java" + stub_logger "[JavaSearch] ... parsing JAVA_HOME as absolute path to the executable '$JAVACMD'" else # otherwise it's a relative path to "$AppPackageFolder" JAVACMD="$AppPackageFolder/$JAVA_HOME/bin/java" + stub_logger "[JavaSearch] ... parsing JAVA_HOME as relative path inside the App bundle to the executable '$JAVACMD'" fi JAVACMD_version=$(get_comparable_java_version $(get_java_version_from_cmd "${JAVACMD}")) else - stub_logger "[JavaSearch] ... didn't found JAVA_HOME" + stub_logger "[JavaSearch] ... haven't found JAVA_HOME" fi # check for any other or a specific Java version # also if $JAVA_HOME exists but isn't executable if [ -z "${JAVACMD}" ] || [ ! -x "${JAVACMD}" ] ; then - stub_logger "[JavaSearch] Checking for JavaVirtualMachines on the system ..." + + # add a warning in the syslog if JAVA_HOME is not executable or not found (#100) + if [ -n "$JAVA_HOME" ] ; then + stub_logger "[JavaSearch] ... but no 'java' executable was found at the JAVA_HOME location!" + fi + + stub_logger "[JavaSearch] Searching for JavaVirtualMachines on the system ..." # reset variables JAVACMD="" JAVACMD_version="" @@ -525,7 +607,7 @@ if [ -z "${JAVACMD}" ] || [ ! -x "${JAVACMD}" ] ; then # log exit cause stub_logger "[EXIT 4] ${MSG_JVMVERSION_REQ_INVALID_EXPANDED}" # display error message with AppleScript - osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_JVMVERSION_REQ_INVALID_EXPANDED}\" with title \"${CFBundleName}\" buttons {\" OK \"} default button 1 with icon path to resource \"${CFBundleIconFile}\" in bundle (path to me)" + osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_JVMVERSION_REQ_INVALID_EXPANDED}\" with title \"${CFBundleName}\" buttons {\" OK \"} default button 1${DialogWithIcon}" # exit with error exit 4 fi @@ -535,7 +617,7 @@ if [ -z "${JAVACMD}" ] || [ ! -x "${JAVACMD}" ] ; then # log exit cause stub_logger "[EXIT 5] ${MSG_JVMVERSION_REQ_INVALID_EXPANDED}" # display error message with AppleScript - osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_JVMVERSION_REQ_INVALID_EXPANDED}\" with title \"${CFBundleName}\" buttons {\" OK \"} default button 1 with icon path to resource \"${CFBundleIconFile}\" in bundle (path to me)" + osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_JVMVERSION_REQ_INVALID_EXPANDED}\" with title \"${CFBundleName}\" buttons {\" OK \"} default button 1${DialogWithIcon}" # exit with error exit 5 fi @@ -543,15 +625,41 @@ if [ -z "${JAVACMD}" ] || [ ! -x "${JAVACMD}" ] ; then # find installed JavaVirtualMachines (JDK + JRE) allJVMs=() - # read JDK's from '/usr/libexec/java_home -V' command - while read -r line; do - version=$(echo $line | awk -F $',' '{print $1;}') - path=$(echo $line | awk -F $'" ' '{print $2;}') - path+="/bin/java" - allJVMs+=("$version:$path") - done < <(/usr/libexec/java_home -V 2>&1 | grep '^[[:space:]]') - # unset while loop variables - unset version path + + # read JDK's from '/usr/libexec/java_home --xml' command with PlistBuddy and a custom Dict iterator + # idea: https://stackoverflow.com/a/14085460/1128689 and https://scriptingosx.com/2018/07/parsing-dscl-output-in-scripts/ + javaXml=$(/usr/libexec/java_home --xml) + javaCounter=$(/usr/libexec/PlistBuddy -c "Print" /dev/stdin <<< $javaXml | grep "Dict" | wc -l | tr -d ' ') + + # iterate over all Dict entries + # but only if there are any JVMs at all (#93) + if [ "$javaCounter" -gt "0" ] ; then + for idx in $(seq 0 $((javaCounter - 1))) + do + version=$(/usr/libexec/PlistBuddy -c "print :$idx:JVMVersion" /dev/stdin <<< $javaXml) + path=$(/usr/libexec/PlistBuddy -c "print :$idx:JVMHomePath" /dev/stdin <<< $javaXml) + path+="/bin/java" + allJVMs+=("$version:$path") + done + # unset for loop variables + unset version path + fi + + # add SDKMAN! java versions (#95) + if [ -d ~/.sdkman/candidates/java/ ] ; then + for sdkjdk in ~/.sdkman/candidates/java/*/ + do + if [[ ${sdkjdk} =~ /current/$ ]] ; then + continue + fi + + sdkjdkcmd="${sdkjdk}bin/java" + version=$(get_java_version_from_cmd "${sdkjdkcmd}") + allJVMs+=("$version:$sdkjdkcmd") + done + # unset for loop variables + unset version + fi # add Apple JRE if available if [ -x "${apple_jre_plugin}" ] ; then @@ -571,6 +679,9 @@ if [ -z "${JAVACMD}" ] || [ ! -x "${JAVACMD}" ] ; then # determine JVMs matching the min/max version requirement + + stub_logger "[JavaSearch] Filtering the result list for JVMs matching the min/max version requirement ..." + minC=$(get_comparable_java_version ${JVMVersion}) maxC=$(get_comparable_java_version ${JVMMaxVersion}) matchingJVMs=() @@ -655,7 +766,7 @@ if [ -z "${JAVACMD}" ] || [ ! -x "${JAVACMD}" ] ; then # debug output for i in "${matchingJVMs[@]}" do - stub_logger "[JavaSearch] ... ... matches all requirements: $i" + stub_logger "[JavaSearch] ... matches all requirements: $i" done @@ -692,7 +803,13 @@ fi stub_logger "[JavaCommand] '$JAVACMD'" stub_logger "[JavaVersion] $(get_java_version_from_cmd "${JAVACMD}")${JAVACMD_version:+ / $JAVACMD_version}" +# Make sure tabbing mode is disabled for the selected java version + +CFBundleIdentifier=net.java.openjdk.$(get_java_version_from_cmd "${JAVACMD}").java +if [ x$(defaults read ${CFBundleIdentifier} AppleWindowTabbingMode) != "xnever" ]; then + defaults write ${CFBundleIdentifier} AppleWindowTabbingMode never +fi if [ -z "${JAVACMD}" ] || [ ! -x "${JAVACMD}" ] ; then @@ -712,9 +829,10 @@ if [ -z "${JAVACMD}" ] || [ ! -x "${JAVACMD}" ] ; then stub_logger "[EXIT 3] ${MSG_NO_SUITABLE_JAVA_EXPANDED}" # display error message with AppleScript - osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_NO_SUITABLE_JAVA_EXPANDED}\n${MSG_NO_SUITABLE_JAVA_CHECK}\" with title \"${CFBundleName}\" buttons {\" OK \", \"${MSG_VISIT_JAVA_DOT_COM}\"} default button \"${MSG_VISIT_JAVA_DOT_COM}\" with icon path to resource \"${CFBundleIconFile}\" in bundle (path to me)" \ + osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_NO_SUITABLE_JAVA_EXPANDED}\n${MSG_NO_SUITABLE_JAVA_CHECK}\" with title \"${CFBundleName}\" buttons {\" OK \", \"${MSG_VISIT_JAVA_DOT_COM}\", \"${MSG_VISIT_ADOPTOPENJDK}\"} default button 1${DialogWithIcon}" \ -e "set response to button returned of the result" \ - -e "if response is \"${MSG_VISIT_JAVA_DOT_COM}\" then open location \"http://java.com\"" + -e "if response is \"${MSG_VISIT_JAVA_DOT_COM}\" then open location \"https://www.java.com/download/\"" \ + -e "if response is \"${MSG_VISIT_ADOPTOPENJDK}\" then open location \"https://adoptopenjdk.net/releases.html\"" # exit with error exit 3 @@ -722,9 +840,10 @@ if [ -z "${JAVACMD}" ] || [ ! -x "${JAVACMD}" ] ; then # log exit cause stub_logger "[EXIT 1] ${MSG_ERROR_LAUNCHING}" # display error message with AppleScript - osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_INSTALL_JAVA}\" with title \"${CFBundleName}\" buttons {\"${MSG_LATER}\", \"${MSG_VISIT_JAVA_DOT_COM}\"} default button \"${MSG_VISIT_JAVA_DOT_COM}\" with icon path to resource \"${CFBundleIconFile}\" in bundle (path to me)" \ + osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_INSTALL_JAVA}\" with title \"${CFBundleName}\" buttons {\"${MSG_LATER}\", \"${MSG_VISIT_JAVA_DOT_COM}\", \"${MSG_VISIT_ADOPTOPENJDK}\"} default button 1${DialogWithIcon}" \ -e "set response to button returned of the result" \ - -e "if response is \"${MSG_VISIT_JAVA_DOT_COM}\" then open location \"http://java.com\"" + -e "if response is \"${MSG_VISIT_JAVA_DOT_COM}\" then open location \"https://www.java.com/download/\"" \ + -e "if response is \"${MSG_VISIT_ADOPTOPENJDK}\" then open location \"https://adoptopenjdk.net/releases.html\"" # exit with error exit 1 fi @@ -739,7 +858,7 @@ if [ -z "${JVMMainClass}" ]; then # log exit cause stub_logger "[EXIT 2] ${MSG_MISSING_MAINCLASS}" # display error message with AppleScript - osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_MISSING_MAINCLASS}\" with title \"${CFBundleName}\" buttons {\" OK \"} default button 1 with icon path to resource \"${CFBundleIconFile}\" in bundle (path to me)" + osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_MISSING_MAINCLASS}\" with title \"${CFBundleName}\" buttons {\" OK \"} default button 1${DialogWithIcon}" # exit with error exit 2 fi @@ -773,11 +892,11 @@ stub_logger "[WorkingDirectory] ${WorkingDirectory}" # - main class # - main class arguments # - passthrough arguments from Terminal or Drag'n'Drop to Finder icon -stub_logger "[Exec] \"$JAVACMD\" -cp \"${JVMClassPath}\" -splash:\"${ResourcesFolder}/${JVMSplashFile}\" -Xdock:icon=\"${ResourcesFolder}/${CFBundleIconFile}\" -Xdock:name=\"${CFBundleName}\" ${JVMOptionsArr:+$(printf "'%s' " "${JVMOptionsArr[@]}") }${JVMDefaultOptions:+$JVMDefaultOptions }${JVMMainClass}${MainArgsArr:+ $(printf "'%s' " "${MainArgsArr[@]}")}${ArgsPassthru:+ $(printf "'%s' " "${ArgsPassthru[@]}")}" +stub_logger "[Exec] \"$JAVACMD\" -cp \"${JVMClassPath}\" ${JVMSplashFile:+ -splash:\"${ResourcesFolder}/${JVMSplashFile}\"} -Xdock:icon=\"${ResourcesFolder}/${CFBundleIconFile}\" -Xdock:name=\"${CFBundleName}\" ${JVMOptionsArr:+$(printf "'%s' " "${JVMOptionsArr[@]}") }${JVMDefaultOptions:+$JVMDefaultOptions }${JVMMainClass}${MainArgsArr:+ $(printf "'%s' " "${MainArgsArr[@]}")}${ArgsPassthru:+ $(printf "'%s' " "${ArgsPassthru[@]}")}" exec "${JAVACMD}" \ -Djava.library.path="${AppleJavaFolder}" \ -cp "${JVMClassPath}" \ - -splash:"${ResourcesFolder}/${JVMSplashFile}" \ + ${JVMSplashFile:+ -splash:"${ResourcesFolder}/${JVMSplashFile}"} \ -Xdock:icon="${ResourcesFolder}/${CFBundleIconFile}" \ -Xdock:name="${CFBundleName}" \ ${JVMOptionsArr:+"${JVMOptionsArr[@]}" }\ diff --git a/micropeak/MicroPeak.java b/micropeak/MicroPeak.java index 7d3e20d8..c34e874a 100644 --- a/micropeak/MicroPeak.java +++ b/micropeak/MicroPeak.java @@ -61,6 +61,10 @@ public class MicroPeak extends MicroFrame implements ActionListener, ItemListene final static String download_command = "download"; final static String download_label = "Download"; + static final String[][] download_menu_entries = new String[][] { + { download_label, download_command } + }; + MicroPeak SetData(MicroData data) { MicroPeak mp = this; if (this.data != null) { @@ -255,7 +259,7 @@ public class MicroPeak extends MicroFrame implements ActionListener, ItemListene } - private JMenu make_menu(String label, String[][] items) { + private void make_menu(String label, String[][] items) { JMenu menu = new JMenu(label); for (int i = 0; i < items.length; i++) { if (MAC_OS_X) { @@ -267,7 +271,6 @@ public class MicroPeak extends MicroFrame implements ActionListener, ItemListene add_menu(menu, items[i][0], items[i][1]); } menu_bar.add(menu); - return menu; } public MicroPeak() { @@ -286,12 +289,16 @@ public class MicroPeak extends MicroFrame implements ActionListener, ItemListene menu_bar = new JMenuBar(); setJMenuBar(menu_bar); - JMenu file_menu = make_menu("File", file_menu_entries); + make_menu("File", file_menu_entries); - JButton download_button = new JButton (download_label); - download_button.setActionCommand(download_command); - download_button.addActionListener(this); - menu_bar.add(download_button); + if (MAC_OS_X) { + make_menu(download_label, download_menu_entries); + } else { + JButton download_button = new JButton (download_label); + download_button.setActionCommand(download_command); + download_button.addActionListener(this); + menu_bar.add(download_button); + } setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); addWindowListener(new WindowAdapter() { @@ -320,6 +327,11 @@ public class MicroPeak extends MicroFrame implements ActionListener, ItemListene container.validate(); doLayout(); validate(); + Insets i = getInsets(); + Dimension ps = pane.getPreferredSize(); + ps.width += i.left + i.right; + ps.height += i.top + i.bottom; + setSize(ps); pack(); setVisible(true); } diff --git a/src/Makefile b/src/Makefile index 3443ec8a..0b6a7e27 100644 --- a/src/Makefile +++ b/src/Makefile @@ -19,6 +19,7 @@ include Makedefs ARMM3DIRS=\ easymega-v1.0 easymega-v1.0/flash-loader \ easymega-v2.0 easymega-v2.0/flash-loader \ + easymotor-v2 easymotor-v2/flash-loader \ easytimer-v1 easytimer-v1/flash-loader \ telemega-v0.1 telemega-v0.1/flash-loader \ telemega-v1.0 telemega-v1.0/flash-loader \ diff --git a/src/easymotor-v2/ao_pins.h b/src/easymotor-v2/ao_pins.h index 1d970e19..097ecb45 100644 --- a/src/easymotor-v2/ao_pins.h +++ b/src/easymotor-v2/ao_pins.h @@ -53,7 +53,7 @@ #define SERIAL_3_PC10_PC11 0 #define SERIAL_3_PD8_PD9 0 -#define AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX (512 * 1024) +#define AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX (1984 * 1024) #define AO_CONFIG_MAX_SIZE 1024 #define LOG_ERASE_MARK 0x55 #define LOG_MAX_ERASE 128 diff --git a/src/easytimer-v1/ao_easytimer.c b/src/easytimer-v1/ao_easytimer.c index 8224ee06..55dd4db0 100644 --- a/src/easytimer-v1/ao_easytimer.c +++ b/src/easytimer-v1/ao_easytimer.c @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/kernel/ao_config.c b/src/kernel/ao_config.c index 24eb79d9..bfc0325e 100644 --- a/src/kernel/ao_config.c +++ b/src/kernel/ao_config.c @@ -190,7 +190,7 @@ _ao_config_get(void) if (minor < 14) ao_config.radio_amp = AO_CONFIG_DEFAULT_RADIO_AMP; #endif -#if HAS_GYRO +#if HAS_IMU if (minor < 15) { ao_config.accel_zero_along = 0; ao_config.accel_zero_across = 0; @@ -395,7 +395,7 @@ ao_config_accel_calibrate_show(void) { printf("Accel cal +1g: %d -1g: %d\n", ao_config.accel_plus_g, ao_config.accel_minus_g); -#if HAS_GYRO +#if HAS_IMU printf ("IMU cal along %d across %d through %d\n", ao_config.accel_zero_along, ao_config.accel_zero_across, @@ -406,7 +406,7 @@ ao_config_accel_calibrate_show(void) #define ACCEL_CALIBRATE_SAMPLES 1024 #define ACCEL_CALIBRATE_SHIFT 10 -#if HAS_GYRO +#if HAS_IMU static int16_t accel_cal_along; static int16_t accel_cal_across; static int16_t accel_cal_through; @@ -418,7 +418,7 @@ ao_config_accel_calibrate_auto(char *orientation) uint16_t i; int32_t accel_total; uint8_t cal_data_ring; -#if HAS_GYRO +#if HAS_IMU int32_t accel_along_total = 0; int32_t accel_across_total = 0; int32_t accel_through_total = 0; @@ -436,7 +436,7 @@ ao_config_accel_calibrate_auto(char *orientation) ao_sleep(&ao_sample_data); while (i && cal_data_ring != ao_sample_data) { accel_total += (int32_t) ao_data_accel(&ao_data_ring[cal_data_ring]); -#if HAS_GYRO +#if HAS_IMU accel_along_total += (int32_t) ao_data_along(&ao_data_ring[cal_data_ring]); accel_across_total += (int32_t) ao_data_across(&ao_data_ring[cal_data_ring]); accel_through_total += (int32_t) ao_data_through(&ao_data_ring[cal_data_ring]); @@ -445,7 +445,7 @@ ao_config_accel_calibrate_auto(char *orientation) i--; } } -#if HAS_GYRO +#if HAS_IMU accel_cal_along = accel_along_total >> ACCEL_CALIBRATE_SHIFT; accel_cal_across = accel_across_total >> ACCEL_CALIBRATE_SHIFT; accel_cal_through = accel_through_total >> ACCEL_CALIBRATE_SHIFT; @@ -457,35 +457,31 @@ static void ao_config_accel_calibrate_set(void) { int16_t up, down; - uint16_t r; -#if HAS_GYRO + bool auto_cal; +#if HAS_IMU int16_t accel_along_up = 0, accel_along_down = 0; int16_t accel_across_up = 0, accel_across_down = 0; int16_t accel_through_up = 0, accel_through_down = 0; #endif - r = ao_cmd_decimal(); + up = ao_cmd_decimal(); if (ao_cmd_status != ao_cmd_success) return; - if (r == 0) { + down = ao_cmd_decimal(); + auto_cal = (up == 0 && ao_cmd_status != ao_cmd_success); + if (auto_cal) { up = ao_config_accel_calibrate_auto("up"); -#if HAS_GYRO +#if HAS_IMU accel_along_up = accel_cal_along; accel_across_up = accel_cal_across; accel_through_up = accel_cal_through; #endif down = ao_config_accel_calibrate_auto("down"); -#if HAS_GYRO +#if HAS_IMU accel_along_down = accel_cal_along; accel_across_down = accel_cal_across; accel_through_down = accel_cal_through; #endif - } else { - up = r; - r = ao_cmd_decimal(); - if (ao_cmd_status != ao_cmd_success) - return; - down = r; } if (up >= down) { printf("Invalid accel: up (%d) down (%d)\n", @@ -495,11 +491,25 @@ ao_config_accel_calibrate_set(void) _ao_config_edit_start(); ao_config.accel_plus_g = up; ao_config.accel_minus_g = down; -#if HAS_GYRO - if (r == 0) { +#if HAS_IMU + if (auto_cal) { ao_config.accel_zero_along = (accel_along_up + accel_along_down) / 2; ao_config.accel_zero_across = (accel_across_up + accel_across_down) / 2; ao_config.accel_zero_through = (accel_through_up + accel_through_down) / 2; + } else { + int16_t v; + + v = ao_cmd_decimal(); + if (ao_cmd_status == ao_cmd_success) { + ao_config.accel_zero_along = v; + v = ao_cmd_decimal(); + if (ao_cmd_status == ao_cmd_success) { + ao_config.accel_zero_across = v; + v = ao_cmd_decimal(); + if (ao_cmd_status == ao_cmd_success) + ao_config.accel_zero_through = v; + } + } } #endif _ao_config_edit_finish(); diff --git a/src/kernel/ao_config.h b/src/kernel/ao_config.h index 3cfd0d07..8a367733 100644 --- a/src/kernel/ao_config.h +++ b/src/kernel/ao_config.h @@ -92,7 +92,7 @@ struct ao_config { #if HAS_RADIO_AMP uint8_t radio_amp; /* minor version 14 */ #endif -#if HAS_GYRO +#if HAS_IMU int16_t accel_zero_along; /* minor version 15 */ int16_t accel_zero_across; /* minor version 15 */ int16_t accel_zero_through; /* minor version 15 */ diff --git a/src/kernel/ao_ignite.c b/src/kernel/ao_ignite.c index e4e4843e..d197239a 100644 --- a/src/kernel/ao_ignite.c +++ b/src/kernel/ao_ignite.c @@ -75,7 +75,7 @@ ao_igniter_status(enum ao_igniter igniter) #endif static void -ao_igniter_fire(enum ao_igniter igniter) +ao_igniter_fire(enum ao_igniter igniter, bool wait) { if (!ao_ignition[igniter].fired) { ao_ignition[igniter].firing = 1; @@ -93,7 +93,8 @@ ao_igniter_fire(enum ao_igniter igniter) break; } ao_ignition[igniter].firing = 0; - ao_delay(AO_IGNITER_CHARGE_TIME); + if (wait) + ao_delay(AO_IGNITER_CHARGE_TIME); } } @@ -111,27 +112,27 @@ ao_igniter(void) switch(ao_config.ignite_mode) { case AO_IGNITE_MODE_DUAL: if (ao_flight_drogue <= ao_flight_state && ao_flight_state < ao_flight_landed) - ao_igniter_fire(ao_igniter_drogue); + ao_igniter_fire(ao_igniter_drogue, true); if (ao_flight_main <= ao_flight_state && ao_flight_state < ao_flight_landed) - ao_igniter_fire(ao_igniter_main); + ao_igniter_fire(ao_igniter_main, true); break; case AO_IGNITE_MODE_APOGEE: if (ao_flight_drogue <= ao_flight_state && ao_flight_state < ao_flight_landed) { - ao_igniter_fire(ao_igniter_drogue); - ao_igniter_fire(ao_igniter_main); + ao_igniter_fire(ao_igniter_drogue, true); + ao_igniter_fire(ao_igniter_main, true); } break; case AO_IGNITE_MODE_MAIN: if (ao_flight_main <= ao_flight_state && ao_flight_state < ao_flight_landed) { - ao_igniter_fire(ao_igniter_drogue); - ao_igniter_fire(ao_igniter_main); + ao_igniter_fire(ao_igniter_drogue, true); + ao_igniter_fire(ao_igniter_main, true); } break; case AO_IGNITE_MODE_BOOSTER: if (ao_flight_fast <= ao_flight_state && ao_flight_state < ao_flight_landed) - ao_igniter_fire(ao_igniter_main); + ao_igniter_fire(ao_igniter_main, true); if (ao_flight_drogue <= ao_flight_state && ao_flight_state < ao_flight_landed) - ao_igniter_fire(ao_igniter_drogue); + ao_igniter_fire(ao_igniter_drogue, true); break; } } @@ -149,12 +150,12 @@ ao_ignite_manual(void) #if HAS_IGNITE if (ao_cmd_lex_c == 'm' && ao_match_word("main")) { ao_ignition[ao_igniter_main].fired = 0; - ao_igniter_fire(ao_igniter_main); + ao_igniter_fire(ao_igniter_main, false); return; } if (ao_cmd_lex_c == 'd' && ao_match_word("drogue")) { ao_ignition[ao_igniter_drogue].fired = 0; - ao_igniter_fire(ao_igniter_drogue); + ao_igniter_fire(ao_igniter_drogue, false); return; } #endif diff --git a/src/kernel/ao_log.c b/src/kernel/ao_log.c index f0816aee..2167d145 100644 --- a/src/kernel/ao_log.c +++ b/src/kernel/ao_log.c @@ -292,28 +292,28 @@ ao_log_scan(void) ao_log_end_pos = ao_log_pos_block_end(0); if (ao_flight_number) { - uint32_t full = ao_log_current_pos; - uint32_t empty = ao_log_end_pos - AO_LOG_SIZE; + uint32_t full = (ao_log_current_pos) / AO_LOG_SIZE; + uint32_t empty = (ao_log_end_pos - AO_LOG_SIZE) / AO_LOG_SIZE; /* If there's already a flight started, then find the * end of it */ for (;;) { - ao_log_current_pos = (full + empty) >> 1; - ao_log_current_pos -= ao_log_current_pos % AO_LOG_SIZE; + uint32_t current = (full + empty) >> 1; + ao_log_current_pos = current * AO_LOG_SIZE; - if (ao_log_current_pos == full) { + if (current == full) { if (ao_log_check(ao_log_current_pos) != AO_LOG_EMPTY) ao_log_current_pos += AO_LOG_SIZE; break; } - if (ao_log_current_pos == empty) + if (current == empty) break; if (ao_log_check(ao_log_current_pos) != AO_LOG_EMPTY) { - full = ao_log_current_pos; + full = current; } else { - empty = ao_log_current_pos; + empty = current; } } ret = 1; diff --git a/src/kernel/ao_log_gps.c b/src/kernel/ao_log_gps.c index bf326c1a..2b45f35e 100644 --- a/src/kernel/ao_log_gps.c +++ b/src/kernel/ao_log_gps.c @@ -81,18 +81,31 @@ ao_log_gps_tracking(uint16_t tick, struct ao_telemetry_satellite *gps_tracking_d ao_log_write(&ao_log_data); } +static uint8_t +ao_log_check_empty(void) +{ + uint8_t *b = (void *) &ao_log_data; + unsigned i; + + for (i = 0; i < sizeof (ao_log_type); i++) + if (*b++ != AO_STORAGE_ERASED_BYTE) + return 0; + return 1; +} + int8_t ao_log_check(uint32_t pos) { - if (ao_storage_is_erased(pos & ~(ao_storage_block - 1))) - return 0; - if (!ao_storage_read(pos, &ao_log_data, sizeof (struct ao_log_gps))) return AO_LOG_INVALID; + if (ao_log_check_empty()) + return AO_LOG_EMPTY; + if (!ao_log_check_data()) return AO_LOG_INVALID; + return AO_LOG_VALID; } diff --git a/src/kernel/ao_storage.c b/src/kernel/ao_storage.c index 213ec2d6..43abc43c 100644 --- a/src/kernel/ao_storage.c +++ b/src/kernel/ao_storage.c @@ -86,10 +86,6 @@ ao_storage_write(ao_pos_t pos, void *v_buf, uint16_t len) return 1; } -#ifndef AO_STORAGE_ERASED_BYTE -#define AO_STORAGE_ERASED_BYTE 0xff -#endif - uint8_t ao_storage_is_erased(uint32_t pos) { diff --git a/src/kernel/ao_storage.h b/src/kernel/ao_storage.h index 026074b5..ff8548eb 100644 --- a/src/kernel/ao_storage.h +++ b/src/kernel/ao_storage.h @@ -44,6 +44,10 @@ extern ao_pos_t ao_storage_block; #define USE_STORAGE_CONFIG 1 #endif +#ifndef AO_STORAGE_ERASED_BYTE +#define AO_STORAGE_ERASED_BYTE 0xff +#endif + #if USE_STORAGE_CONFIG /* Byte offset of config block. Will be ao_storage_block bytes long */ extern ao_pos_t ao_storage_config; diff --git a/src/microtest/Makefile b/src/microtest/Makefile new file mode 100644 index 00000000..04c31b02 --- /dev/null +++ b/src/microtest/Makefile @@ -0,0 +1,81 @@ +# +# Tiny AltOS build +# +# +TOPDIR=.. +include $(TOPDIR)/attiny/Makefile.defs + +PROGNAME=microtest-v1.0 +PROG=$(PROGNAME)-$(VERSION).elf +HEX=$(PROGNAME)-$(VERSION).ihx + +ALTOS_SRC = \ + ao_microtest.c \ + ao_spi_attiny.c \ + ao_led_tiny.c \ + ao_clock.c \ + ao_ms5607.c \ + ao_exti.c \ + ao_notask.c \ + ao_eeprom_tiny.c \ + ao_panic.c \ + ao_log_micro.c \ + ao_async.c \ + ao_microflight.c \ + ao_microkalman.c + +INC=\ + ao.h \ + ao_pins.h \ + ao_arch.h \ + ao_arch_funcs.h \ + ao_exti.h \ + ao_ms5607.h \ + ao_log_micro.h \ + ao_micropeak.h \ + ao_product.h \ + altitude-pa.h + +IDPRODUCT=0 +PRODUCT=MicroTest-v1.0 +PRODUCT_DEF=-DMICROPEAK +CFLAGS = $(PRODUCT_DEF) $(ATTINY_CFLAGS) + +SRC=$(ALTOS_SRC) +OBJ=$(SRC:.c=.o) + +all: $(PROG) $(HEX) + +CHECK=sh ../util/check-avr-mem + +$(PROG): Makefile $(OBJ) + $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) + $(call quiet,CHECK) $(PROG) || ($(RM) -f $(PROG); exit 1) + +$(HEX): $(PROG) + avr-size $(PROG) + $(OBJCOPY) -R .eeprom -O ihex $(PROG) $@ + +load: $(HEX) + $(LOADCMD) $(LOADARG)$(HEX) + +load-slow: $(HEX) + $(LOADCMD) $(LOADSLOW) $(LOADARG)$(HEX) + +distclean: clean + +clean: + rm -f *.o *.elf *.ihx *.map + rm -f ao_product.h + +load-product: + ./$(SCRIPT) fast + +load-product-slow: + ./$(SCRIPT) slow + +install: + +uninstall: + +$(OBJ): $(INC) diff --git a/src/microtest/ao_microtest.c b/src/microtest/ao_microtest.c new file mode 100644 index 00000000..168220c4 --- /dev/null +++ b/src/microtest/ao_microtest.c @@ -0,0 +1,147 @@ +/* + * Copyright © 2012 Keith Packard + * + * This program is free software; 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 +#include +#include +#include +#include + +static struct ao_ms5607_value value; + +alt_t ground_alt, max_alt; +alt_t ao_max_height; + +void +ao_pa_get(void) +{ + ao_ms5607_sample(&ao_ms5607_current); + ao_ms5607_convert(&ao_ms5607_current, &value); + pa = value.pres; +} +static void +ao_pips(void) +{ + uint8_t i; + for (i = 0; i < 10; i++) { + ao_led_toggle(AO_LED_REPORT); + ao_delay(AO_MS_TO_TICKS(80)); + } + ao_delay(AO_MS_TO_TICKS(200)); +} + +#define POLY 0x8408 + +static uint16_t +ao_log_micro_crc(uint16_t crc, uint8_t byte) +{ + uint8_t i; + + for (i = 0; i < 8; i++) { + if ((crc & 0x0001) ^ (byte & 0x0001)) + crc = (crc >> 1) ^ POLY; + else + crc = crc >> 1; + byte >>= 1; + } + return crc; +} + +struct header { + uint32_t pa_ground_offset; + uint32_t pa_min_offset; + N_SAMPLES_TYPE nsamples; +}; + +static const struct header head = { + .pa_ground_offset = 0xfffefdfc, + .pa_min_offset = 0xfbfaf9f8, + .nsamples = 64 +}; + +static void +ao_test_micro_dump(void) +{ + N_SAMPLES_TYPE n_samples; + uint16_t nbytes; + uint8_t byte; + uint16_t b; + uint16_t crc = 0xffff; + + n_samples = head.nsamples; + nbytes = STARTING_LOG_OFFSET + sizeof (uint16_t) * n_samples; + + /* + * Rewrite n_samples so that it includes the log ID value with + * 32-bit n_samples split into two chunks + */ + if (sizeof (n_samples) > 2) { + N_SAMPLES_TYPE n_samples_low; + N_SAMPLES_TYPE n_samples_high; + n_samples_low = n_samples & ((1 << AO_LOG_ID_SHIFT) - 1); + n_samples_high = (n_samples - n_samples_low) << AO_LOG_ID_WIDTH; + n_samples = n_samples_low | n_samples_high; + } +#if AO_LOG_ID + n_samples |= AO_LOG_ID << AO_LOG_ID_SHIFT; +#endif + ao_async_start(); + ao_async_byte('M'); + ao_async_byte('P'); + for (b = 0; b < nbytes; b++) { + if ((b & 0xf) == 0) + ao_log_newline(); + if (b < sizeof (head)) + byte = ((uint8_t *) &head)[b]; + else + byte = b; +#if AO_LOG_ID + if (N_SAMPLES_OFFSET <= b && b < (N_SAMPLES_OFFSET + sizeof(n_samples))) { + byte = n_samples >> ((b - N_SAMPLES_OFFSET) << 3); + } +#endif + ao_log_hex(byte); + crc = ao_log_micro_crc(crc, byte); + } + ao_log_newline(); + crc = ~crc; + ao_log_hex(crc >> 8); + ao_log_hex(crc); + ao_log_newline(); + ao_async_stop(); +} + +int +main(void) +{ + ao_led_init(); + ao_timer_init(); + + /* Init external hardware */ + ao_spi_init(); + ao_ms5607_init(); + ao_ms5607_setup(); + + for (;;) + { + ao_delay(AO_MS_TO_TICKS(1000)); + + ao_pips(); + ao_test_micro_dump(); + } +} diff --git a/src/microtest/ao_pins.h b/src/microtest/ao_pins.h new file mode 100644 index 00000000..2c02f3a3 --- /dev/null +++ b/src/microtest/ao_pins.h @@ -0,0 +1,67 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; 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_ +#include + +#define AO_LED_ORANGE (1<<4) +#define AO_LED_SERIAL 4 +#define AO_LED_PANIC AO_LED_ORANGE +#define AO_LED_REPORT AO_LED_ORANGE +#define LEDS_AVAILABLE (AO_LED_ORANGE) +#define USE_SERIAL_1_STDIN 0 +#define HAS_USB 0 +#define PACKET_HAS_SLAVE 0 +#define HAS_SERIAL_1 0 +#define HAS_TASK 0 +#define HAS_MS5607 1 +#define HAS_MS5611 0 +#define HAS_SENSOR_ERRORS 0 +#define HAS_EEPROM 0 +#define HAS_BEEP 0 +#define AVR_CLOCK 250000UL + +/* SPI */ +#define SPI_PORT PORTB +#define SPI_PIN PINB +#define SPI_DIR DDRB +#define AO_MS5607_CS_PORT PORTB +#define AO_MS5607_CS_PIN 3 + +/* MS5607 */ +#define AO_MS5607_SPI_INDEX 0 +#define AO_MS5607_MISO_PORT PORTB +#define AO_MS5607_MISO_PIN 0 +#define AO_MS5607_BARO_OVERSAMPLE 4096 +#define AO_MS5607_TEMP_OVERSAMPLE 1024 + +/* I2C */ +#define I2C_PORT PORTB +#define I2C_PIN PINB +#define I2C_DIR DDRB +#define I2C_PIN_SCL PINB2 +#define I2C_PIN_SDA PINB0 + +#define AO_CONST_ATTRIB PROGMEM +typedef int32_t alt_t; +#define FETCH_ALT(o) ((alt_t) pgm_read_dword(&altitude_table[o])) + +#define AO_ALT_VALUE(x) ((x) * (alt_t) 10) + +#endif /* _AO_PINS_H_ */ diff --git a/telegps/TeleGPS.app/Contents/MacOS/JavaApplicationStub b/telegps/TeleGPS.app/Contents/MacOS/JavaApplicationStub index 145a260b..aa96638f 100755 --- a/telegps/TeleGPS.app/Contents/MacOS/JavaApplicationStub +++ b/telegps/TeleGPS.app/Contents/MacOS/JavaApplicationStub @@ -1,16 +1,4 @@ #!/bin/bash -# -# Fix fonts. I don't know why the getting the -# basename of the app set to . matters, but it does -# -case "$0" in - /*) - cd `dirname "$0"` - ./`basename "$0"` "$@" - exit $? - ;; -esac -export FREETYPE_PROPERTIES=truetype:interpreter-version=35 ################################################################################## # # # universalJavaApplicationStub # @@ -23,14 +11,14 @@ export FREETYPE_PROPERTIES=truetype:interpreter-version=35 # # # @author Tobias Fischer # # @url https://github.com/tofi86/universalJavaApplicationStub # -# @date 2018-08-24 # -# @version 3.0.4 # +# @date 2021-02-21 # +# @version 3.2.0 # # # ################################################################################## # # # The MIT License (MIT) # # # -# Copyright (c) 2014-2018 Tobias Fischer # +# Copyright (c) 2014-2021 Tobias Fischer # # # # Permission is hereby granted, free of charge, to any person obtaining a copy # # of this software and associated documentation files (the "Software"), to deal # @@ -52,7 +40,18 @@ export FREETYPE_PROPERTIES=truetype:interpreter-version=35 # # ################################################################################## - +# +# Fix fonts. I don't know why the getting the +# basename of the app set to . matters, but it does +# +case "$0" in + /*) + cd `dirname "$0"` + ./`basename "$0"` "$@" + exit $? + ;; +esac +export FREETYPE_PROPERTIES=truetype:interpreter-version=35 # function 'stub_logger()' # @@ -178,6 +177,8 @@ if [ $exitcode -eq 0 ]; then JavaFolder="${AppleJavaFolder}" ResourcesFolder="${AppleResourcesFolder}" + # set expandable variables + APP_ROOT="${AppPackageFolder}" APP_PACKAGE="${AppPackageFolder}" JAVAROOT="${AppleJavaFolder}" USER_HOME="$HOME" @@ -192,7 +193,7 @@ if [ $exitcode -eq 0 ]; then # AppPackageRoot is the standard WorkingDirectory when the script is started WorkingDirectory="${AppPackageRoot}" fi - # expand variables $APP_PACKAGE, $JAVAROOT, $USER_HOME + # expand variables $APP_PACKAGE, $APP_ROOT, $JAVAROOT, $USER_HOME WorkingDirectory=$(eval echo "${WorkingDirectory}") @@ -215,7 +216,7 @@ if [ $exitcode -eq 0 ]; then else JVMClassPath=${JVMClassPath_RAW} fi - # expand variables $APP_PACKAGE, $JAVAROOT, $USER_HOME + # expand variables $APP_PACKAGE, $APP_ROOT, $JAVAROOT, $USER_HOME JVMClassPath=$(eval echo "${JVMClassPath}") # read the JVM Options in either Array or String style @@ -225,6 +226,8 @@ if [ $exitcode -eq 0 ]; then else JVMDefaultOptions=${JVMDefaultOptions_RAW} fi + # expand variables $APP_PACKAGE, $APP_ROOT, $JAVAROOT, $USER_HOME (#84) + JVMDefaultOptions=$(eval echo "${JVMDefaultOptions}") # read StartOnMainThread and add as -XstartOnFirstThread JVMStartOnMainThread=$(plist_get_java ':StartOnMainThread') @@ -232,9 +235,14 @@ if [ $exitcode -eq 0 ]; then JVMDefaultOptions+=" -XstartOnFirstThread" fi - # read the JVM Arguments as an array and retain spaces + # read the JVM Arguments in either Array or String style (#76) and retain spaces IFS=$'\t\n' - MainArgs=($(xargs -n1 <<<$(plist_get_java ':Arguments'))) + MainArgs_RAW=$(plist_get_java ':Arguments' | xargs) + if [[ $MainArgs_RAW == *Array* ]] ; then + MainArgs=($(xargs -n1 <<<$(plist_get_java ':Arguments' | tr -d '\n' | sed -E 's/Array \{ *(.*) *\}/\1/g' | sed 's/ */ /g'))) + else + MainArgs=($(xargs -n1 <<<$(plist_get_java ':Arguments'))) + fi unset IFS # post processing of the array follows further below... @@ -252,7 +260,11 @@ else ResourcesFolder="${OracleResourcesFolder}" WorkingDirectory="${OracleJavaFolder}" + # set expandable variables APP_ROOT="${AppPackageFolder}" + APP_PACKAGE="${AppPackageFolder}" + JAVAROOT="${OracleJavaFolder}" + USER_HOME="$HOME" # read the MainClass name JVMMainClass="$(plist_get ':JVMMainClassName')" @@ -270,12 +282,12 @@ else JVMClassPath_RAW=$(plist_get ':JVMClassPath') if [[ $JVMClassPath_RAW == *Array* ]] ; then JVMClassPath=.$(plist_get ':JVMClassPath' | grep " " | sed 's/^ */:/g' | tr -d '\n' | xargs) - # expand variables $APP_PACKAGE, $JAVAROOT, $USER_HOME + # expand variables $APP_PACKAGE, $APP_ROOT, $JAVAROOT, $USER_HOME JVMClassPath=$(eval echo "${JVMClassPath}") elif [[ ! -z ${JVMClassPath_RAW} ]] ; then JVMClassPath=${JVMClassPath_RAW} - # expand variables $APP_PACKAGE, $JAVAROOT, $USER_HOME + # expand variables $APP_PACKAGE, $APP_ROOT, $JAVAROOT, $USER_HOME JVMClassPath=$(eval echo "${JVMClassPath}") else @@ -284,8 +296,11 @@ else # Do NOT expand the default 'AppName.app/Contents/Java/*' classpath (#42) fi - # read the JVM Default Options + # read the JVM Default Options by parsing the :JVMDefaultOptions + # and pulling all values starting with a dash (-) JVMDefaultOptions=$(plist_get ':JVMDefaultOptions' | grep -o " \-.*" | tr -d '\n' | xargs) + # expand variables $APP_PACKAGE, $APP_ROOT, $JAVAROOT, $USER_HOME (#99) + JVMDefaultOptions=$(eval echo "${JVMDefaultOptions}") # read the Main Arguments from JVMArguments key as an array and retain spaces (see #46 for naming details) IFS=$'\t\n' @@ -299,6 +314,18 @@ else fi +# (#75) check for undefined icons or icon names without .icns extension and prepare +# an osascript statement for those cases when the icon can be shown in the dialog +DialogWithIcon="" +if [ ! -z ${CFBundleIconFile} ]; then + if [[ ${CFBundleIconFile} == *.icns ]] && [[ -f "${ResourcesFolder}/${CFBundleIconFile}" ]] ; then + DialogWithIcon=" with icon path to resource \"${CFBundleIconFile}\" in bundle (path to me)" + elif [[ ${CFBundleIconFile} != *.icns ]] && [[ -f "${ResourcesFolder}/${CFBundleIconFile}.icns" ]] ; then + CFBundleIconFile+=".icns" + DialogWithIcon=" with icon path to resource \"${CFBundleIconFile}\" in bundle (path to me)" + fi +fi + # JVMVersion: post processing and optional splitting if [[ ${JVMVersion} == *";"* ]]; then @@ -309,14 +336,14 @@ fi stub_logger "[JavaRequirement] JVM minimum version: ${JVMVersion}" stub_logger "[JavaRequirement] JVM maximum version: ${JVMMaxVersion}" -# MainArgs: replace occurences of $APP_ROOT with its content +# MainArgs: expand variables $APP_PACKAGE, $APP_ROOT, $JAVAROOT, $USER_HOME MainArgsArr=() for i in "${MainArgs[@]}" do MainArgsArr+=("$(eval echo "$i")") done -# JVMOptions: replace occurences of $APP_ROOT with its content +# JVMOptions: expand variables $APP_PACKAGE, $APP_ROOT, $JAVAROOT, $USER_HOME JVMOptionsArr=() for i in "${JVMOptions[@]}" do @@ -327,14 +354,37 @@ done # internationalized messages ############################################ -LANG=$(defaults read -g AppleLocale) -stub_logger "[Language] $LANG" +# supported languages / available translations +stubLanguages="^(fr|de|zh|es|en)-" + +# read user preferred languages as defined in macOS System Preferences (#101) +stub_logger '[LanguageSearch] Checking preferred languages in macOS System Preferences...' +appleLanguages=($(defaults read -g AppleLanguages | grep '\s"' | tr -d ',' | xargs)) +stub_logger "[LanguageSearch] ... found [${appleLanguages[*]}]" + +language="" +for i in "${appleLanguages[@]}" +do + langValue="${i%-*}" + if [[ "$i" =~ $stubLanguages ]]; then + stub_logger "[LanguageSearch] ... selected '$i' ('$langValue') as the default language for the launcher stub" + language=${langValue} + break + fi +done +if [ -z "${language}" ]; then + language="en" + stub_logger "[LanguageSearch] ... selected fallback 'en' as the default language for the launcher stub" +fi +stub_logger "[Language] $language" -# French localization -if [[ $LANG == fr* ]] ; then + +case "${language}" in +# French +fr) MSG_ERROR_LAUNCHING="ERREUR au lancement de '${CFBundleName}'." MSG_MISSING_MAINCLASS="'MainClass' n'est pas spécifié.\nL'application Java ne peut pas être lancée." - MSG_JVMVERSION_REQ_INVALID="La syntaxe de la version Java demandée est invalide: %s\nVeuillez contacter le développeur de l'application." + MSG_JVMVERSION_REQ_INVALID="La syntaxe de la version de Java demandée est invalide: %s\nVeuillez contacter le développeur de l'application." MSG_NO_SUITABLE_JAVA="La version de Java installée sur votre système ne convient pas.\nCe programme nécessite Java %s" MSG_JAVA_VERSION_OR_LATER="ou ultérieur" MSG_JAVA_VERSION_LATEST="(dernière mise à jour)" @@ -342,10 +392,12 @@ if [[ $LANG == fr* ]] ; then MSG_NO_SUITABLE_JAVA_CHECK="Merci de bien vouloir installer la version de Java requise." MSG_INSTALL_JAVA="Java doit être installé sur votre système.\nRendez-vous sur java.com et suivez les instructions d'installation..." MSG_LATER="Plus tard" - MSG_VISIT_JAVA_DOT_COM="Visiter java.com" + MSG_VISIT_JAVA_DOT_COM="Java by Oracle" + MSG_VISIT_ADOPTOPENJDK="Java by AdoptOpenJDK" + ;; -# German localization -elif [[ $LANG == de* ]] ; then +# German +de) MSG_ERROR_LAUNCHING="FEHLER beim Starten von '${CFBundleName}'." MSG_MISSING_MAINCLASS="Die 'MainClass' ist nicht spezifiziert!\nDie Java-Anwendung kann nicht gestartet werden!" MSG_JVMVERSION_REQ_INVALID="Die Syntax der angeforderten Java-Version ist ungültig: %s\nBitte kontaktieren Sie den Entwickler der App." @@ -356,10 +408,12 @@ elif [[ $LANG == de* ]] ; then MSG_NO_SUITABLE_JAVA_CHECK="Stellen Sie sicher, dass die angeforderte Java-Version installiert ist." MSG_INSTALL_JAVA="Auf Ihrem System muss die 'Java'-Software installiert sein.\nBesuchen Sie java.com für weitere Installationshinweise." MSG_LATER="Später" - MSG_VISIT_JAVA_DOT_COM="java.com öffnen" + MSG_VISIT_JAVA_DOT_COM="Java von Oracle" + MSG_VISIT_ADOPTOPENJDK="Java von AdoptOpenJDK" + ;; -# Simplifyed Chinese localization -elif [[ $LANG == zh* ]] ; then +# Simplified Chinese +zh) MSG_ERROR_LAUNCHING="无法启动 '${CFBundleName}'." MSG_MISSING_MAINCLASS="没有指定 'MainClass'!\nJava程序无法启动!" MSG_JVMVERSION_REQ_INVALID="Java版本参数语法错误: %s\n请联系该应用的开发者。" @@ -370,10 +424,28 @@ elif [[ $LANG == zh* ]] ; then MSG_NO_SUITABLE_JAVA_CHECK="请确保系统中安装了所需的Java版本" MSG_INSTALL_JAVA="你需要在Mac中安装Java运行环境!\n访问 java.com 了解如何安装。" MSG_LATER="稍后" - MSG_VISIT_JAVA_DOT_COM="访问 java.com" - -# English default localization -else + MSG_VISIT_JAVA_DOT_COM="Java by Oracle" + MSG_VISIT_ADOPTOPENJDK="Java by AdoptOpenJDK" + ;; + +# Spanish +es) + MSG_ERROR_LAUNCHING="ERROR iniciando '${CFBundleName}'." + MSG_MISSING_MAINCLASS="¡'MainClass' no especificada!\n¡La aplicación Java no puede iniciarse!" + MSG_JVMVERSION_REQ_INVALID="La sintaxis de la versión Java requerida no es válida: %s\nPor favor, contacte con el desarrollador de la aplicación." + MSG_NO_SUITABLE_JAVA="¡No se encontró una versión de Java adecuada en su sistema!\nEste programa requiere Java %s" + MSG_JAVA_VERSION_OR_LATER="o posterior" + MSG_JAVA_VERSION_LATEST="(ultima actualización)" + MSG_JAVA_VERSION_MAX="superior a %s" + MSG_NO_SUITABLE_JAVA_CHECK="Asegúrese de instalar la versión Java requerida." + MSG_INSTALL_JAVA="¡Necesita tener JAVA instalado en su Mac!\nVisite java.com para consultar las instrucciones para su instalación..." + MSG_LATER="Más tarde" + MSG_VISIT_JAVA_DOT_COM="Java de Oracle" + MSG_VISIT_ADOPTOPENJDK="Java de AdoptOpenJDK" + ;; + +# English | default +en|*) MSG_ERROR_LAUNCHING="ERROR launching '${CFBundleName}'." MSG_MISSING_MAINCLASS="'MainClass' isn't specified!\nJava application cannot be started!" MSG_JVMVERSION_REQ_INVALID="The syntax of the required Java version is invalid: %s\nPlease contact the App developer." @@ -384,8 +456,10 @@ else MSG_NO_SUITABLE_JAVA_CHECK="Make sure you install the required Java version." MSG_INSTALL_JAVA="You need to have JAVA installed on your Mac!\nVisit java.com for installation instructions..." MSG_LATER="Later" - MSG_VISIT_JAVA_DOT_COM="Visit java.com" -fi + MSG_VISIT_JAVA_DOT_COM="Java by Oracle" + MSG_VISIT_ADOPTOPENJDK="Java by AdoptOpenJDK" + ;; +esac @@ -468,7 +542,7 @@ function get_comparable_java_version() { ################################################################################ function is_valid_requirement_pattern() { local java_req=$1 - java8pattern='1\.[4-8](\.0)?(\.0_[0-9]+)?[*+]?' + java8pattern='1\.[4-8](\.[0-9]+)?(\.0_[0-9]+)?[*+]?' java9pattern='(9|1[0-9])(-ea|[*+]|(\.[0-9]+){1,2}[*+]?)?' # test matches either old Java versioning scheme (up to 1.8) or new scheme (starting with 9) if [[ ${java_req} =~ ^(${java8pattern}|${java9pattern})$ ]]; then @@ -501,20 +575,28 @@ if [ -n "$JAVA_HOME" ] ; then if [[ $JAVA_HOME == /* ]] ; then # if "$JAVA_HOME" starts with a Slash it's an absolute path JAVACMD="$JAVA_HOME/bin/java" + stub_logger "[JavaSearch] ... parsing JAVA_HOME as absolute path to the executable '$JAVACMD'" else # otherwise it's a relative path to "$AppPackageFolder" JAVACMD="$AppPackageFolder/$JAVA_HOME/bin/java" + stub_logger "[JavaSearch] ... parsing JAVA_HOME as relative path inside the App bundle to the executable '$JAVACMD'" fi JAVACMD_version=$(get_comparable_java_version $(get_java_version_from_cmd "${JAVACMD}")) else - stub_logger "[JavaSearch] ... didn't found JAVA_HOME" + stub_logger "[JavaSearch] ... haven't found JAVA_HOME" fi # check for any other or a specific Java version # also if $JAVA_HOME exists but isn't executable if [ -z "${JAVACMD}" ] || [ ! -x "${JAVACMD}" ] ; then - stub_logger "[JavaSearch] Checking for JavaVirtualMachines on the system ..." + + # add a warning in the syslog if JAVA_HOME is not executable or not found (#100) + if [ -n "$JAVA_HOME" ] ; then + stub_logger "[JavaSearch] ... but no 'java' executable was found at the JAVA_HOME location!" + fi + + stub_logger "[JavaSearch] Searching for JavaVirtualMachines on the system ..." # reset variables JAVACMD="" JAVACMD_version="" @@ -525,7 +607,7 @@ if [ -z "${JAVACMD}" ] || [ ! -x "${JAVACMD}" ] ; then # log exit cause stub_logger "[EXIT 4] ${MSG_JVMVERSION_REQ_INVALID_EXPANDED}" # display error message with AppleScript - osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_JVMVERSION_REQ_INVALID_EXPANDED}\" with title \"${CFBundleName}\" buttons {\" OK \"} default button 1 with icon path to resource \"${CFBundleIconFile}\" in bundle (path to me)" + osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_JVMVERSION_REQ_INVALID_EXPANDED}\" with title \"${CFBundleName}\" buttons {\" OK \"} default button 1${DialogWithIcon}" # exit with error exit 4 fi @@ -535,7 +617,7 @@ if [ -z "${JAVACMD}" ] || [ ! -x "${JAVACMD}" ] ; then # log exit cause stub_logger "[EXIT 5] ${MSG_JVMVERSION_REQ_INVALID_EXPANDED}" # display error message with AppleScript - osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_JVMVERSION_REQ_INVALID_EXPANDED}\" with title \"${CFBundleName}\" buttons {\" OK \"} default button 1 with icon path to resource \"${CFBundleIconFile}\" in bundle (path to me)" + osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_JVMVERSION_REQ_INVALID_EXPANDED}\" with title \"${CFBundleName}\" buttons {\" OK \"} default button 1${DialogWithIcon}" # exit with error exit 5 fi @@ -543,15 +625,41 @@ if [ -z "${JAVACMD}" ] || [ ! -x "${JAVACMD}" ] ; then # find installed JavaVirtualMachines (JDK + JRE) allJVMs=() - # read JDK's from '/usr/libexec/java_home -V' command - while read -r line; do - version=$(echo $line | awk -F $',' '{print $1;}') - path=$(echo $line | awk -F $'" ' '{print $2;}') - path+="/bin/java" - allJVMs+=("$version:$path") - done < <(/usr/libexec/java_home -V 2>&1 | grep '^[[:space:]]') - # unset while loop variables - unset version path + + # read JDK's from '/usr/libexec/java_home --xml' command with PlistBuddy and a custom Dict iterator + # idea: https://stackoverflow.com/a/14085460/1128689 and https://scriptingosx.com/2018/07/parsing-dscl-output-in-scripts/ + javaXml=$(/usr/libexec/java_home --xml) + javaCounter=$(/usr/libexec/PlistBuddy -c "Print" /dev/stdin <<< $javaXml | grep "Dict" | wc -l | tr -d ' ') + + # iterate over all Dict entries + # but only if there are any JVMs at all (#93) + if [ "$javaCounter" -gt "0" ] ; then + for idx in $(seq 0 $((javaCounter - 1))) + do + version=$(/usr/libexec/PlistBuddy -c "print :$idx:JVMVersion" /dev/stdin <<< $javaXml) + path=$(/usr/libexec/PlistBuddy -c "print :$idx:JVMHomePath" /dev/stdin <<< $javaXml) + path+="/bin/java" + allJVMs+=("$version:$path") + done + # unset for loop variables + unset version path + fi + + # add SDKMAN! java versions (#95) + if [ -d ~/.sdkman/candidates/java/ ] ; then + for sdkjdk in ~/.sdkman/candidates/java/*/ + do + if [[ ${sdkjdk} =~ /current/$ ]] ; then + continue + fi + + sdkjdkcmd="${sdkjdk}bin/java" + version=$(get_java_version_from_cmd "${sdkjdkcmd}") + allJVMs+=("$version:$sdkjdkcmd") + done + # unset for loop variables + unset version + fi # add Apple JRE if available if [ -x "${apple_jre_plugin}" ] ; then @@ -571,6 +679,9 @@ if [ -z "${JAVACMD}" ] || [ ! -x "${JAVACMD}" ] ; then # determine JVMs matching the min/max version requirement + + stub_logger "[JavaSearch] Filtering the result list for JVMs matching the min/max version requirement ..." + minC=$(get_comparable_java_version ${JVMVersion}) maxC=$(get_comparable_java_version ${JVMMaxVersion}) matchingJVMs=() @@ -655,7 +766,7 @@ if [ -z "${JAVACMD}" ] || [ ! -x "${JAVACMD}" ] ; then # debug output for i in "${matchingJVMs[@]}" do - stub_logger "[JavaSearch] ... ... matches all requirements: $i" + stub_logger "[JavaSearch] ... matches all requirements: $i" done @@ -692,7 +803,13 @@ fi stub_logger "[JavaCommand] '$JAVACMD'" stub_logger "[JavaVersion] $(get_java_version_from_cmd "${JAVACMD}")${JAVACMD_version:+ / $JAVACMD_version}" +# Make sure tabbing mode is disabled for the selected java version + +CFBundleIdentifier=net.java.openjdk.$(get_java_version_from_cmd "${JAVACMD}").java +if [ x$(defaults read ${CFBundleIdentifier} AppleWindowTabbingMode) != "xnever" ]; then + defaults write ${CFBundleIdentifier} AppleWindowTabbingMode never +fi if [ -z "${JAVACMD}" ] || [ ! -x "${JAVACMD}" ] ; then @@ -712,9 +829,10 @@ if [ -z "${JAVACMD}" ] || [ ! -x "${JAVACMD}" ] ; then stub_logger "[EXIT 3] ${MSG_NO_SUITABLE_JAVA_EXPANDED}" # display error message with AppleScript - osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_NO_SUITABLE_JAVA_EXPANDED}\n${MSG_NO_SUITABLE_JAVA_CHECK}\" with title \"${CFBundleName}\" buttons {\" OK \", \"${MSG_VISIT_JAVA_DOT_COM}\"} default button \"${MSG_VISIT_JAVA_DOT_COM}\" with icon path to resource \"${CFBundleIconFile}\" in bundle (path to me)" \ + osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_NO_SUITABLE_JAVA_EXPANDED}\n${MSG_NO_SUITABLE_JAVA_CHECK}\" with title \"${CFBundleName}\" buttons {\" OK \", \"${MSG_VISIT_JAVA_DOT_COM}\", \"${MSG_VISIT_ADOPTOPENJDK}\"} default button 1${DialogWithIcon}" \ -e "set response to button returned of the result" \ - -e "if response is \"${MSG_VISIT_JAVA_DOT_COM}\" then open location \"http://java.com\"" + -e "if response is \"${MSG_VISIT_JAVA_DOT_COM}\" then open location \"https://www.java.com/download/\"" \ + -e "if response is \"${MSG_VISIT_ADOPTOPENJDK}\" then open location \"https://adoptopenjdk.net/releases.html\"" # exit with error exit 3 @@ -722,9 +840,10 @@ if [ -z "${JAVACMD}" ] || [ ! -x "${JAVACMD}" ] ; then # log exit cause stub_logger "[EXIT 1] ${MSG_ERROR_LAUNCHING}" # display error message with AppleScript - osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_INSTALL_JAVA}\" with title \"${CFBundleName}\" buttons {\"${MSG_LATER}\", \"${MSG_VISIT_JAVA_DOT_COM}\"} default button \"${MSG_VISIT_JAVA_DOT_COM}\" with icon path to resource \"${CFBundleIconFile}\" in bundle (path to me)" \ + osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_INSTALL_JAVA}\" with title \"${CFBundleName}\" buttons {\"${MSG_LATER}\", \"${MSG_VISIT_JAVA_DOT_COM}\", \"${MSG_VISIT_ADOPTOPENJDK}\"} default button 1${DialogWithIcon}" \ -e "set response to button returned of the result" \ - -e "if response is \"${MSG_VISIT_JAVA_DOT_COM}\" then open location \"http://java.com\"" + -e "if response is \"${MSG_VISIT_JAVA_DOT_COM}\" then open location \"https://www.java.com/download/\"" \ + -e "if response is \"${MSG_VISIT_ADOPTOPENJDK}\" then open location \"https://adoptopenjdk.net/releases.html\"" # exit with error exit 1 fi @@ -739,7 +858,7 @@ if [ -z "${JVMMainClass}" ]; then # log exit cause stub_logger "[EXIT 2] ${MSG_MISSING_MAINCLASS}" # display error message with AppleScript - osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_MISSING_MAINCLASS}\" with title \"${CFBundleName}\" buttons {\" OK \"} default button 1 with icon path to resource \"${CFBundleIconFile}\" in bundle (path to me)" + osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_MISSING_MAINCLASS}\" with title \"${CFBundleName}\" buttons {\" OK \"} default button 1${DialogWithIcon}" # exit with error exit 2 fi @@ -773,11 +892,11 @@ stub_logger "[WorkingDirectory] ${WorkingDirectory}" # - main class # - main class arguments # - passthrough arguments from Terminal or Drag'n'Drop to Finder icon -stub_logger "[Exec] \"$JAVACMD\" -cp \"${JVMClassPath}\" -splash:\"${ResourcesFolder}/${JVMSplashFile}\" -Xdock:icon=\"${ResourcesFolder}/${CFBundleIconFile}\" -Xdock:name=\"${CFBundleName}\" ${JVMOptionsArr:+$(printf "'%s' " "${JVMOptionsArr[@]}") }${JVMDefaultOptions:+$JVMDefaultOptions }${JVMMainClass}${MainArgsArr:+ $(printf "'%s' " "${MainArgsArr[@]}")}${ArgsPassthru:+ $(printf "'%s' " "${ArgsPassthru[@]}")}" +stub_logger "[Exec] \"$JAVACMD\" -cp \"${JVMClassPath}\" ${JVMSplashFile:+ -splash:\"${ResourcesFolder}/${JVMSplashFile}\"} -Xdock:icon=\"${ResourcesFolder}/${CFBundleIconFile}\" -Xdock:name=\"${CFBundleName}\" ${JVMOptionsArr:+$(printf "'%s' " "${JVMOptionsArr[@]}") }${JVMDefaultOptions:+$JVMDefaultOptions }${JVMMainClass}${MainArgsArr:+ $(printf "'%s' " "${MainArgsArr[@]}")}${ArgsPassthru:+ $(printf "'%s' " "${ArgsPassthru[@]}")}" exec "${JAVACMD}" \ -Djava.library.path="${AppleJavaFolder}" \ -cp "${JVMClassPath}" \ - -splash:"${ResourcesFolder}/${JVMSplashFile}" \ + ${JVMSplashFile:+ -splash:"${ResourcesFolder}/${JVMSplashFile}"} \ -Xdock:icon="${ResourcesFolder}/${CFBundleIconFile}" \ -Xdock:name="${CFBundleName}" \ ${JVMOptionsArr:+"${JVMOptionsArr[@]}" }\