Porównaj commity

...

1125 Commity

Autor SHA1 Wiadomość Data
crewdogelectronics 36b5045554
Update README.md
I was today years old when I learned software gets deprecated not depreciated.
2024-09-24 11:55:10 -06:00
crewdogelectronics ea492efca5
Update README.md 2024-09-23 13:17:11 -06:00
crewdogelectronics 5230289042
Update README.md 2024-09-22 22:27:42 -06:00
crewdogelectronics 2844766179
Update README.md 2024-09-22 21:40:51 -06:00
crewdogelectronics 2ce453289c
Update README.md 2024-09-22 21:33:44 -06:00
crewdogelectronics 03312cff4f
Update README.md 2024-09-22 21:25:45 -06:00
crewdogelectronics e90076cae0
Update README.md 2024-09-22 21:19:15 -06:00
crewdogelectronics 4f67598acd
Update README.md 2024-09-22 20:53:16 -06:00
Helno eec0b15d4a
Update README.md 2023-02-26 15:59:49 -05:00
Helno 2d421310bd
Update README.md
Updated pi compatibility statement.
2023-02-26 15:59:33 -05:00
Eric Westphal ec997fbf98
Merge pull request #829 from cyoung/revert-824-bmx160
Revert "Add support for bmx160 MPU"
2020-12-19 09:02:26 -06:00
Eric Westphal ac357d8a28
Revert "Add support for bmx160 MPU" 2020-12-19 10:01:42 -05:00
Helno fb1ef310f5
Merge pull request #824 from westphae/bmx160
Add support for bmx160 MPU
2020-12-16 20:48:08 -05:00
Eric Westphal d9a19c0a7f Add support for bmx160 MPU 2020-11-21 20:28:08 -06:00
cyoung 7eeb32acf6
Merge pull request #817 from cyoung/icm20948
ICM-20948 support.
2020-08-19 16:27:04 -04:00
cyoung e949daed02
Merge pull request #816 from jtremolo/add_dark_mode
Add dark mode
2020-08-19 11:59:53 -04:00
Jordan T b28b002e6b Dynamically change theme css 2020-08-19 10:40:07 -05:00
Jordan T 4241d2a17e Add dark mode switch 2020-08-19 10:38:29 -05:00
Jordan T 463721c93b Add dark mode setting storage 2020-08-19 10:38:19 -05:00
Jordan T fb7a09ba3e Add dark mode switch 2020-08-19 10:38:19 -05:00
Jordan T eb4fc67e22 Move embedded styling to css 2020-08-19 10:36:17 -05:00
cyoung cf28a07c9f
Merge pull request #756 from PepperJo/showheightWGS84
Website: Add height above ellipsoid
2020-05-15 15:21:56 -04:00
cyoung 8859b26653
Merge pull request #794 from wcas/wac/improve-ownship-report-v2
Improve ownship detection for EFBs that care
2020-05-15 15:19:27 -04:00
cyoung e0a22baeac
Merge branch 'master' into wac/improve-ownship-report-v2 2020-05-15 15:19:00 -04:00
cyoung 89e158d29b
Merge pull request #801 from lyusupov/master
UDEV rule for SoftRF Dongle Edition
2020-05-15 15:07:57 -04:00
cyoung 5a47671866
Merge pull request #802 from MatthewH-code/master
Added setting "NoSleep" to disable sleeping
2020-05-15 15:07:06 -04:00
cyoung 1da3dd81f4
Merge pull request #803 from Desarrolloscr/master
Missing closing bracket
2020-05-15 15:06:26 -04:00
cyoung c4e00ccf46
Merge pull request #808 from Blaumeiser/patch-1
Update README.md
2020-05-15 15:05:55 -04:00
cyoung 9db076f8d3 Clean up old Stratus AHRS RE tools.
FF opened their AHRS-over-GDL90, not needed.
2020-04-14 11:07:19 -04:00
cyoung d85695e842 Update goflying module. 2020-03-27 11:25:43 -04:00
Blaumeiser ba27147404
Update README.md
Add Pilots Atlas in the Apple AppStore to the list of supported Apps. I'm the developer of the Pilots Atlas App.
2020-03-01 11:49:32 +01:00
cyoung 8698e90f0a Merge branch 'master' into icm20948 2020-01-15 21:45:24 -05:00
cyoung 6d470ac0f8 Add ICM-20948 sensor module and detection. 2020-01-15 11:51:06 -05:00
Jonathan 115c4c3373 Missing closing bracket 2020-01-07 19:45:19 -06:00
matthewh628 1738345af5 Added setting "NoSleep" to disable sleeping 2020-01-03 10:22:25 -06:00
Linar Yusupov 2a0f638f63
UDEV rule for SoftRF Dongle Edition 2020-01-02 18:22:57 +03:00
cyoung 37911bc692 Remove dhcpd file before creating new symlink. 2019-12-21 12:40:46 -05:00
cyoung be93f4290c Add WiFi "Smart Mode" option.
No default gateway. Allows iOS to choose internet source (cellular or WiFi).
2019-12-21 12:32:02 -05:00
William Castillo 1c92f75c4d Improve ownship detection for EFBs that care 2019-10-27 11:58:18 -05:00
cyoung eebe80d3c7
Merge pull request #793 from wcas/wac/fix-ownship-report
Fix Ownship Target Identity Information
2019-10-14 11:56:04 -04:00
William Castillo cac8dd98d4 Fix Ownship Target Identity Information 2019-10-13 22:23:38 -05:00
cyoung 93de565e4b Pass i2cbus parameter for NewMPU9250(). 2019-09-24 14:05:18 -04:00
cyoung 377d22b403 Remove constant "No suitable device found." log message when no GPS found.
Debug only now.
2019-08-12 16:21:21 -04:00
cyoung 4afdebbc5a Comments on /getSituation AHRS fields. 2019-07-04 13:50:05 -04:00
cyoung ab6b11554c Move "GPS serial connection in use" log print to DEBUG only.
#772.
2019-06-05 10:09:08 -04:00
Helno 88ad123672
added G450 to the jet tests list. 2019-05-04 18:14:28 -04:00
cyoung 50e2b3c997 Typo fix. 2019-04-08 12:42:35 -04:00
cyoung 9afe00dbc7 Add ublox9 handling (same as ublox8) for testing. 2019-04-08 12:20:03 -04:00
cyoung 9e211d849d Use ownship received traffic. 2019-04-02 10:12:32 -04:00
cyoung e162742d68 Clean up dhcpd.conf. 2019-03-20 10:06:07 -04:00
cyoung 3ce29823ed Clarify Pi 3 B+. 2019-02-24 18:04:49 -05:00
cyoung 41383ced4e Clarify sleep mode behavior. 2019-02-05 23:17:48 -05:00
cyoung 8f4a52d739 Call `gracefulShutdown()` before reboot.
Fixes #717.
2019-02-01 16:06:22 -05:00
cyoung 39bb2e3415 Add min/max observed CPU temps.
#728.
2019-01-31 11:45:21 -05:00
cyoung 7026f1975a AUXSV parsing for UAT message types 1,2,5,6. Calculate GnssDiffFromBaroAlt.
#721.
2019-01-31 10:32:35 -05:00
cyoung 5593f389cd Config anonymous SDR to 1090 by default when uatradio is present. 2019-01-31 09:37:29 -05:00
cyoung 659e7860a2 Don't duplicate gen_gdl90 messages in syslog general log.
#765.
2019-01-17 17:09:23 -05:00
cyoung 362a2ffb39 Add stratux logrotate conf.
#765.
2019-01-17 16:56:51 -05:00
cyoung bcceaab2ee Handle multiple signals.
#765.
2019-01-17 16:54:34 -05:00
cyoung 73ae89d137 Re-open logfile on SIGHUP for log rotation.
#765.
2019-01-17 16:49:04 -05:00
cyoung e5916be472 Clean up /root/stratux-update after update. 2018-11-16 16:29:28 -05:00
cyoung 24a5d552c4 Add chmod for permissions on certain files for update. 2018-11-13 19:30:26 -05:00
cyoung 8544d6926f Add prometheus metrics to fancontrol. 2018-11-13 19:24:12 -05:00
cyoung 7aa986fbab Allow AHRS output when GPS fix not valid but in developer mode. 2018-10-29 08:36:58 -04:00
cyoung 9a495c964a Use "GPS fix valid" condition instead of GPS ground track valid for isAHRSValid(). 2018-10-29 08:34:46 -04:00
PepperJo 5974fd2266 Website: Add height above ellipsoid
Add GPS height above WGS-84 ellispoid to the website.

Signed-off-by: PepperJo <pepperjo@japf.ch>
2018-10-24 21:34:54 +02:00
cyoung 1756f77433
Merge pull request #751 from westphae/ahrs_warnings
AHRS Warnings and disable AHRS output when GPS not available, fixes #732.
2018-10-01 13:59:51 -04:00
Eric Westphal 5495b8b265 Add warning messages for pseudo-AHRS and no AHRS 2018-09-30 22:40:45 +00:00
Eric Westphal 9b5c850d9e Enable Connected indicators on Towers and GPS/AHRS web UI pages 2018-09-30 18:23:43 +00:00
Eric Westphal 7a31db058e Remove Calibrate Gyros from Settings page of web UI 2018-09-30 01:56:06 +00:00
Eric Westphal da66dc5461 Merge remote-tracking branch 'cyoung/master' into ahrs_warnings 2018-09-29 21:57:53 +00:00
Eric Westphal de865c6961 Add Gyro Calibration button to AHRS page in web UI 2018-09-29 21:57:30 +00:00
Eric Westphal b42350f1cf ahrs.js code cleanup, improve ahrs error display 2018-09-29 18:46:34 +00:00
cyoung 7340719ae3
Merge pull request #734 from westphae/wifi
Wifi Configuration on Settings Page
2018-09-29 10:08:30 -04:00
Eric Westphal 3b32df7f39 Display AHRS ground mode warning in web UI 2018-09-29 11:06:54 +00:00
cyoung 3d168d0c6c Link against math lib for lowpower_uat.go. 2018-09-27 16:02:59 -04:00
cyoung 5ed17d968a Cleanup. 2018-09-27 15:58:41 -04:00
cyoung ceb9a7dc1a
Merge pull request #750 from cyoung/newradio
Add new UAT radio support.
2018-09-27 15:54:08 -04:00
cyoung b10b1769d8 Merge branch 'master' into newradio 2018-09-27 15:15:39 -04:00
cyoung cd4b756810 Add log output. Change SDR count only for interface. 2018-09-27 14:23:03 -04:00
cyoung 517ad79632 Imports/unused variable fix. 2018-09-27 11:40:22 -04:00
cyoung 96338b413d Add /dev/uatradio on a one second interval. 2018-09-27 11:33:47 -04:00
cyoung beed8e7c1a Remove debug logging. 2018-09-27 11:11:44 -04:00
Helno 77fffa5f13
Update README.md 2018-09-25 19:27:12 -04:00
cyoung d0b447dc7a Add SoftRF udev rules and "ping" code hack (temporary). 2018-09-12 10:09:08 -04:00
cyoung c612444a79 Revert 0d93623b94. 2018-09-11 16:05:40 -04:00
Helno 4f9a02d567
update readme
Remove line about dangerzone and added kwikEFIS to the list of apps that support Stratux
2018-09-04 15:07:06 -04:00
cyoung 260a14ca4c Adds AU tail number decoding from ICAO addr.
Contribution by @armeniki. #736.
2018-08-15 15:02:52 -04:00
cyoung 6c0f75de77 Merge branch 'newradio' of https://github.com/cyoung/stratux into newradio 2018-08-13 22:52:03 -04:00
cyoung 578148e5f2 Change to stratux/serial. 2018-08-13 22:52:01 -04:00
cyoung 2bf1bb6dba Merge remote-tracking branch 'refs/remotes/origin/master' into newradio 2018-08-08 13:04:20 -04:00
Eric Westphal 65e80816c2 Merge branch 'master' into wifi 2018-08-05 22:24:25 -04:00
cyoung 8d9fdd31f7 Add info to main status help page.
Fixes #728.
2018-07-30 10:43:33 -04:00
cyoung 4b0f7f47cf Scope error fix. 2018-07-13 12:03:36 -04:00
cyoung 8703b4c124 Don't relay uncorrectable (rs_errors=9999) messages. 2018-07-10 17:42:44 -04:00
cyoung b0821576fb Merge branch 'master' into newradio 2018-07-10 11:42:44 -04:00
cyoung 6df88abc72 Increase suggested wait time on updates. 2018-06-26 09:39:37 -04:00
cyoung 898463e2ef Merge remote-tracking branch 'refs/remotes/origin/master' into newradio 2018-06-22 14:26:15 -04:00
cyoung 0d93623b94 Comment out ublox8 Glonass / Galileo code. 2018-06-13 15:11:06 -04:00
cyoung fbb64a4345 Cleanup. Add /dev/uatradio rule. 2018-06-13 15:10:11 -04:00
cyoung 2dca39c7d8 Add udev rules. Change start-up sequence (fixes race condition -- receiving UAT packets before init is complete). 2018-06-11 19:02:38 -04:00
cyoung 7142edb3ba Restore RSSI/timestamp parsing. 2018-06-11 16:56:14 -04:00
cyoung 462de2843f Revert back to FEC calculating code. 2018-06-11 16:50:33 -04:00
cyoung 8082df9752 Merge remote-tracking branch 'refs/remotes/origin/master' into newradio 2018-06-11 16:48:42 -04:00
cyoung 8eeb20a9df
Merge pull request #720 from westphae/gyro-heading-fix
Fix gdl90 AHRSGyroHeading reporting.
2018-05-29 18:53:36 -04:00
Eric Westphal 006824ef8d Fix gdl90 AHRSGyroHeading reporting. 2018-05-28 08:30:32 -04:00
cyoung 164b00396f Remove FEC computations on Pi side. 2018-05-21 14:27:34 -04:00
cyoung c0127928af Fan control failsafe temp.
#663
2018-05-10 22:42:41 -04:00
cyoung d8a9d5c1a3 Add signal strength and timestamp parsing. 2018-05-01 13:41:31 -04:00
cyoung 2e8ed95506 Clean up obsolete dangerzone includes. 2018-04-26 14:54:12 -04:00
cyoung b9ac1a394a Initial testing code. 2018-04-25 16:08:46 -04:00
cyoung 92dab38028 gen_gdl90 gracefulShutdown() on system shutdown or reboot request. 2018-04-19 10:37:30 -04:00
cyoung 991f48eaa5 Update ForeFlight version to 10+ for AHRS support. 2018-04-10 16:10:33 -04:00
cyoung ddbd3d5ef8 Change ForeFlight support note in README. 2018-04-06 15:10:17 -04:00
cyoung 54ab7df155 Add new ForeFlight AHRS and ID GDL90 messages. 2018-04-06 15:08:45 -04:00
cyoung 14a21eaa0b RPi3B+ setup. 2018-03-29 22:32:40 -04:00
cyoung 915391fa91 Use "N" or "C" regs derived from Mode-S identifier, or default to "Stratux". 2018-03-09 09:49:03 -05:00
cyoung 99ac28b104 Roll back changes. 2018-01-26 11:15:55 -05:00
cyoung 7338ad4336 Merge remote-tracking branch 'origin/master'
# Conflicts:
#	selfupdate/makeupdate.sh
2018-01-26 10:48:55 -05:00
cyoung cd875f6449 Merge remote-tracking branch 'refs/remotes/origin/ahrs_dev_protocolfun' 2018-01-26 10:44:39 -05:00
cyoung 6a40d979b7 Make PPM setting a developer option.
#79.
2018-01-17 14:10:24 -05:00
cyoung da28af53c0 Simplify "Settings" page.
Only display "Hardware" and "Diagnostic" settings when in developer mode.
2018-01-17 10:55:09 -05:00
cyoung 1a1cf2e93c Delete /var/log/stratux* on update. 2018-01-17 10:33:13 -05:00
cyoung a1ea17e7ca Remove unnecessary debug print. 2018-01-09 16:30:28 -05:00
cyoung 95a80395fd Change CircleCI to test to build master. 2018-01-09 12:14:32 -05:00
cyoung 2abfdd11af Remove test build from CircleCI config. 2018-01-09 12:04:41 -05:00
cyoung b8e149cb61 Cleanup.
#692
2018-01-09 12:00:55 -05:00
cyoung 8b806b8aad Remove "test" directory from go get in gen_gdl90 make. 2018-01-09 11:58:14 -05:00
cyoung 0eb6014341 Install mercurial on CircleCI. 2018-01-09 11:42:50 -05:00
cyoung 56ac7ee8fc Clean gopath on each CircleCI build. 2018-01-09 11:38:16 -05:00
cyoung 36ea8c0d40 Upgrade golang version in CircleCI from 1.6 to 1.9.2. 2018-01-09 11:19:30 -05:00
cyoung c5314de3f2 Clean up unused imports.
#692
2018-01-09 10:41:13 -05:00
cyoung c4b8216a84 Change error prints to use addSingleSystemErrorf().
#692
2018-01-09 10:40:25 -05:00
cyoung 033c3ca1e4 Use addSingleSystemErrorf() instead of tracking error prints individually.
#692.
2018-01-09 10:09:18 -05:00
cyoung df6f844738 Create function that tracks critical system errors and issues them only once.
#692
2018-01-09 09:57:00 -05:00
cyoung 31b3e83ea6 Remove old libimu.so references in selfupdate. 2017-12-28 16:58:04 -05:00
cyoung 607310af24 Change deleted AvSquirrel/dump1090 submodule to mirror at stratux/dump1090 2017-12-28 16:47:38 -05:00
Christopher Young 08f786b4b0 Add some AHRS and maintenance web calls to documents. 2017-11-29 20:16:29 -05:00
Christopher Young bd10be4f63 Add logrotate conf. Keep two days of logs. Run logrotate on boot. 2017-11-17 11:12:20 -05:00
Christopher Young a3fda2aa3c Turn off wireless power management, from D. DeMartini. 2017-11-10 09:57:29 -05:00
cyoung 16b61a37a9
Merge pull request #678 from Helno/patch-2
update readme.md
2017-11-10 09:51:01 -05:00
Helno 2a6beb8478
update readme.md
added additional jet tests.
2017-11-10 09:46:39 -05:00
Christopher Young a0d9a4be25 Merge branch 'master' into ahrs_dev_protocolfun 2017-10-31 22:56:14 -04:00
cyoung bb9cb778d2 Update system uptime warning format. 2017-10-27 16:05:15 -04:00
cyoung cc4127df80 Remove socket listener from fancontrol. Replace with http server. Serve status in JSON format. 2017-10-23 14:58:24 -04:00
cyoung bb9c3c6435 Add NightMode to turn off ACT LED.
#659.
2017-10-17 17:30:03 -04:00
cyoung f28bfffc0a Turn off PPS output (green LED on GPYes).
#659.
2017-10-17 17:23:54 -04:00
cyoung b3ca828086 Use estimate vAcc = 2*hAcc instead of reported vAcc.
Fixes #666.
2017-10-17 16:26:11 -04:00
cyoung b7beee37f0 Change luma usage.
#672.
2017-10-17 14:42:19 -04:00
cyoung 0d4d61cf56 Update oled package to new 'luma' package name.
Fixes #672.
2017-10-17 14:40:01 -04:00
cyoung 9a3fe7c0d1 Clean up log output. 2017-10-12 13:21:55 -04:00
cyoung 8bc7f0c093 Add Merlin auto-detect. 2017-10-12 12:22:52 -04:00
Christopher Young 3b57564490 Cleanup. 2017-10-11 13:37:37 -04:00
Christopher Young 04e6d6af36 Merge branch 'master' into ahrs_dev_protocolfun 2017-10-11 13:29:31 -04:00
Christopher Young 022545dde6 Merge branch 'master' into ahrs_dev_protocolfun
# Conflicts:
#	selfupdate/makeupdate.sh
#	selfupdate/update_footer.sh
2017-10-11 13:18:36 -04:00
Christopher Young 157e456805 Change goflying version. 2017-10-11 13:18:26 -04:00
cyoung 782f22cf54 Update goflying. 2017-10-11 09:22:15 -04:00
cyoung 3ef0c4b31a Update goflying. 2017-10-11 09:20:32 -04:00
cyoung 7ac2aa7478 Move to cyoung/goflying, 'stratux_master' branch. 2017-10-11 09:11:45 -04:00
cyoung 57c783d695 Typo fix. 2017-10-11 08:56:30 -04:00
cyoung 2df716f2f6 Remove unused 'CPULoad' status variable. 2017-10-11 08:40:10 -04:00
cyoung 4fa548b380 stratux.log cleanup. 2017-10-11 08:39:09 -04:00
cyoung b695353d44 Install dhcpd.conf and interfaces file. 2017-10-11 08:33:11 -04:00
cyoung 62b6df682b Remove sqlite log and stratux.log on update. 2017-10-11 08:23:57 -04:00
cyoung 4da6af1905 Add dhcpd.conf and interfaces files to .sh update. 2017-10-11 08:07:30 -04:00
Christopher Young 4de2420803 Clean up cputemp. 2017-10-10 11:27:15 -04:00
Christopher Young ae734f41ba Adapt `ffMonitor()` to ahrs_approx - only send the FF AHRS packets when FF is detected. 2017-10-10 10:05:40 -04:00
Christopher Young fc0fe317ab Merge remote-tracking branch 'origin/master' into ahrs_dev_protocolfun 2017-10-10 09:56:28 -04:00
cyoung 2fc134aa38 Update EFB documentation. 2017-09-26 14:45:36 -04:00
cyoung be67f51eab Remove ahrs_dev branch deployment rule. 2017-09-22 12:49:47 -04:00
cyoung 269ef27b50 Fix outdated imports. Cleanup. 2017-09-22 11:42:57 -04:00
cyoung abe84edfae Fix circleci build test - outdated imports in test/maxgap.go. 2017-09-22 11:20:15 -04:00
cyoung 7f6f1394e0 Activate config change block for $OPT_P (-p option).
Ref #667.
2017-09-22 10:55:54 -04:00
Christopher Young f422ae6578 Remove test CircleCI build. 2017-09-12 10:33:30 -04:00
Christopher Young 2017adf78b Remove tests from "go get".
Tests aren’t automatically built.
2017-09-12 10:20:58 -04:00
Christopher Young 05aa90b125 Clean up fancontrol.
Working on #663.
2017-09-12 08:56:31 -04:00
Christopher Young f8646d9ebe Check system uptime before SDR startup delay.
Throw a system error in developer mode if the uptime is greater than
120s and `sdrWatcher()` is restarted (usually a systemd restart).
2017-08-18 12:56:58 -04:00
Christopher Young 94c6e5a353 Add alias for 192.168.10.1 for normal webui access. 2017-08-15 17:25:53 -04:00
Christopher Young 5ddadfa78d Merge remote-tracking branch 'origin/master' into ahrs_dev_protocolfun 2017-08-15 16:28:45 -04:00
cyoung 032849fab0 Merge pull request #657 from cyoung/ahrs_dev
Sync master with ahrs_dev (minor webui changes).
2017-08-13 16:25:03 -04:00
Christopher Young 28710b59cc Merge remote-tracking branch 'origin/master' into ahrs_dev 2017-08-13 16:24:18 -04:00
Christopher Young 31abc00910 Delay SDR startup by 1m30s. 2017-08-07 16:50:44 -04:00
Christopher Young 36454ad743 Update goflying. 2017-08-04 00:10:24 -04:00
Christopher Young 046dc54f27 Update goflying. 2017-08-03 23:09:11 -04:00
Christopher Young fcf524b03c Merge remote-tracking branch 'origin/master' into ahrs_dev_protocolfun 2017-08-03 23:08:45 -04:00
Eric Westphal 945724c907 Slightly different regex's in javascript validation. 2017-07-30 12:38:44 -04:00
Eric Westphal ed7c1475c2 Merge branch 'master' of github.com:westphae/stratux 2017-07-29 10:41:28 -04:00
Eric Westphal c319d49e74 Angular validation on settings page. 2017-07-29 10:40:29 -04:00
Christopher Young 4b66b518f1 Add link in README to EFB integration guide. 2017-07-22 22:34:35 -04:00
Eric Westphal d48691bdac Fix .js and .html permissions. 2017-07-22 17:04:30 -04:00
Eric Westphal 034e38d4e7 Formatting; re-do grayout of disabled text boxes. 2017-07-22 16:03:35 -04:00
Eric Westphal be692f7a84 Merge remote-tracking branch 'peeps/patch-2' into peeps 2017-07-22 15:31:37 -04:00
peepsnet 8932abf342 Removed Confirm Modal and cleaned up modals 2017-07-22 14:49:15 -04:00
peepsnet dd9afdac33 error checking in SSID and WPA Passphrase 2017-07-22 14:48:11 -04:00
Eric Westphal e96694ced2 Merge remote-tracking branch 'cyoung/master' into ahrs_dev 2017-07-22 13:34:55 -04:00
Eric Westphal c406c344aa Grey out settings text boxes when disabled. 2017-07-22 13:22:58 -04:00
Eric Westphal cc24fb6fef Added Go portion of @peepsnet WiFi handling. 2017-07-22 12:43:32 -04:00
Eric Westphal e5631bd38f A few more changes from @peepsnet. 2017-07-21 17:03:16 -04:00
Eric Westphal 7e74615ce6 Remove hostapd_manager_quiet.sh per @peepsnet. 2017-07-21 16:00:37 -04:00
Eric Westphal ef3c8d526a Whitespace fixes 2017-07-20 17:35:55 -04:00
Eric Westphal 57a1bd9c7c Merge remote-tracking branch 'cyoung/master' into peeps 2017-07-20 17:30:09 -04:00
Eric Westphal be066a67bc Merge remote-tracking branch 'cyoung/ahrs_dev' into ahrs_dev 2017-07-20 17:09:55 -04:00
Eric Westphal 8fadfe0602 Formatting and spelling. 2017-07-18 19:29:50 -04:00
Eric Westphal 5463d334c4 Merge remote-tracking branch 'peeps/master' into peeps
Added new settings from ahrs_dev branch back in.
2017-07-18 18:32:02 -04:00
Christopher Young f6bad36cdc Update README. 2017-07-17 17:49:40 -04:00
cyoung 67058e7ae5 Merge pull request #641 from cyoung/ahrs_dev
AHRS for v1.4r1.
2017-07-17 17:45:31 -04:00
Christopher Young 0d833946f4 Remove redeclared variables. 2017-07-17 17:36:43 -04:00
Christopher Young 284bb0733f Remove redeclared structs. 2017-07-17 17:35:10 -04:00
Christopher Young 6709c9b4e6 Merge remote-tracking branch 'origin/master' into ahrs_dev
# Conflicts:
#	main/gen_gdl90.go
2017-07-17 17:18:12 -04:00
cyoung 68ceffd8f5 Merge pull request #635 from peepsnet/patch-1
Added allow-hotplug eth0
2017-07-17 10:14:49 -04:00
cyoung 765417b7bc Merge pull request #638 from drnic/patch-1
[docs] change snippet to 'javascript' for github markdown
2017-07-17 10:14:02 -04:00
Dr Nic Williams 5cce0a3f30 change snippet to 'javascript' for github markdown
github markdown `json` format doesn't accept comments; but luckily `javascript` format does. This change makes the docs look nice in github.
2017-07-16 19:26:59 +10:00
Eric Westphal aa74554a81 Change sensor switch names. 2017-07-15 22:06:26 -04:00
Eric Westphal 218c312b98 Better initialization of gLoad, slipSkid, rateOfTurn. 2017-07-14 16:46:03 -04:00
peepsnet 3148f810c3 Update __root__stratux-pre-start.sh 2017-07-14 14:47:01 -04:00
peepsnet 8ff30f0980 Set theme jekyll-theme-time-machine 2017-07-14 14:43:09 -04:00
peepsnet ff3e901501 Update __root__stratux-pre-start.sh 2017-07-14 14:29:13 -04:00
peepsnet 95f4d0a278 Update main.js 2017-07-13 09:13:14 -04:00
Eric Westphal 1877e66056 Ensure level signal doesn't block cal channel. 2017-07-12 22:20:23 -04:00
peepsnet 57c6c8ee8b look and feel 2017-07-12 21:13:52 -04:00
Eric Westphal 20877df847 Separate gyro calibration and AHRS level functions. 2017-07-12 13:27:26 -04:00
peepsnet 10475445fd added allow-hotplug eth0
Seems this is useful now that we have the static IP option in developers
2017-07-11 21:07:40 -04:00
peepsnet ed53ecf3d8 typo 2017-07-10 23:01:22 -04:00
peepsnet 5d13c10a58 Updated Help also 2017-07-10 22:56:39 -04:00
peepsnet f5e1ec828f Tweak look feel 2017-07-10 21:42:28 -04:00
peepsnet dca880738d class to grey out div 2017-07-10 20:40:26 -04:00
peepsnet f42bb4d47f cleaned up application constants 2017-07-10 20:39:25 -04:00
peepsnet dc14b9dd80 HTML/JS Prop for WiFI Settings
added js code for error checking and formatting the JSON string for the call to /setSettings
{"WiFiSSID":"stratux","WiFiSecurityEnabled":true,"WiFiPasscode":"h98tdjepi","WiFiChannel":"5"}

 $scope.WiFiSSID = "stratux"; //settings.WiFiSSID;
 $scope.WiFiSecurityEnabled = true; //settings.WiFiSecurityEnabled;
$scope.WiFiPasscode = Math.random().toString(36).substring(4); //settings.WiFiPasscode;
$scope.WiFiChannel = "5"; //settings.WiFiChannel;    

I have hardcoded the values till they are included in the /getSettings JSON string
2017-07-10 20:38:22 -04:00
peepsnet aad4dc53ec HTML/JS Prep for WiFi Settings and StaticIP value fix
FIrst, I added the missing code to pull in the Static IP info the input field from the JSON string

Second and biggest:
This is the code to add the WiFi Settings to the Settings Page. In preparation for the GO code behind the scenes

Before it is live/working a few lines should be removed and the modals cleaned up. 

I had some issues getting the ng-bind working in the modalErrorWiFi modal. There is an update issue. Something about being outside of the digest.  I'm not sure.

The code sends a JSON string:  {"WiFiSSID":"stratux","WiFiSecurityEnabled":true,"WiFiPasscode":"h98tdjepi","WiFiChannel":"5"} to /setSettings

I also did some cleanup in the HTML.
2017-07-10 20:32:40 -04:00
Eric Westphal 90c10195fb Minor log message change. 2017-07-09 17:48:35 -04:00
peepsnet e43f09395f added hostpad_manager_quiet.sh 2017-07-08 18:55:57 -04:00
peepsnet d47bea63c9 added hostpad_manager_quiet.sh 2017-07-08 18:55:07 -04:00
peepsnet 4d26ba2c48 added hostpad_manager_quiet.sh 2017-07-08 18:54:07 -04:00
peepsnet 3bd913ecb6 added hostpad_manager_quiet.sh 2017-07-08 18:52:46 -04:00
peepsnet c8c43e6638 A quiet hostpad_manager script for app calls
# This script is almost identical to hostapd_manager.sh except all the
# screen outputs are supplressed except for error messages. 
#
# Usage:
# hostapd_manager_quiet.sh -s Stratux-N12345 -p SquawkDirty! -c 5
# Command above sets the SSID to "Stratux-N12345, secures the network with the passphrase "SquawkDirty!, and changes the network channel to "5"
#
# hostapd_manager_quiet.sh -o
# Command above opens the network(removes any passphrase)
#
# hostapd_manager_quiet.sh -e
# Command above secures the WiFi network using the default passphrase "SquawkDirtyToMe!"

# Options:
# -s	--Sets the SSID to ${BOLD}ssid${NORM}. -s stratux
# -c	--Sets the channel to chan. -c 1
# -o	--Turns off encryption and sets network to open. Cannot be used with -e or -p.
# -e	--Turns on encryption with passphrase SquawkDirtyToMe!. Cannot be used with -o or -p
# -p	--Turns on encryption with your chosen passphrase pass. 8-63 Printable Characters(ascii 32-126). Cannot be used with -o or -e. -p password!
#
# Important:
# After each call of this script the wifi network will disconnect and restart all associated services to apply the changes
2017-07-08 18:49:23 -04:00
peepsnet 6e9c86eeb6 Merge pull request #10 from cyoung/master
update
2017-07-08 17:57:21 -04:00
Eric Westphal 21278eb265 Level uses calibration accels, retry ccal if nonsense values. 2017-07-08 14:52:10 -04:00
Eric Westphal 572c1d08a5 Minor reorganization. 2017-07-08 13:50:46 -04:00
Eric Westphal 5926b05757 Deleting AHRS logs no longer stops all AHRS logging. 2017-07-07 21:24:49 -04:00
Eric Westphal 5c66d14d00 Re-word AHRS orientation dialog boxes. 2017-07-07 19:56:45 -04:00
Eric Westphal e0faa71b3f Remove 'up' section from orientation procedure. 2017-07-06 19:45:01 -04:00
Eric Westphal ccf04867fb Reduce AI pitch scale. 2017-07-06 19:43:32 -04:00
Christopher Young 0788d4a1a6 Add ahrs_dev deployment circleci rule. 2017-07-06 16:00:09 -04:00
Eric Westphal 4d3235fb4b Minor variable reorganization. 2017-07-04 13:31:04 -04:00
Eric Westphal 1bf2a9d808 Developer UI page allows downloading and deleting AHRS logs. 2017-07-03 19:43:51 -04:00
Eric Westphal e657a400f8 Elongate all the 5 deg marks on AI. 2017-07-01 17:32:23 -04:00
Eric Westphal 5f8ac80ac3 Move sensor orientation quaternion into AHRSProvider. 2017-07-01 17:19:27 -04:00
Eric Westphal 60a4e74503 Ensure AHRS level occurs after orientation. 2017-06-28 20:49:55 -04:00
Eric Westphal d854fb01be Update settings display on web UI after orientation. 2017-06-28 19:09:45 -04:00
Eric Westphal 2a132bb9cc Pass empty initial orientation to NewSimpleAHRS. 2017-06-28 19:08:55 -04:00
Eric Westphal e2c6fa26af Rename InitializeSimple to NewSimpleAHRS. 2017-06-25 11:36:57 -04:00
Eric Westphal b4f437aa3d Remove some old AHRS logging. 2017-06-24 15:51:13 -04:00
Eric Westphal 22fe8cddbe G Load min value doesn't start near zero. 2017-06-24 15:12:10 -04:00
Eric Westphal 993e0c946f Remove unused import. 2017-06-24 14:59:23 -04:00
Eric Westphal fef0ed466f Fix some bad initializations. 2017-06-24 14:46:47 -04:00
cyoung 771a1fe8a8 Merge pull request #625 from cyoung/ahrs_dev
Ahrs dev
2017-06-23 10:48:07 -04:00
Eric Westphal 74909ada85 Ensure SensorQuaternion synced with IMUMapping. 2017-06-22 19:47:25 -04:00
Eric Westphal a2bba208b6 Sensor orientation more reliable. 2017-06-21 22:05:44 -04:00
Eric Westphal c6e01d2ec6 Variable name change. 2017-06-21 22:02:59 -04:00
cyoung af317bc834 Merge pull request #624 from cyoung/ahrs_dev
Ahrs dev
2017-06-21 11:43:47 -04:00
cyoung 3871279473 Merge pull request #619 from jamez70/move_structs
Move structs to the top of the file
2017-06-14 10:33:44 -04:00
Eric Westphal 542a68fc26 Remove AHRS config from developer settings. 2017-06-13 18:14:08 -04:00
Eric Westphal b7cd14debb AHRS algorithm improvements 2017-06-13 17:54:25 -04:00
Eric Westphal 7af6f20884 Maybe make the orientation process more consistent. 2017-06-13 17:48:34 -04:00
Jim Jacobsen 545343332e Move structs to the top of the file 2017-06-11 17:50:34 +00:00
Christopher Young 51fd728cc6 Merge fix. 2017-06-09 10:54:41 -04:00
Christopher Young fd7ce1ec92 Merge remote-tracking branch 'origin/master' into ahrs_dev
# Conflicts:
#	main/gen_gdl90.go
2017-06-09 10:53:41 -04:00
Christopher Young 5f1ebfbe70 Removed ForeFlight GDL90 parsing bug workaround.
#348, 604.
2017-06-09 10:49:25 -04:00
Christopher Young 45e8ea90ac Merge remote-tracking branch 'origin/master' into ahrs_dev 2017-06-06 14:54:57 -04:00
Christopher Young 7fd67ccbc1 Stop fancontrol service before replacing binary.
#612.
2017-06-06 14:48:06 -04:00
root b11b23899d Merge branch 'ahrs_dev' into ahrs_dev_protocolfun 2017-06-05 20:52:02 +00:00
root 4c6573e103 Merge remote-tracking branch 'origin/ahrs_dev_protocolfun' into ahrs_dev 2017-06-05 20:51:44 +00:00
Christopher Young 23921ee384 Type fix. 2017-06-05 16:49:52 -04:00
root 11e09dcf5b Merge branch 'ahrs_dev' into ahrs_dev_protocolfun 2017-06-05 20:41:03 +00:00
root 82f2129d60 Merge remote-tracking branch 'origin/ahrs_dev_protocolfun' into ahrs_dev 2017-06-05 20:40:44 +00:00
Christopher Young a82f376ad0 Typo fix. 2017-06-05 16:37:32 -04:00
root e398ea152b Merge branch 'ahrs_dev' into ahrs_dev_protocolfun 2017-06-05 20:34:00 +00:00
root 78404004ab Merge remote-tracking branch 'origin/ahrs_dev_protocolfun' into ahrs_dev 2017-06-05 20:33:42 +00:00
Christopher Young e9e552a149 Use GPSTrueCourse in GDL90 packet as heading when gyro heading not available.
#612
2017-06-05 16:29:28 -04:00
Christopher Young ca4ae22c42 Change float32 types to float64 types to match AHRS library outputs. 2017-06-05 16:19:45 -04:00
Christopher Young 215b6034d6 Typo fix. 2017-06-05 15:06:11 -04:00
Christopher Young 92da285c55 Add isAHRSInvalidValue(). 2017-06-05 15:03:19 -04:00
Christopher Young ac021ebe6a Conslidate 'ahrs.Invalid' constant references. 2017-06-05 14:55:25 -04:00
Christopher Young e43caad938 Typo fix. 2017-06-05 14:48:10 -04:00
Christopher Young 6e184a9ce7 Merge remote-tracking branch 'origin/master' into ahrs_dev 2017-06-04 00:35:53 -04:00
cyoung e2b3529f95 Merge pull request #611 from peepsnet/master
Hostapd_manager.sh, sdr-tool.sh and  .stxAliases updates
2017-06-04 00:35:34 -04:00
Eric Westphal 255c1695e5 Better rejection of weak GPS in SimpleAHRS static mode. 2017-06-03 15:50:05 -04:00
peepsnet da8c3a74fd Restart Stratux on exit
The script will now restart your stratux service if you exit the script before completing.

And some aesthetics things
2017-06-03 11:27:50 -04:00
Eric Westphal 586d951582 Save sensor orientation for pseudo-installed units. 2017-06-01 17:33:18 -04:00
peepsnet 94d8f8813e Update hostapd_manager.sh 2017-06-01 15:20:01 -04:00
Eric Westphal 84d578ff6c Heading slews more quickly when movement begins. 2017-06-01 14:08:49 -04:00
peepsnet 321273f8d4 added an easy alias for securing/opening WiFI
Added "open" and "secure" as aliases to easily open or secure your WiFi

It simply calls the hostapd_manager.sh script with either -o or -e
2017-06-01 10:49:55 -04:00
peepsnet a72219bae5 Added encryption back to script
Help documentation for hostapd_manager.sh.

Basic usage: hostapd_manager.sh -s ssid -c chan -p pass

The following command line switches are recognized.
-s  --Sets the SSID to ssid. "-s stratux"
-c  --Sets the channel to chan. "-c 1"
-o  --Turns off encryption and sets network to open. Cannot be used with -e or -p.
-e  --Turns on encryption with passphrase SquawkDirtyToMe!. Cannot be used with -o or -p
-p  --Turns on encryption with your chosen passphrase pass. 8-63 Printable Characters(ascii 32-126). Cannot be used with -o or -e. "-p password!"
-q  --Run silently. Still a work in progress, but quieter.
-h  --Displays this help message. No further functions are performed.

Example: hostapd_manager.sh -s Stratux-N3558D -c 5 -p SquawkDirty!
2017-06-01 10:28:22 -04:00
peepsnet 95d0b97564 updating to add encryption back.
It seems to work in my testing!!

#### Stratux HOSTAPD Settings ####


Help documentation for hostapd_manager.sh.

Basic usage: hostapd_manager.sh -s ssid -c chan -p pass

The following command line switches are recognized.
-s  --Sets the SSID to ssid. "-s stratux"
-c  --Sets the channel to chan. "-c 1"
-o  --Turns off encryption and sets network to open. Cannot be used with -e or -p.
-e  --Turns on encryption with passphrase SquawkDirtyToMe!{NORM}. Cannot be used with -o or -p
-p  --Turns on encryption with your chosen passphrase pass. 8-63 Printable Characters(ascii 32-126). Cannot be used with -o or -e. "-p password!"
-q  --Run silently. Still a work in progress, but quieter.
-h  --Displays this help message. No further functions are performed.

Example: hostapd_manager.sh -s Stratux-N3558D -c 5 -p SquawkDirtyToMe!
2017-06-01 10:15:23 -04:00
peepsnet b5f18aa529 Merge pull request #9 from cyoung/master
updating
2017-06-01 10:05:45 -04:00
Christopher Young 9c602d97cf Merge branch 'ahrs_dev' into ahrs_dev_protocolfun 2017-05-31 16:19:16 -04:00
Christopher Young 48bccdc81e Merge remote-tracking branch 'origin/ahrs_dev_protocolfun' into ahrs_dev 2017-05-31 16:18:40 -04:00
Christopher Young 0a60929cab Typo fix. 2017-05-31 15:37:14 -04:00
Christopher Young f4144710e9 Update comments. 2017-05-31 15:34:57 -04:00
Christopher Young c0a79700b8 Change calcGPSValidity() to isGPSGroundTrackValid(). Replace existing isGPSGroundTrackValid() function. 2017-05-31 15:33:19 -04:00
Christopher Young 9839e88e71 Merge remote-tracking branch 'origin/master' into ahrs_dev 2017-05-31 15:21:37 -04:00
Eric Westphal db8d2f3e7f Add a bit more AHRS logging. 2017-05-29 20:32:50 -04:00
Eric Westphal 5f5f236b6e AHRSSimple ensures quaternion has correct sign to avoid split S. 2017-05-29 20:23:15 -04:00
Eric Westphal e421d160b7 Base AHRS GPS Validity on NACp. 2017-05-29 15:56:16 -04:00
Eric Westphal c96f3d4844 Extra AHRS logging from external sources. 2017-05-29 15:53:06 -04:00
Eric Westphal 22ad90fb8a Don't show AHRS info when it's invalid. 2017-05-29 15:50:54 -04:00
Eric Westphal fcc9322a57 Remove minor unneeded logging. 2017-05-29 15:44:34 -04:00
Christopher Young 053d60110f Typo fix. 2017-05-25 21:48:23 -04:00
Christopher Young 5bb15527f4 Merge remote-tracking branch 'origin/master' into ahrs_dev_protocolfun 2017-05-24 21:44:28 -04:00
Christopher Young 506db50fb2 Merge remote-tracking branch 'origin/master' into ahrs_dev 2017-05-24 21:44:11 -04:00
Christopher Young c3e4d613ca Remove full speed defaults.
#599, #595, #593.
2017-05-24 21:42:11 -04:00
Christopher Young daee7316f5 Switch from "BAL" mode to "MS" PWM modes. #599, #595, #593. 2017-05-24 13:25:52 -04:00
Christopher Young 4c854999bb Reduce number of fan modes to 10 from 256. Add five second run-up at startup. #599, #595, #593. 2017-05-24 13:24:46 -04:00
Christopher Young 7c33203672 Add missing files from update scripts. 2017-05-23 17:32:36 -04:00
Christopher Young b812c29996 Update make clean. 2017-05-23 17:11:44 -04:00
Christopher Young 93a2d82f96 Update install and auto-start scripts. 2017-05-23 17:06:50 -04:00
Christopher Young 9989b913bc Change IP Stratux IP address and DHCP range. 2017-05-23 17:04:29 -04:00
Christopher Young 7ac549a540 Typo and path fix. 2017-05-23 17:03:11 -04:00
Christopher Young 3f72b1e18b Remove old AHRS replay tools. Add protocol tools. 2017-05-23 16:56:18 -04:00
Eric Westphal 46233e704c Merge branch 'master' into ahrs_dev 2017-05-21 21:52:02 -04:00
Eric Westphal ac386cb0a1 Add AHRS setting defaults to defaultConfig. 2017-05-21 21:51:40 -04:00
Eric Westphal 436a6ccdb2 Merge branch 'gpsnan' 2017-05-21 20:23:05 -04:00
Eric Westphal 9f7775f580 Merge branch 'gpsnan' into ahrs_dev 2017-05-21 20:22:43 -04:00
Eric Westphal 7e89eb0abb G-Meter invalid zone fixed. 2017-05-21 19:12:41 -04:00
Eric Westphal 3e07390bac GPS map transparent and values -- when no GPS fix. 2017-05-21 17:13:42 -04:00
Eric Westphal b89bf75b07 Merge branch 'master' into glimits 2017-05-20 22:20:32 -04:00
Eric Westphal 6b4ab9b1a4 Merge branch 'master' into gpsnan 2017-05-20 22:19:10 -04:00
Eric Westphal 14e5c49e57 Add fancontrol to .gitignore. 2017-05-20 22:04:57 -04:00
Eric Westphal 51d7530208 Web UI shows -- and inf when GPS values missing. 2017-05-20 21:58:51 -04:00
Eric Westphal d69e195489 Use appropriate defaults for AHRS config. 2017-05-20 08:07:41 -04:00
Eric Westphal 4bc1bbe394 Merge branch 'ahrs_dev' 2017-05-20 07:36:07 -04:00
Eric Westphal 5aefc145ac Initial commit - user can set G limits for own aircraft. 2017-05-20 07:35:40 -04:00
Eric Westphal 9ebe32e6e0 Move SetConfig into AHRSProvider. 2017-05-17 19:41:01 -04:00
Eric Westphal 2a1a938194 Change AHRS Smoothness label. 2017-05-17 19:18:41 -04:00
Eric Westphal 9264dd4908 Merge branch 'ahrs_dev' into eric 2017-05-17 18:28:20 -04:00
Eric Westphal 71094ae189 Merge branch 'ahrs_dev' 2017-05-17 18:28:12 -04:00
Eric Westphal a4a7ea1912 Prevent G Meter from resetting on webpage changes. 2017-05-17 18:27:45 -04:00
Eric Westphal 52e61ca48c Merge remote-tracking branch 'cyoung/ahrs_dev' into eric 2017-05-17 18:26:56 -04:00
Eric Westphal 06f0d2d8f9 Merge remote-tracking branch 'origin/master' 2017-05-17 17:56:53 -04:00
Eric Westphal 8aeb5d285b Web UI G-Meter uses mySituation min/max G Load. 2017-05-17 17:55:42 -04:00
Eric Westphal e8273544ae mySituation tracks min/max G Load. 2017-05-17 17:55:42 -04:00
Eric Westphal c1ca21e8fb Web UI G-Meter uses mySituation min/max G Load. 2017-05-17 17:54:32 -04:00
Eric Westphal 20c1e32ff7 mySituation tracks min/max G Load. 2017-05-17 17:32:05 -04:00
Christopher Young 0678955b01 Merge remote-tracking branch 'origin/master' into ahrs_dev 2017-05-17 17:18:30 -04:00
Christopher Young f2c311db6d If temperature rises after ramping to 100% PWM, then stop controlling the fan and set it to full ON.
#599, #595, #593.
2017-05-17 17:18:00 -04:00
Christopher Young 0d146d1747 Set GDL90 traffic alert bit always when bearing/distance is not available. #580, #582. 2017-05-17 15:25:14 -04:00
Christopher Young 83f0c6843f Suppress detected ownship traffic target, but don't use received data for GDL90 ownship message.
#590.
2017-05-17 15:12:22 -04:00
Christopher Young 069cb9e1fc Undo cab2a81.
See commit comments:
cab2a81
9ca4549ba.

A static build of wiringPi is all that is needed to produce the static
binary. Static linking is needed to produce a working binary on current
production images.
2017-05-16 23:50:35 -04:00
Christopher Young fcfe8adeaf Undo cab2a81c26.
See commit comments:
https://github.com/cyoung/stratux/commit/cab2a81c26f214709f8cda941ff8ea1
9ca4549ba.

A static build of wiringPi is all that is needed to produce the static
binary. Static linking is needed to produce a working binary on current
production images.
2017-05-16 23:40:48 -04:00
Eric Westphal 50a0443f74 Merge branch 'ahrs_dev' into eric 2017-05-16 16:57:28 -04:00
Eric Westphal 1e40573d1e Merge branch 'ahrs_dev' 2017-05-16 16:57:17 -04:00
Eric Westphal 8c0364c04a Move NoSleep instance into . 2017-05-16 16:57:08 -04:00
Eric Westphal 28225dc343 Move AHRS Settings into Developer section. 2017-05-16 16:50:54 -04:00
Eric Westphal a0bea25d68 Merge branch 'ahrs_dev' into eric 2017-05-16 15:05:56 -04:00
Eric Westphal d7cafb0a8a Merge branch 'ahrs_dev' 2017-05-16 15:05:35 -04:00
Eric Westphal 4a038f5317 Headings 0-359 and keep app awake in AHRS-only mode. 2017-05-16 15:05:12 -04:00
Eric Westphal 7cd00ce4b5 Merge remote-tracking branch 'origin/master' into eric 2017-05-16 14:34:45 -04:00
Eric Westphal 834eeefc7c Update goflying submodule to compatible version. 2017-05-16 16:04:03 +00:00
Eric Westphal 115edcef28 Update goflying submodule to compatible version. 2017-05-16 16:03:30 +00:00
Eric Westphal a08d269e4c Merge remote-tracking branch 'cyoung/ahrs_dev' into eric 2017-05-16 10:50:19 -04:00
Christopher Young 3db11bd09d Add goflying submodule. Change imports. 2017-05-15 22:22:32 -04:00
Eric Westphal 58389f8ec5 Merge branch 'ahrs_dev' into eric 2017-05-15 20:35:04 -04:00
Eric Westphal cab2a81c26 Revert Makefile back to non-static fancontrol. 2017-05-15 20:34:55 -04:00
Eric Westphal be84ec785c Merge remote-tracking branch 'cyoung/ahrs_dev' into eric 2017-05-15 07:55:23 -04:00
Eric Westphal ea657208c0 Merge remote-tracking branch 'cyoung/ahrs_dev' into ahrs_dev 2017-05-14 09:44:15 -04:00
Eric Westphal d84a3a0199 Merge branch 'invalid' into eric 2017-05-14 09:25:48 -04:00
Eric Westphal 7add14badf Invalidate GDL90 UDP values when AHRS data invalid. 2017-05-14 09:25:11 -04:00
Eric Westphal 84eea16eed Merge branch 'invalid' into eric 2017-05-14 08:17:26 -04:00
Christopher Young 95fe19902a Merge remote-tracking branch 'origin/master' into ahrs_dev 2017-05-13 18:43:54 -04:00
Christopher Young 7ef5efdd6e Make fancontrol a static executable (for systems without wiringPi installed). 2017-05-13 18:43:43 -04:00
Christopher Young c6e96b5d09 Merge remote-tracking branch 'origin/master' into ahrs_dev
# Conflicts:
#	Makefile
#	main/equations.go
#	main/gen_gdl90.go
2017-05-13 12:37:06 -04:00
Christopher Young d242233e6d Ignore errors on 'remove'. #593. 2017-05-13 12:21:41 -04:00
Christopher Young ae03336a0b Reduce CPU temperature target to 50ºC. #593. 2017-05-13 12:16:20 -04:00
Christopher Young eebb040e1e Remove GPS power save mode. 2017-05-13 12:15:42 -04:00
Christopher Young b423c4e48e Change pinout. Increase PWM frequency. Decrease min duty cycle.
#593.
2017-05-13 12:11:31 -04:00
Christopher Young 5a83452c64 Skip fancontrol build on CircleCI - no wiringPi equivalent on x86.
#593.
2017-05-13 11:01:52 -04:00
Christopher Young 200b3fcf57 Add wiringPi to CircleCI install.
#593.
2017-05-13 10:40:56 -04:00
Christopher Young c7f0ed1245 Re-add CircleCI hack.
#593.
2017-05-13 10:35:21 -04:00
Christopher Young 29c86d0343 Formatting.
#593.
2017-05-13 10:33:09 -04:00
Christopher Young 0264383389 Add new fancontrol install to .sh update packager and image maker script.
#593.
2017-05-13 10:24:12 -04:00
cyoung 5ae514e5ce Merge pull request #593 from lukepalmer/master
Rework fan PWM control
2017-05-13 10:15:27 -04:00
Eric Westphal 70236a95da Show --- on web UI when AHRS values invalid. 2017-05-13 08:40:19 -04:00
Eric Westphal 338f1cc934 AHRS settings in the UI 2017-05-12 20:40:53 -04:00
Luke Palmer 01cc01f8fa Rework fan PWM control 2017-05-11 00:32:45 -04:00
Christopher Young a6f9aaf9f5 TEMPORARY: get latest 'goflying' packages in Makefile. 2017-05-10 09:43:57 -04:00
Christopher Young d7ca5b0376 Undo merge typo. 2017-05-10 09:42:20 -04:00
Christopher Young 17b719f755 Merge remote-tracking branch 'origin/master' into ahrs_dev
# Conflicts:
#	main/gps.go
#	main/traffic.go
2017-05-10 09:27:22 -04:00
cyoung 7933b70821 Merge pull request #592 from westphae/master
WebUI and dependency changes.
2017-05-09 10:28:14 -04:00
Eric Westphal 449043bb4a Refactor rotation matrix creation function to westphae/goflying. 2017-05-08 21:21:37 -04:00
Eric Westphal 6127d4f70f Only report turn tate < 10 min/turn on web UI. 2017-04-22 18:37:03 -04:00
Eric Westphal f8187e1383 Report fixed digits for AHRS info on web UI. 2017-04-22 18:20:09 -04:00
Eric Westphal c113876821 Restore GPS uncertainties on web UI. 2017-04-22 18:08:52 -04:00
Christopher Young 7d7c2abe35 Gofmt. Typo fix. Comment change. 2017-04-21 14:16:21 -04:00
cyoung 1934d858de Merge pull request #586 from kjablonski/master
Enable Galileo and updates to stratux-help
2017-04-21 14:08:39 -04:00
kjablonski e3fcadb4ba Update gps.go
Fixed undeclared variable updatespeed
2017-04-21 06:57:18 -05:00
kjablonski a8bd9a28f9 Update gps.go
Added logic to only slow down to 2Hz for UBX8 using Galileo
2017-04-20 21:42:45 -05:00
Christopher Young 176cf42f2e Blink ACT LED ten times per second when there is a system error.
#567.
2017-04-19 17:04:12 -04:00
Christopher Young c0b6e9a93b Set "Maintenance Req'd" bit in GDL90 heartbeat when there exists a system error.
#567.
2017-04-19 16:49:35 -04:00
Christopher Young b431187d7a Use isGPSValid(). 2017-04-19 16:01:29 -04:00
Christopher Young fe7dc97c19 Clean up typos and formatting. 2017-04-19 15:57:25 -04:00
Christopher Young 2645f98293 Cleanup. 2017-04-19 15:51:49 -04:00
Eric Westphal 95ade5a64b Rename Reset AHRS Button for the last time. 2017-04-16 20:13:55 -05:00
Christopher Young 9e12f69318 Add comments on units and constants.
#580, #582.
2017-04-06 11:28:56 -04:00
Christopher Young f564f2bb6b Remove redundant distance calculation. 2017-04-06 11:27:03 -04:00
Christopher Young 93321a4f8f Reset Distance, Bearing, and BearingDist_valid if GPS data becomes invalid.
#580, #582.
2017-04-06 11:26:51 -04:00
Christopher Young 5d5f165218 Formatting.
Use gofmt after edits. #580, #582.
2017-04-06 11:24:46 -04:00
cyoung dfee391e66 Merge pull request #582 from ChiefPilot/master
Remove hardcoded alert flag on traffic report and replace with simple…
2017-04-06 11:24:01 -04:00
Eric Westphal fc438c0b30 mySituation AHRS and Baro variables now float32 for iOS. 2017-04-05 20:30:16 -04:00
Christopher Young 1fca793b2c Merge remote-tracking branch 'origin/master' into ahrs_dev
# Conflicts:
#	main/gen_gdl90.go
2017-04-04 20:55:57 -04:00
Christopher Young 744939d940 Add log comment on CPU profile option. 2017-04-04 20:55:03 -04:00
Christopher Young a6ded9a5c0 Add -cpuprofile command line option. 2017-04-04 20:52:22 -04:00
Christopher Young 171ab4a21e Merge fix. 2017-04-04 16:28:44 -04:00
Christopher Young 29b959afa9 Merge remote-tracking branch 'origin/master' into ahrs_dev
# Conflicts:
#	main/gen_gdl90.go
#	main/gps.go
#	main/managementinterface.go
#	main/network.go
#	web/js/main.js
#	web/plates/developer.html
#	web/plates/gps.html
#	web/plates/js/developer.js
#	web/plates/js/gps.js
#	web/plates/js/settings.js
#	web/plates/js/status.js
#	web/plates/status-help.html
#	web/plates/status.html
#	web/plates/traffic-help.html
2017-04-04 13:16:32 -04:00
Eric Westphal bc54533351 Ease up on the cpu. 2017-04-04 11:20:28 -04:00
kjablonski 64dca38480 Merge pull request #1 from cyoung/master
Merge Cyoung
2017-04-03 14:17:27 -05:00
kjablonski b8dd5d7b2c Update stxAliases.txt
Typo fixes
2017-04-03 14:12:18 -05:00
Brad Benson 24d20e7cdb Remove hardcoded alert flag on traffic report and replace with simple logic to set it only if a target is within 2nm. This addresses issue #580 . 2017-04-03 14:10:12 -05:00
Eric Westphal 23df9c9c2e Slip/skid indicates correctly in UDP; limit UI slip/skid to 10 deg max. 2017-04-02 10:26:23 -04:00
Eric Westphal ac6da35e3b Tidy up UI Status page, display CPU stats always. 2017-04-02 10:09:16 -04:00
Eric Westphal b9ebc3b39e Sensor values in arrays instead of scalars. 2017-04-01 19:21:12 -04:00
Eric Westphal 9b7212ed11 More robust acceleration detection for orientation. 2017-04-01 19:00:28 -04:00
Eric Westphal a2580d4593 AHRS auto-level working. 2017-04-01 14:02:12 -04:00
Eric Westphal 1961a3cc8c Remove some old comments. 2017-04-01 09:19:01 -04:00
Eric Westphal effa8da5a9 Decompose rotation matrix into x, y, z basis vectors. 2017-04-01 09:14:13 -04:00
Eric Westphal a998ede17b Merge branch 'ahrs_dev' 2017-04-01 08:35:34 -04:00
Eric Westphal 18af334813 Extract sensor rotation matrix creation into function. 2017-04-01 08:27:45 -04:00
Eric Westphal 6220a2dfe3 Change Situation field names to more explanatory scheme. 2017-03-30 19:20:49 -04:00
Eric Westphal c12aa3e728 Merge pull request #24 from cyoung/ahrs_dev
Fix nil pointer dereference crash.
2017-03-30 08:12:33 -04:00
Christopher Young bcd62e7c00 ssd1306 python driver - version change. 2017-03-28 17:18:53 -04:00
Christopher Young 7efcefcf3f Fix screen towers count - display only active. 2017-03-28 17:11:03 -04:00
Christopher Young f2c6c23c8e Remove auto-expand code. Increases microSD card failures. 2017-03-28 15:57:10 -04:00
Christopher Young a11b0b9be4 Formatting.
Run gofmt on modified files.
2017-03-28 11:57:32 -04:00
Christopher Young 89b848c3e5 Fix nil pointer dereference when sensor is not connected/initialized and webUI sensor option is disabled.
2017/03/28 13:43:00 wrote settings.
2017/03/28 13:43:01 http: panic serving 192.168.10.12:52012: runtime
error: invalid memory address or nil pointer dereference
goroutine 83 [running]:
net/http.(*conn).serve.func1(0x10ab6ae0, 0x73826140, 0x10d8c708)
	/root/go-1.5.1/src/net/http/server.go:1287 +0x9c
main.handleSettingsSetRequest(0x72ec00b0, 0x10d93580, 0x10db0620)
	/root/stratux-westphae/main/managementinterface.go:286 +0x1620
net/http.HandlerFunc.ServeHTTP(0x5d2ecc, 0x72ec00b0, 0x10d93580,
0x10db0620)
	/root/go-1.5.1/src/net/http/server.go:1422 +0x34
net/http.(*ServeMux).ServeHTTP(0x10960dc0, 0x72ec00b0, 0x10d93580,
0x10db0620)
	/root/go-1.5.1/src/net/http/server.go:1699 +0x164
net/http.serverHandler.ServeHTTP(0x109c4300, 0x72ec00b0, 0x10d93580,
0x10db0620)
	/root/go-1.5.1/src/net/http/server.go:1862 +0x190
net/http.(*conn).serve(0x10ab6ae0)
	/root/go-1.5.1/src/net/http/server.go:1361 +0xbfc
created by net/http.(*Server).Serve
	/root/go-1.5.1/src/net/http/server.go:1910 +0x360
2017/03/28 13:43:01 http: panic serving 192.168.10.12:52013: runtime
error: invalid memory address or nil pointer dereference
goroutine 58 [running]:
net/http.(*conn).serve.func1(0x1098b4a0, 0x73826140, 0x10de8228)
	/root/go-1.5.1/src/net/http/server.go:1287 +0x9c
main.handleSettingsSetRequest(0x72ec00b0, 0x10d93680, 0x10db0690)
	/root/stratux-westphae/main/managementinterface.go:286 +0x1620
net/http.HandlerFunc.ServeHTTP(0x5d2ecc, 0x72ec00b0, 0x10d93680,
0x10db0690)
	/root/go-1.5.1/src/net/http/server.go:1422 +0x34
net/http.(*ServeMux).ServeHTTP(0x10960dc0, 0x72ec00b0, 0x10d93680,
0x10db0690)
	/root/go-1.5.1/src/net/http/server.go:1699 +0x164
net/http.serverHandler.ServeHTTP(0x109c4300, 0x72ec00b0, 0x10d93680,
0x10db0690)
	/root/go-1.5.1/src/net/http/server.go:1862 +0x190
net/http.(*conn).serve(0x1098b4a0)
	/root/go-1.5.1/src/net/http/server.go:1361 +0xbfc
created by net/http.(*Server).Serve
	/root/go-1.5.1/src/net/http/server.go:1910 +0x360
2017-03-28 11:54:27 -04:00
cyoung 99e61dc343 Merge pull request #578 from westphae/master
Merge westphae/stratux:master into cyoung/stratux:ahrs_dev.
2017-03-28 11:41:59 -04:00
kjablonski 992367e50a Updates to gps.go
tweaks after testing on stratux
2017-03-27 21:49:01 -05:00
kjablonski aaf2025968 Update gps.go 2017-03-26 21:59:56 -05:00
kjablonski 1d33f79e04 More Galileo Updates
Updated sv numbers and added text to indicated Galileo in solution E#
2017-03-26 21:50:14 -05:00
Eric Westphal 9e101b4cf5 Minor ahrs.js name changes. 2017-03-26 20:44:42 -04:00
Eric Westphal 1904227438 Use websocket for gps/ahrs instead of GET polling. 2017-03-26 20:38:36 -04:00
kjablonski 0207ede47d Update gps.go
Added support for Galileo GNSS constellation
2017-03-26 19:15:31 -05:00
Eric Westphal bef3f475da Minor reformatting of gps.js. 2017-03-26 19:54:28 -04:00
Eric Westphal 7cca9a1bbc AHRS indicator lights red if stratux disconnects. 2017-03-26 19:42:15 -04:00
Eric Westphal a23a29fdfd Improved formatting of calibration warning message. 2017-03-25 22:55:19 -04:00
Eric Westphal ae92bae0d3 Resetting AHRS now turns of AI and displays calibration warning. 2017-03-25 18:24:51 -04:00
Christopher Young 7e0205be17 Limit main CPU to 900 MHz and set "sdram_freq" / "core_freq" as in pre-Jessie.
Issue #573.
2017-03-20 15:27:26 -04:00
Eric Westphal 63ce795340 web Makefile tried to copy nonexistent file. 2017-03-19 21:50:15 -05:00
Eric Westphal 551b2fc3e9 AI headings above 360 modded by 360. 2017-03-16 17:33:59 -04:00
Eric Westphal 2a40f80e5e Relabel cage button on AHRS UI page. 2017-03-14 19:33:21 -04:00
Eric Westphal adfa54813a Change Heading label to Track on AHRS UI. 2017-03-13 19:29:30 -04:00
Eric Westphal 9fefa4c3ff Create ai svg in javascript. 2017-03-12 22:27:24 -04:00
Eric Westphal ef8064c09f IMU->ATT and BMP->ALT on UI indicators. 2017-03-12 18:21:20 -04:00
Eric Westphal 571bec5a57 Make sure G Meter resets fully on power-up. 2017-03-11 19:39:49 -05:00
Eric Westphal d625f50446 Add arcs to g meter between max and min. 2017-03-11 09:20:26 -05:00
Eric Westphal f25df87825 Add G Meter to UI. 2017-03-10 22:03:35 -05:00
Eric Westphal 8ce402a33f Add AHRS status indicators to web UI. 2017-03-09 21:43:26 -05:00
Eric Westphal 5f8718c96a Reorder AHRS updates. 2017-03-09 21:41:45 -05:00
Eric Westphal cd314682eb Better orientation routine. 2017-03-09 21:40:21 -05:00
Eric Westphal 234dcb3726 Initial display of MagHeading, Slip/Skid, TurnRate, GLoad on web UI. 2017-03-08 18:11:05 -05:00
Eric Westphal d2526efc7c Slightly smarter sensor failure detection. 2017-03-08 18:10:13 -05:00
Eric Westphal 36595433be AHRSProvider calcs supplemental AHRS info instead of sensor. 2017-03-08 17:16:29 -05:00
Eric Westphal e78146ab99 Change "Calibration" to "Orientation" in UI. 2017-03-05 22:11:52 -05:00
Eric Westphal 3e43c1f69e AHRSLogger logs only if disk usage < 95%. 2017-03-05 19:07:01 -05:00
Eric Westphal 5667c1a871 All logs go to /root/ for FlightBox. 2017-03-05 18:56:11 -05:00
Eric Westphal f1ff15031f Add UI switch to record AHRS logs. 2017-03-05 18:34:25 -05:00
Eric Westphal 1344515c93 Separate UI switches for BMP and IMU connected. 2017-03-05 17:47:38 -05:00
Eric Westphal c34592e347 Refactor ahrs.InitializeSimple to separate logging from initialization. 2017-03-05 09:16:50 -05:00
Eric Westphal 043f334dc2 More robust initialization of baro ewma for ROC calc. 2017-03-05 09:13:18 -05:00
cyoung 0360e506ec Use netMutex to protect dhcpLeases, pingResponse, and outSockets. 2017-03-03 11:00:05 -05:00
cyoung 7631543b1a Merge pull request #566 from AvSquirrel/uat-traffic-improvements
UAT traffic decoding improvements
2017-03-03 09:56:58 -05:00
Eric Westphal 3d0ce092ab Re-run sensor calibration when caged. 2017-02-27 20:59:05 -05:00
Eric Westphal 787250b95f Slightly better location for stopping AHRS. 2017-02-27 20:58:45 -05:00
Eric Westphal cd6b708007 Better AHRS initialization behavior when sensors not yet calibrated. 2017-02-27 20:34:02 -05:00
Eric Westphal 4d31c3940c Initialize AHRSProvider using modified Reset interface. 2017-02-27 20:28:05 -05:00
Eric Westphal e397305fd0 MPU9250 correctly handles a zero calibration duration. 2017-02-27 19:57:01 -05:00
Eric Westphal 4bd6544cc0 AHRS_Provider gets a Reset method. 2017-02-27 18:07:14 -05:00
Eric Westphal 384cf16996 Move AHRS orientation explanation into help. 2017-02-23 14:41:39 -05:00
Eric Westphal b20302dff2 Cage button friendlier to data on web UI. 2017-02-23 14:41:03 -05:00
Eric Westphal 34396a36e5 Fix panic and lack of reconnect when Sensors switch toggled. 2017-02-22 16:54:13 -05:00
Eric Westphal f39c58ca3d netMutex becomes RWMutex, protects some additional reads. 2017-02-22 15:10:15 -05:00
cyoung acbe7742b2 Join DXF logo segments into polylines. 2017-02-17 12:57:04 -05:00
Eric Westphal 2ba3f136bb Change http status messages for go1.5.1 compatibility. 2017-02-17 11:11:27 -05:00
Eric Westphal f2cfe3344b Re-do sensor orientation setting method. 2017-02-16 16:57:30 -05:00
Eric Westphal e78afed4d4 Remove SensorLogger, some log messages. 2017-02-16 16:56:42 -05:00
Eric Westphal 2cf49218bd Increase GPS update cycle to 10Hz. 2017-02-15 16:10:52 -05:00
Eric Westphal 079dfc0e00 Increase AHRS calculation cycle to 20Hz for 10Hz GPS updates. 2017-02-15 16:09:09 -05:00
Christopher Young 4b63351c9c Disable hciuart. 2017-02-15 02:37:59 -05:00
Eric Westphal 9b180e2f25 AHRS tracks GPS time separately from sensor time. 2017-02-13 16:01:43 -05:00
Eric Westphal a5aa50f44f AHRS logging uses AHRSProvider built-in logging. 2017-02-13 15:15:45 -05:00
Eric Westphal 261dd637e0 Missing continue. 2017-02-13 14:26:29 -05:00
Keith Tschohl 71a9c06a29 Add parsing of UAT SIL, SDA, NACv, and In capability to verbose logs 2017-02-13 04:26:15 +00:00
Keith Tschohl 318e883db5 Add emergency status to traffic msgs; additional UAT statistics; cleanup 2017-02-13 03:37:51 +00:00
Eric Westphal 99cdda2219 ahrsweb Kalman Listener Send fails more nicely. 2017-02-12 17:06:36 -05:00
Eric Westphal 5ab394b31d Add Cage button to Attitude Indicator/AHRS. 2017-02-12 17:06:03 -05:00
Eric Westphal 59da452770 Add mutex to pingResponse map to prevent panics with Go>1.5. 2017-02-11 15:20:47 -05:00
Eric Westphal b3dd98cd76 AHRS attitude indicator displays tenth of degree changes. 2017-02-10 23:14:19 -05:00
Eric Westphal d17e218324 gdl90Report uses Gyro_heading. 2017-02-10 16:45:55 -05:00
Keith Tschohl 950c0594bf Disable sqlite logs when using UAT playback 2017-02-10 06:28:22 +00:00
Keith Tschohl f423f2c74e Determine UAT version. Proper decoding of callsign vs Mode 3/A code 2017-02-10 06:17:27 +00:00
Keith Tschohl dae0a29278 Add UAT traffic message decoder and v2 message documentation 2017-02-10 04:09:14 +00:00
Keith Tschohl 4201bb1ec3 Fix UAT track calculation when one velocity component = 0 2017-02-10 03:55:26 +00:00
Eric Westphal ba0440c49b Validate sensor calibration. 2017-02-07 21:35:59 -05:00
Eric Westphal ecd0ed5e2e bmp280 reads at the right frequency. 2017-02-07 21:35:21 -05:00
Christopher Young 239c473c9a Automatically expand root partition on first boot.
Compatible with .sh updates from previous versions via
`/etc/stratux.firstboot`.
2017-02-05 16:22:33 -05:00
cyoung 1ae6b5cb1f Merge pull request #514 from jamez70/developer_mode_add_loghandling
Added logfile truncation and download buttons to developer mdoe screen
2017-02-02 22:28:23 -05:00
cyoung a37d0f9ae3 Merge branch 'master' into developer_mode_add_loghandling 2017-02-02 22:28:16 -05:00
Christopher Young 6b10432240 dhcpcd disable. 2017-02-02 10:44:59 -05:00
Christopher Young d895772f6f Fix: systemd[1]: [/lib/systemd/system/stratux.service:8] Executable path is not absolute, ignoring: pkill dump1090 2017-02-02 10:07:56 -05:00
Christopher Young 6ec0b480bf Add hostapd_manager and stratux-wifi scripts to 'make install'. 2017-02-02 10:07:13 -05:00
cyoung dc074454c6 Merge pull request #555 from peepsnet/wifi-lag-fix
Wifi lag fix
2017-02-02 09:36:54 -05:00
cyoung 490e3d9900 Merge pull request #557 from AvSquirrel/10Hz-gps
GPS configuration and detection improvements
2017-01-30 00:27:24 -05:00
cyoung 9ee46170ff Merge pull request #556 from jonvadney/master
Add ability to set static ip from web ui when in dev mode
2017-01-29 20:32:17 -05:00
cyoung d8219c495d Merge pull request #559 from pmaag/traffic-help-additions
Added traffic type prefix definitions to traffic-help.html
2017-01-29 20:28:34 -05:00
Eric Westphal 5e0f586f8a Lighten logging, longer timeout for GPS. 2017-01-21 12:39:06 -05:00
Eric Westphal 0e14b82ddb Show CPU load on UI status page. 2017-01-16 22:25:26 -05:00
Eric Westphal b1351af740 A little more logging. 2017-01-16 18:25:53 -05:00
Eric Westphal 3c16945c92 Set orientation of AHRS sensor in UI. 2017-01-16 18:22:57 -05:00
Eric Westphal ed49f2c270 AHRS full-screen mode added. 2017-01-13 19:21:35 -05:00
Eric Westphal 541ce527a9 Add refresh UI function to developer mode. 2017-01-12 22:36:45 -05:00
Eric Westphal e0f794b907 AHRS calibration UI mostly done. 2017-01-08 23:04:16 -05:00
Eric Westphal 352c9eb79c sensorAttitudeSender is a little more robust. 2017-01-08 23:01:34 -05:00
Eric Westphal b6fef3ca9a sensors.go gets sensor orientation from globalSettings. 2017-01-08 12:11:51 -05:00
Eric Westphal af2ea7196b Make pressure reader work again. 2017-01-08 10:14:24 -05:00
Eric Westphal 816411b3ee Replace windoze CRLF with Linux LF in web files 2017-01-07 22:45:19 -05:00
Eric Westphal 22867df1f4 Improved GPS/AHRS UI layout 2017-01-07 08:29:33 -05:00
Eric Westphal a6642353d7 Add Enable_Sensors to settings UI 2017-01-07 08:05:37 -05:00
Eric Westphal 601efa9023 Start managementinterface earlier to avoid nil 2017-01-07 08:01:15 -05:00
Eric Westphal b615a0370b Move satelliteMutex into Situation alongside other Mutexes 2017-01-07 07:59:00 -05:00
pmaag f70a8c9525 Added traffic type prefix definitions to traffic-help.html
Added additional information to traffic-help.html to include the prefix
used when Show Traffic Source In Callsign is enabled within the
settings.

It was difficult to locate the definitions of each of the traffic type
prefixes, so I thought the help page would be a good location to define
these.

Additionally adjusted some spacing of the list elements to provide
easier readability on this help page.
2017-01-06 14:27:30 -08:00
Eric Westphal 9f9298734d Hack to avoid race condition, for now. 2017-01-05 23:01:00 -05:00
Eric Westphal 744c7bfe1c Replace paper airplane with attitude indicator in UI 2017-01-05 23:00:35 -05:00
Eric Westphal 84e81bbd3b Correct multiplier for climb rate 2016-12-29 15:12:19 -06:00
Eric Westphal c9c02e2e86 Change execution modes of non-executables 2016-12-29 06:43:00 -06:00
Eric Westphal 6c539a0f77 Merge branch 'dev' 2016-12-29 06:35:27 -06:00
Eric Westphal a3a811aa53 First working commit merging latest cyoung/master into westphae/dev 2016-12-29 06:33:11 -06:00
Keith Tschohl c7c6fb628b UI tweaks: Unbold 'Towers'. Suppress accuracy if disconnected / solution. Wordsmithing. 2016-12-26 21:25:56 +00:00
Keith Tschohl df22888465 Regression window tweaks 2016-12-26 15:54:05 +00:00
Keith Tschohl c67f4acb8c Update 'Status' help page. Make tabbing consistent. 2016-12-26 08:34:47 +00:00
Keith Tschohl 900ff0052e Status UI cleanup. Consolidate UAT stats, fix disappearing DIV for uptime / temp, add bytes free. 2016-12-26 08:07:52 +00:00
Keith Tschohl 7063c73ba7 Reset accuracy and NACp on GPS disconnect. Add sample rate to GPS UI page. 2016-12-26 07:30:46 +00:00
Keith Tschohl c84abec96f Report GPS position rate (Hz). Tweak gpsattitude filter. Cleanup. 2016-12-26 06:37:33 +00:00
Keith Tschohl c7ad7728d6 Add GPS hardware detection status to UI 2016-12-25 20:06:28 +00:00
Keith Tschohl 6544562913 Refined GPS detection. Updated gpsatttitude copyright notice 2016-12-25 19:00:01 +00:00
Keith Tschohl 529079368a 10 Hz default UBX config. Enable GLONASS multi-GNSS on UBX8 2016-12-25 08:36:40 +00:00
Jon Vadney 6198fc2ce3 add ability to set static ip from web ui when in dev mode 2016-12-25 07:03:56 +00:00
peepsnet 069db15e1e Update stratux-wifi.sh 2016-12-21 23:22:46 -05:00
peepsnet e5c694ac88 moved to function based
I moved all the code to functions and commented to reflect the file format
2016-12-21 22:46:55 -05:00
peepsnet 575d51c172 Removed encryption options
Since I am unable to get the encryption to work with the edimax I commented all the code out for now in hostapd_manager.sh
2016-12-21 22:45:23 -05:00
peepsnet 1b73935838 Added the hostpad.user creation code here 2016-12-21 12:17:21 -05:00
peepsnet 345350df82 Moving hostapd.user code 2016-12-21 12:10:24 -05:00
Jim Jacobsen 6de246d789 removed reopenLogFile it is unused 2016-12-20 22:57:09 -06:00
peepsnet b37a49948e Merge pull request #8 from cyoung/master
update master
2016-12-20 15:54:17 -05:00
cyoung 2b5037eb31 Merge pull request #553 from Helno/patch-1
Update fancontrol.py
2016-12-20 15:17:50 -05:00
Helno d4ed2d1b0c Update fancontrol.py
Update note on line 6 to reflect the currently used pin.
2016-12-20 11:58:59 -05:00
cyoung 5aeb10503e Merge pull request #550 from peepsnet/master
FIX Stratux so it works again!!! a.k.a. added stratux-wifi.sh to update scripts and correct pathing issue
2016-12-18 14:45:08 -05:00
peepsnet ac3a36251a Update interfaces 2016-12-18 11:53:27 -05:00
peepsnet ed1b908188 Cleaned up the comments
I cleaned up these comments and added the code that worked for me to get his running. I can now connect to my home wifi and cell phone hotspot with these settings.
2016-12-18 11:51:30 -05:00
peepsnet 806473455a simplify creating the tmp file 2016-12-18 11:12:19 -05:00
peepsnet eec6e2c7db nope 2016-12-18 09:53:55 -05:00
peepsnet 3b56dc7c3b added notes 2016-12-17 17:28:12 -05:00
peepsnet 6c927417c3 path typo
path typo for edimax driver
2016-12-17 15:40:43 -05:00
peepsnet 9957479024 Update makeupdate.sh 2016-12-17 15:31:17 -05:00
peepsnet e428800762 Update update_footer.sh 2016-12-17 15:30:06 -05:00
peepsnet cca83cd476 Merge pull request #7 from cyoung/master
update
2016-12-17 15:24:34 -05:00
Christopher Young 3e663c89c8 Limit number of traffic target reports sent in a single packet. 2016-12-14 20:52:16 -05:00
Eric Westphal cd2aadc0e3 Modifications for compatibility with simple AHRS 2016-12-12 18:12:40 -05:00
cyoung de93c79a07 Merge pull request #529 from peepsnet/master
Move user configurable options out of hostapd.conf and hostapd-edimax.conf to hostapd.user and build temp hoatapd.conf on the fly with stratux-wifi.sh
2016-12-12 14:39:33 -05:00
Christopher Young 720a7aad72 Clean up libimu ref. 2016-12-12 12:41:21 -05:00
cyoung 0107b59010 Merge pull request #544 from cyoung/gpsattitude
Promote gpsattitude to master.
2016-12-12 10:21:38 -05:00
Christopher Young ef56848715 Resolve conflicts. 2016-12-12 10:16:46 -05:00
Christopher Young 18de46745e Missing include. 2016-12-09 10:14:56 -05:00
Christopher Young 316cbf2329 Add DHCP lease directory write testing and webui error.
#500, #540.
2016-12-09 09:22:10 -05:00
cyoung beb3e04dd1 Merge pull request #542 from cyoung/use_modes
Use decoded ADS-B Out message from Ownship for Ownship 0x0A message d…
2016-12-09 08:58:29 -05:00
Christopher Young 9e8d20e3da Use decoded ADS-B Out message from Ownship for Ownship 0x0A message data, if available. 2016-12-02 10:57:40 -05:00
Christopher Young c19d32353f Typo. 2016-11-27 14:46:26 -05:00
peepsnet ed0cc5bd74 set a default passphrase if not choosen
Fixed the script to use a default passphrase("Squawk1200") if option -e used but no passphrase entered.
2016-11-24 12:00:24 -05:00
peepsnet a951410f3f Restart WiFi in script
This change now restarts the WiFI services in the script and no longer needs a restart!!
2016-11-24 11:48:14 -05:00
peepsnet 96a67ee5fc adding hostapd.user building code
Adding the code needed to update previous version of stratux with the new file structure needed while keeping custom user settings already used
2016-11-24 10:47:43 -05:00
peepsnet 469a413bb3 Change is logic placement
I removes all my code from this file and moved to stratux-pre-start.sh. This seems like a logical place to monkey around with stuff that must be ready for the start of stratux.
2016-11-24 10:41:50 -05:00
peepsnet 737df68e46 clean up 2016-11-24 00:00:52 -05:00
peepsnet 2ef42ea8d0 add sleep
add sleep to make sure the file write has time to finish before checking for the file
2016-11-23 23:51:18 -05:00
peepsnet 6c5352e3a1 clean up code 2016-11-23 23:35:14 -05:00
peepsnet 18b0bf53ef clean up 2016-11-23 23:31:03 -05:00
peepsnet 27db95f749 hopefully better speed 2016-11-23 22:09:35 -05:00
peepsnet e3e7fd7aab logic reorder 2016-11-23 21:20:42 -05:00
peepsnet 7b104be3dc formatting 2016-11-23 20:37:19 -05:00
peepsnet 94da60ed06 formatting 2016-11-23 19:35:36 -05:00
peepsnet 226b8442f7 Check for and handle hostapd.user
This script now not only starts hostapd using the proper driver(standard/edimax). 

It now checks for the existance of the hostapd.user file and if found uses it. if not found creates it with the values from the existing hostapd.conf

I choose to only carry over the values from the hostaod.conf and not the edimax because they should be the same. 

If there is no user configurable values in hostapd.conf and no hostapd.user file then a default hostapd.user file is created.
2016-11-23 19:22:18 -05:00
peepsnet 454da41fd2 Update stratux-wifi.sh 2016-11-23 17:25:21 -05:00
peepsnet d2c50f0921 Delete hostapd.user 2016-11-23 17:03:24 -05:00
peepsnet 31dc1a14fd user configurable hostapd values
this is where the user valies are stored and used to build /tmp/hostapd.conf
2016-11-23 17:01:28 -05:00
peepsnet 4a1ce917a3 update comments 2016-11-23 16:37:19 -05:00
peepsnet 3ad982e1c0 copy both hostapd.comf and hostapd-edimax.conf
this is now able because we moved the user configurable options away from the package files and build a temp hostapd.conf on the fly.
see https://github.com/cyoung/stratux/blob/master/image/stratux-wifi.sh
2016-11-23 16:13:35 -05:00
peepsnet d5afa25c69 Merge pull request #6 from cyoung/master
Standardize TODOs.
2016-11-23 16:10:36 -05:00
peepsnet c0a945bb88 edits hostapd.user
this file now edits hostapd.user to change user configurable values for hostapd
2016-11-23 15:54:49 -05:00
peepsnet 3cca4ba525 loading user config settings
update the file to create a tmp file that adds all the user config valuse to the hostapd.conf and uses the new /tmp/hostapd.conf to run the hostapd deamon
2016-11-23 15:52:44 -05:00
peepsnet 11f513c1da removed user configurable values 2016-11-23 15:50:55 -05:00
Christopher Young 5c70640eac Standardize TODOs. 2016-11-23 15:50:41 -05:00
peepsnet 9489933233 removed user configurable values
removed user configurable values to be placed in a global hosapd file
2016-11-23 15:50:32 -05:00
peepsnet a8b98677c3 Merge pull request #5 from cyoung/master
update
2016-11-23 15:49:12 -05:00
Eric Westphal d1607e0729 Support the BMP280 2016-11-23 10:34:41 -05:00
Christopher Young ff7a7a2781 Undo a few non-webui related changes. #531. 2016-11-22 23:33:39 -05:00
cyoung 8bf9347878 Merge pull request #531 from jamez70/move_timer_calls
Move timer calls to bottom of routines
2016-11-22 23:27:22 -05:00
Jim Jacobsen 1bf4de80a2 Move timer calls to bottom of routines, makes the web interface a lot more responsive 2016-11-23 03:14:45 +00:00
peepsnet d98d173e31 stop overwriting hostapd.conf on update
For some reason, this line was added and it caused the hostapd.conf(but not hostapd-edimax.conf) to be replaced at each update. This caused the users custom SSID and channel settings to be replaced!!
2016-11-19 11:03:37 -05:00
peepsnet 33c90e8da8 Merge pull request #4 from cyoung/master
update
2016-11-19 10:58:09 -05:00
Christopher Young ebfb671142 Rename ry835ai.go to gps.go. 2016-11-17 19:14:33 -05:00
Christopher Young 360845b454 Misc cleanup. 2016-11-17 19:10:59 -05:00
Christopher Young d7498169ed Misc cleanup. 2016-11-17 19:02:55 -05:00
Christopher Young 0ed4c0bfb7 Remove globalSettings.AHRS_Enabled. 2016-11-17 19:01:03 -05:00
Christopher Young d60248b660 Remove globalStatus.RY835AI_connected. 2016-11-17 18:56:15 -05:00
Christopher Young bc830b0a4e Remove mpu6050 references. 2016-11-17 18:49:18 -05:00
Christopher Young a47b1483c7 Remove linux-mpu9150 submodule. 2016-11-17 18:26:13 -05:00
Christopher Young eaea0178c2 Remove outdated FF compatibility warning. 2016-11-17 18:19:00 -05:00
Christopher Young 6c50a96347 Remove 'AHRS_GDL90_Enabled' option. 2016-11-17 18:18:16 -05:00
cyoung a473cca229 Merge pull request #527 from cyoung/master
Merge master.
2016-11-17 18:10:42 -05:00
Christopher Young 564bf93c63 Cleanup. #526. 2016-11-17 12:46:48 -05:00
Christopher Young 57e7c6d0a9 Formatting.
#526.
2016-11-17 12:43:47 -05:00
Christopher Young 83beb6dac1 Merge branch 'jamez70-gdl90-websocket-broadcaster' 2016-11-17 12:42:30 -05:00
Christopher Young 12df162b25 Manual merge. 2016-11-17 12:42:24 -05:00
cyoung 7d45737709 Merge pull request #516 from cyoung/stratux_websocket_support
Stratux websocket support. NEXRAD decoding added to uatparse.
2016-11-17 12:38:28 -05:00
Christopher Young b30f7094dc Formatting.
#525.
2016-11-17 10:54:30 -05:00
Christopher Young 2691fe714c Remove debug code.
#525.
2016-11-17 10:53:39 -05:00
cyoung 7b1dbf1975 Merge pull request #525 from jamez70/church-up-weather-status-page
Church up weather status page
2016-11-17 10:37:26 -05:00
Jim Jacobsen 7a801c6a06 oops again 2016-11-17 07:41:10 +00:00
Jim Jacobsen 2b3d06eafa Fixed JSON call 2016-11-17 07:25:36 +00:00
Jim Jacobsen 3a5a5e5048 GDL90 JSON interface stratux changes 2016-11-17 07:09:18 +00:00
Jim Jacobsen c5b18b79d9 More churching up, looks good 2016-11-17 06:58:36 +00:00
Jim Jacobsen e742ff0712 Add colors for wind, taf and pirep weather reports 2016-11-17 06:01:39 +00:00
Christopher Young 64836196cf Merge branch 'AvSquirrel-gpsattitude-june2016' into gpsattitude 2016-11-16 16:15:40 -05:00
Christopher Young a777e7d462 Manual merge. 2016-11-16 16:15:30 -05:00
cyoung 54204bab0d Merge pull request #524 from jamez70/gps_accuracy_meter_unit
Added 'm' specifier on unit for gps
2016-11-16 15:52:21 -05:00
Jim Jacobsen 9f195fa067 Was a bug, fixed now 2016-11-16 20:48:03 +00:00
Jim Jacobsen 71aea36e69 Added 'm' specifier on unit for gps 2016-11-16 20:42:09 +00:00
Christopher Young b67af3d191 Ping comments change. Added some data on recent tests. 2016-11-16 09:17:23 -05:00
cyoung 286fc27b84 Merge pull request #508 from uavionix/master
Add pingEFB text to README
2016-11-16 09:15:32 -05:00
Christopher Young 37e955474f Calculate data_item.time for report types other than WINDS. Don't calculate data age if greater than 2 days off.
#521.
2016-11-16 08:26:58 -05:00
Christopher Young 60b4b808ee Formatting.
#521.
2016-11-16 08:20:10 -05:00
cyoung 692157ecf5 Merge pull request #521 from jamez70/upper-winds-time-fix
Possible solution for upper level winds forecast time
2016-11-16 08:16:32 -05:00
cyoung b6fef657a2 Merge pull request #522 from jamez70/fix-font-weight
A font you can actually read on a tablet/phone
2016-11-15 09:55:22 -05:00
cyoung 6d9434d4b9 Merge pull request #519 from jamez70/fix_uat_status_layout
Updated UAT statistics
2016-11-15 09:37:32 -05:00
cyoung 49e252c270 Merge pull request #520 from jamez70/browser-cache-reload-possible-fix
Added seconds tag to stratux.appcache for page reloading if built cod…
2016-11-15 09:36:56 -05:00
Jim Jacobsen 7a980d7899 A font you can actually read on a tablet/phone 2016-11-14 05:55:30 +00:00
Jim Jacobsen b857c56a37 Possible solution for upper level winds forecast time 2016-11-14 05:07:16 +00:00
Jim Jacobsen 5058d0e4e1 Added seconds tag to stratux.appcache for page reloading if built code has changed 2016-11-14 05:00:38 +00:00
Jim Jacobsen d3a060a2de fixed incorrect color test html 2016-11-14 04:11:22 +00:00
Jim Jacobsen 380d13d383 Updated UAT statistics 2016-11-14 04:01:45 +00:00
Jim Jacobsen ff9c9966af Updated per suggestions and changes by ergonomicmike 2016-11-12 03:53:47 +00:00
peepsnet c77875493e Merge pull request #3 from cyoung/master
update
2016-10-27 08:34:13 -04:00
Christopher Young 33e9cb0b44 Change Intensity encoding. 2016-10-24 21:32:42 -04:00
Christopher Young 73d7cdbe1d weatherRawUpdate uibroadcast - send UATFrame as received. 2016-10-24 17:28:57 -04:00
Christopher Young 76e71bd6e5 Make NEXRADBlock fields exportable. 2016-10-24 17:14:06 -04:00
Christopher Young e0b123e426 Fixes. 2016-10-24 16:52:27 -04:00
Christopher Young b829e2228a Replaced NEXRAD processing. 2016-10-24 16:12:18 -04:00
Christopher Young 386be11b8c Subscribe /jsonio socket for situation updates. 2016-10-24 16:05:30 -04:00
Christopher Young f5ebf4c43d Use uibroadcast.SendJSON(). 2016-10-24 15:40:30 -04:00
Christopher Young a949bda34f Add mySituation uibroadcast. 2016-10-24 15:38:05 -04:00
Christopher Young 504d97ec7a Add SendJSON() to uibroadcaster. 2016-10-24 15:36:54 -04:00
Christopher Young 27206c0751 Formatting. 2016-10-24 15:28:44 -04:00
Christopher Young d433881b0b Formatting. 2016-10-24 15:27:48 -04:00
Christopher Young 04ee9d8b1b Formatting. 2016-10-24 15:22:57 -04:00
cyoung 5eb079dae6 Merge pull request #515 from jamez70/stratux_websocket_support
Initial support for NEXRAD data, added support for JSON types
2016-10-24 15:20:17 -04:00
Jim Jacobsen 7239e81418 Initial support for NEXRAD data, added support for JSON types 2016-10-23 23:38:13 -05:00
Jim Jacobsen 601e21c564 Added logfile truncation and download buttons to developer mdoe screen 2016-10-23 11:04:18 -05:00
cyoung 92e48862e2 Merge pull request #513 from jamez70/save_developermode
This saves developermode to settings when it is activated
2016-10-20 21:13:32 -04:00
Jim Jacobsen 1e9cff43c8 This saves developermode to settings when it is activated 2016-10-20 20:52:11 +00:00
cyoung b5ccfdc9ae Merge pull request #512 from jamez70/developer_mode_bugfix
Fixed typo with developer mode variable
2016-10-20 14:24:23 -04:00
Jim Jacobsen e4de2f5778 Fixed typo with developer mode variable 2016-10-20 18:17:31 +00:00
peepsnet af220df029 Merge pull request #2 from cyoung/master
update
2016-10-18 22:14:20 -04:00
Christopher Young 20ada0a9d7 Cleanup. 2016-10-18 20:29:31 -04:00
Christopher Young 32f0054f72 Formatting. 2016-10-18 20:27:14 -04:00
cyoung 2679c03472 Merge pull request #504 from jamez70/developer_mode_flag_handling
Developer mode flag handling
2016-10-18 20:19:04 -04:00
cyoung fc6e75adde Merge pull request #503 from peepsnet/master
Fixed the sleep function to lcase and a bit of look & feel
2016-10-18 20:18:33 -04:00
cyoung b9a9dd427d Merge pull request #510 from jamez70/fix_crash_in_issleeping
Fix crash in issleeping
2016-10-18 12:00:55 -04:00
Jim Jacobsen d1bb84327a reverted rules file 2016-10-17 22:34:32 -05:00
Jim Jacobsen 463ecafc38 Fixed bug with help of cyoung found with running on native linux, which may show itself on the RaspberryPi at some point 2016-10-17 22:30:43 -05:00
Jim Jacobsen 0f8e5810c6 Merge branch 'master' of github.com:cyoung/stratux 2016-10-14 21:11:30 -05:00
Jim Jacobsen 562529881d Merge branch 'master' of github.com:jamez70/stratux 2016-10-14 09:05:29 -05:00
Ryan C. Braun 5b1a9988f9 Add pingEFB text to README 2016-10-07 10:28:13 -05:00
peepsnet 883e8fd36c Merge pull request #1 from cyoung/master
Merge to update
2016-10-06 17:17:13 -04:00
cyoung 84a8d4a98a Merge pull request #506 from cyoung/traffic_counts
Add current UAT/ES tracked targets count in globalStatus.
2016-10-05 00:00:16 -04:00
Christopher Young ce5fe35bb7 Add current UAT/ES tracked targets count in globalStatus. 2016-10-04 23:50:44 -04:00
Jim Jacobsen bb00189e94 Added developer mode toggle by clicking on version 7 times within 3 seconds 2016-10-02 22:17:09 -05:00
peepsnet 0325a9ea39 Fixed the sleep function to lcase and a bit of look & feel 2016-10-02 11:54:31 -04:00
Jim Jacobsen 2a76788405 Added developer menu item in addition 2016-10-01 21:03:04 -05:00
Jim Jacobsen 9f1fd88485 Added developer mode handing from /etc/stratux.conf instead, then this allows options in the status and settings pages. Would like to add a menu option for this in the future though 2016-10-01 19:59:41 -05:00
Christopher Young 8929116f00 Formatting. 2016-10-01 11:48:27 -04:00
cyoung d67f2fe1db Merge pull request #492 from jamez70/allow_static_ip_hosts
Added ability to have static IP hosts
2016-10-01 11:47:04 -04:00
cyoung 3932153c3d Merge pull request #498 from peepsnet/patch-23
update for sdr-tool.sh. mkimg.sh addition.
2016-10-01 11:45:12 -04:00
cyoung 91ae3b7bfa Merge pull request #497 from peepsnet/patch-22
update for sdr-tool.sh script. Selfupdate addition.
2016-10-01 11:44:44 -04:00
cyoung 6f27e96233 Merge pull request #496 from peepsnet/patch-21
update for sdr-tool.sh script. Selfupdate addition.
2016-10-01 11:44:26 -04:00
cyoung 7865039dc2 Merge pull request #499 from peepsnet/patch-24
added sdr-tool.sh info
2016-10-01 11:43:57 -04:00
cyoung d9cb13d500 Merge pull request #495 from peepsnet/patch-20
Tool to "automate" setting SDR serials
2016-10-01 11:43:41 -04:00
peepsnet 06cbb8c508 uncommented a few need lines 2016-09-30 21:35:09 -04:00
peepsnet 0b71091b34 added sdr-tool.sh info 2016-09-30 21:24:38 -04:00
peepsnet c2b0e051ad update for sdr-tool.sh 2016-09-30 21:13:35 -04:00
peepsnet 066b61571c update for sdr-tool.sh script 2016-09-30 21:10:16 -04:00
peepsnet f8bb2c202f update for sdr-tool.sh script 2016-09-30 21:08:32 -04:00
peepsnet 37309af7bb Tool to "automate" setting SDR serials
The script walks users through setting serials for the SDRs and offers the "Fallback" option when setting the 1090 SDR.
2016-09-30 21:05:40 -04:00
Christopher Young 8f3ca19aca Add GPRMC date sanity checking. Add 'RealTime' monotonic ticker, set once by GPS time. 2016-09-29 18:30:26 -04:00
Jim Jacobsen bab827d492 Added ability to have static IP hosts 2016-09-27 23:56:17 -05:00
cyoung 2d03dde95a Merge pull request #471 from uavionix/master
Disable logging when Ping receives data
2016-09-27 17:21:04 -04:00
Christopher Young 8cef443497 Change green (ACT) LED default behavior on RPi - off = stratux not running, on = stratux running. 2016-09-26 14:34:41 -04:00
cyoung f711e61a1f Merge pull request #490 from jamez70/UAT_Statistics
Added UAT statistics to the status page
2016-09-25 20:44:26 -04:00
Jim Jacobsen f099336823 Fixed typo, and added TAF.AMD 2016-09-24 18:23:39 -05:00
Jim Jacobsen 2f2c3d27a3 Added UAT statistics to the status page 2016-09-24 12:17:46 -05:00
cyoung a951ea9afb Merge pull request #488 from AvSquirrel/ubx-zeroalt-fix
Workaround to allow negative GPS HAE on ublox-7. Fixes #487.
2016-09-21 09:04:25 -04:00
Christopher Young dc62a3abba Make HardwareBuild checking for updates case insensitive. 2016-09-19 18:27:19 -04:00
Christopher Young 31bbf1bc1b Don't display serialout settings unless a serialout device is present. 2016-09-19 12:25:23 -04:00
Christopher Young 30fe7295c4 Add automatic serialout when /dev/serialout0 is present.
/dev/serialout0 created by either inserting a CP2102-based
USB-to-Serial dongle or by symlink.
2016-09-19 12:21:39 -04:00
Keith Tschohl 9939ba986a Ignore PUBX,00 'HAE' field if it is equal to 0 2016-09-17 03:56:22 +00:00
Eric Westphal c3f002577f add ahrsweb kalman_listener for inflight monitoring of kalman filter 2016-09-16 13:36:45 -04:00
Eric Westphal 5acbcbfc32 improve ahrs kalman filter stability 2016-09-16 13:36:11 -04:00
Eric Westphal 91ed08583d Fix mapping of 9250 axes to ahrs kalman measurement 2016-09-16 13:34:44 -04:00
Christopher Young 85d73964c7 Typo. 2016-09-14 22:23:17 -04:00
Christopher Young 4659e03dbd Use Pin 12 (GPIO 18) for fancontrol. 2016-09-12 15:25:53 -04:00
Christopher Young 0d404a19bc Remove stratux-post-start.sh. 2016-09-12 14:44:28 -04:00
Christopher Young 95c1c3669e Remove stratux-post-start.sh. Start fancontrol and screen controller from rc.local. 2016-09-12 14:43:56 -04:00
Eric Westphal 6e622e3abb Integrate non-control Kalman approach 2016-09-11 20:33:26 -04:00
Eric Westphal cefbcc49da Measure magnetometer by default 2016-09-11 20:32:45 -04:00
Eric Westphal 9127c3a132 Round groundspeed 2016-09-11 20:32:10 -04:00
Christopher Young 89c82762b7 Change paths. 2016-09-11 18:49:01 -04:00
Christopher Young e4916a9de6 Add back DHCP default route.
Fixes some issues with Android. Cellular no longer usable on iPad when
connected.
2016-09-11 18:48:56 -04:00
Christopher Young 0588f8b0e7 Daemonize stratux-screen.py and fancontrol.py. 2016-09-11 17:24:01 -04:00
Christopher Young 333bb6c3ce Add "post start" script to start fan control and screen controllers. 2016-09-11 17:06:06 -04:00
Christopher Young 03f3957a0d Change paths for OLED screen addition. Add OLED script install into mkimg.sh. 2016-09-11 16:58:37 -04:00
Eric Westphal f6880436ba Merge remote-tracking branch 'origin/master' into dev 2016-09-11 06:37:44 -04:00
Eric Westphal ea353387d9 Fix FPS from FPM 2016-09-07 22:00:28 -04:00
Christopher Young e7636a0561 Add specific CP2102 rule for dedicated serialout device. 2016-09-06 16:16:02 -04:00
Christopher Young f477a8366e Traffic Javascript logic improvements and cleanup.
Fixes case where aircraft is first placed into “invalid position” table
and is never removed (even when position becomes valid).
2016-09-05 14:50:56 -04:00
Christopher Young 16c68b737d BMP logo initial commit. 2016-09-05 14:49:43 -04:00
Christopher Young 1159a37baf Add RPi3 FCC testing report for reference. 2016-08-26 23:09:47 -04:00
cyoung 5c322896e6 Merge pull request #478 from peepsnet/patch-19
Fixed typo
2016-08-24 17:48:16 -04:00
Christopher Young 0177402f00 Write only a single file for updates - fixes reboot loop issues.
Files with spaces and special characters were causing reboot loops.
2016-08-24 10:25:27 -04:00
cyoung 84e3497da5 Merge pull request #479 from tc0nn/master
Fixed typo in aliases for setSerial1
2016-08-20 23:00:51 -04:00
tconnolly@Tims-Home-iMac.local 45aac86b76 Fixed type in aliases for setSerial1 2016-08-20 20:07:25 -05:00
Ryan C. Braun e93b90197c Remove unused fmt from imports 2016-08-20 15:05:35 -05:00
peepsnet 574ff01d51 Fixed typo
this was preventing the stxAliases.txt from being copied over properly
2016-08-19 13:12:33 -04:00
Christopher Young e472329a32 Update issue template with checkboxes. 2016-08-16 16:07:03 -04:00
Christopher Young 6e6aa0b055 Clarify motd message about 'stratux-help' - command only applies to root user.
#473.
2016-08-16 16:04:25 -04:00
Jim Jacobsen 04e4454bb7 Added modification to udev rule to support replacement uAvionix device received 2016-08-11 21:12:38 -05:00
Ryan C. Braun 3cd58d20d8 Disable logging of Ping data reception 2016-08-09 14:36:01 -05:00
Ryan C. Braun 6daa3b7240 Merge remote-tracking branch 'upstream/master' 2016-08-09 14:10:55 -05:00
cyoung ff79aa5555 Merge pull request #463 from egid/egid-cleanup-426
Clean out clock UI
2016-08-05 17:07:02 -04:00
cyoung 973f576a54 Merge pull request #461 from egid/egid-gps-tweak
GPS accuracy on Status page
2016-08-05 17:05:59 -04:00
cyoung 1a7405ee32 Merge pull request #464 from AvSquirrel/boot-fixes
Update setup scripts to disable console on ttyAMA0
2016-08-05 17:04:42 -04:00
cyoung 5a13cc01ee Merge pull request #467 from peepsnet/patch-18
Added hostapd_manager.sh and raspi-config reminders
2016-08-05 12:07:12 -04:00
cyoung fb6c9ee119 Merge pull request #469 from cyoung/uavionix
PingEFB support - initial.
2016-08-05 12:05:02 -04:00
Christopher Young 8293c88936 Merge remote-tracking branch 'origin/master' into uavionix 2016-08-05 11:56:25 -04:00
Christopher Young 2569a146e9 Use apt-get to install python-pil. 2016-07-29 08:34:11 -04:00
Eric Gideon ee6ca139af add horizontal GPS precision to the "GPS solution" row on the status page 2016-07-23 13:16:20 -07:00
peepsnet afe73c38f1 Added hostapd_manager.sh and raspi-config reminders
Added hostapd_manager.sh and raspi-config reminders in the help
2016-07-22 20:35:56 -04:00
Eric Westphal 9faf95a90b Missed a few changes to pointers in ry83Xai 2016-07-21 21:57:51 -04:00
Eric Westphal 38cb2384d7 mpu.Calibrate takes a number of retries 2016-07-21 15:16:21 -04:00
Eric Westphal c27870d2a9 Make SituationData.GroundSpeed a float 2016-07-21 15:16:02 -04:00
Eric Westphal ef436544ac Use new channel interface for mpu9250.go 2016-07-19 07:49:41 -04:00
Eric Westphal 38b0105187 Merge branch 'gdl90report' into dev 2016-07-19 07:48:35 -04:00
Eric Westphal bf30fa147c Provide invalid GDL90Report values if AHRS invalid 2016-07-19 06:40:57 -04:00
Eric Westphal 832054bd35 Rate of Climb uses simpler ewma assuming steady data updates 2016-07-19 00:43:45 -04:00
Eric Westphal be30aefa79 Catch GDL90Report network error, useful for troubleshooting 2016-07-18 22:49:30 -04:00
Eric Westphal a7bb43d6ba Switch GDL90 report to version 1, include other goodies 2016-07-18 22:45:14 -04:00
Eric Westphal 9d133a5855 Calculate rate of climb from bmp altitude measurements 2016-07-18 22:43:44 -04:00
AvSquirrel f529ce3231 Remove references to /etc/inittab 2016-07-16 02:38:13 +00:00
Eric Westphal ad3798b5c8 Make Calibrate public for MPU's 2016-07-15 11:58:13 -04:00
AvSquirrel 56874e0886 Disable console on ttyAMA0 - shell updates 2016-07-15 15:50:30 +00:00
AvSquirrel fd6b8626e8 Disable console on ttyAMA0 - mkimg.sh 2016-07-15 15:49:51 +00:00
Eric Westphal 6b9b754257 MPU uses Calibrate rather than CalibrateGyro 2016-07-15 11:39:33 -04:00
Eric Westphal 3b21f9685a Some Kalman tuning 2016-07-15 11:39:10 -04:00
Eric Gideon 80b373a7a4 Remove clock / clock diff row from status template; also remove from js and go. 2016-07-15 01:28:30 -07:00
Eric Westphal 92001f1e35 First commit of AHRS Kalman Filter integration, untested 2016-07-15 01:31:45 -04:00
Eric Westphal bd2b303b59 Prepare for proper AHRS calculation 2016-07-15 01:31:03 -04:00
Eric Westphal 5382012417 mostly gofmt 2016-07-15 01:30:40 -04:00
Eric Westphal ee8c98eb50 Missing BMP won't shut down entire AHRS; make room for BMP280 2016-07-15 00:12:16 -04:00
Eric Westphal c201bdc4d8 Suggestion for network 2016-07-15 00:10:38 -04:00
Eric Westphal d91a2a10e7 Use RY835AI or RY836AI; add more fields to GDL90 report 2016-07-14 21:38:15 -04:00
Christopher Young e3d348a0fa Resolve conflicts. 2016-07-14 15:50:07 -04:00
Christopher Young 77ecb0d6ad Merge remote-tracking branch 'origin/master' into uavionix
# Conflicts:
#	Makefile
#	image/mkimg.sh
#	selfupdate/makeupdate.sh
2016-07-14 15:45:34 -04:00
Christopher Young eebf4be15c Update README. 2016-07-14 14:59:13 -04:00
Eric Westphal ddaf673006 Don't add one little change before pushing 2016-07-13 20:49:07 -04:00
Eric Westphal 7ee7a83a87 Change MPU to interface to allow RY835AI or RY836AI (or ....) 2016-07-13 18:42:25 -04:00
Eric Westphal c3c49b7c36 Prep for extracting interface for mpu6050 2016-07-13 16:36:33 -04:00
Christopher Young 945c8bf6bc Don't start ffMonitor() - no longer needed. 2016-07-13 15:53:02 -04:00
Christopher Young 04be847069 Add OLED screen display files. 2016-07-12 18:08:56 -04:00
Christopher Young 787887894d Switch last line of data every 5 seconds from CPU+Towers to GPS stats. 2016-07-12 01:15:31 -04:00
cyoung 3877461b6e Merge pull request #459 from peepsnet/patch-16
fix typo
2016-07-10 12:12:59 -04:00
cyoung 24e21bb640 Merge pull request #458 from peepsnet/patch-15
More info in the MOTD
2016-07-10 12:12:55 -04:00
cyoung 2f0f62c8b3 Merge pull request #452 from mhrivnak/patch-1
fixes a minor typo
2016-07-10 12:12:21 -04:00
peepsnet 622c9eb643 fix typo 2016-07-10 10:59:18 -04:00
peepsnet f77b21175b Update motd 2016-07-10 10:55:46 -04:00
peepsnet 2c0768c44c More info in the MOTD 2016-07-10 10:54:44 -04:00
Christopher Young 996deda432 Screen test script - initial commit. 2016-07-09 14:55:56 -04:00
Christopher Young e83bfb6319 Add python-dev for OLED screen. 2016-07-09 14:35:16 -04:00
Christopher Young 6d063cce42 OLED screen notes. 2016-07-09 14:25:06 -04:00
Christopher Young b31ed721c3 Fix more log errors. 2016-07-09 14:05:40 -04:00
Christopher Young f62d83f47f Typo. 2016-07-09 14:01:36 -04:00
Christopher Young f8fa9f5fb4 Fix some log(0) errors. 2016-07-09 13:59:41 -04:00
Christopher Young 3dfbcc6ad7 Add new kernel module name to blacklist for newer Linux distros. 2016-07-07 19:05:35 -04:00
Michael Hrivnak 76484b315e fixes a minor typo 2016-07-03 19:03:34 -04:00
Christopher Young f8269f5759 Make "GPS week out of scope" warning a debug message. 2016-06-30 11:51:56 -04:00
Christopher Young 917029b7ac Stratux logo vector format. 2016-06-28 14:10:42 -04:00
Christopher Young 31464f92ad Install fan control utility via update script. Move to /usr/bin/.
#444.
2016-06-27 09:28:56 -04:00
Christopher Young 9d3060af95 Use sh syntax since previous versions execute the update script using /bin/sh. 2016-06-24 17:15:43 -04:00
Christopher Young 629fa68a13 Use bash to execute update script. 2016-06-24 17:12:37 -04:00
Christopher Young 0f001da912 Remove init.d files from gen_gdl90 process. 2016-06-24 16:48:48 -04:00
Christopher Young f4a36b2df7 Throw webUI error prompting user to update image if /etc/debian_version <8.0.
#448.
2016-06-24 16:10:34 -04:00
Christopher Young b611615dce Don't delete init.d script in .sh update unless running Jessie.
#448.
2016-06-24 15:51:04 -04:00
Christopher Young d50748c23a Update README. 2016-06-23 17:53:09 -04:00
Christopher Young 18cbe9d784 Cleanup. Startup scripts installed by 'make install'. 2016-06-23 16:03:51 -04:00
Christopher Young 6ce1f48f63 Cleanup. Startup scripts installed by 'make install'. 2016-06-23 16:03:20 -04:00
Christopher Young 64710fe60d Typo. 2016-06-23 15:58:14 -04:00
Christopher Young 6e33ff07d6 Update Makefile, remove init.d file install, add new startup script file install. 2016-06-23 15:42:43 -04:00
Christopher Young 9f05b24536 Cleanup. 2016-06-23 15:34:00 -04:00
Christopher Young 3250158126 Clean up. Add systemd files install to mkimg.sh.
#445.
2016-06-21 22:58:30 -04:00
cyoung 5b998896cc Merge pull request #446 from kdknigga/master
convert from sysv init to systemd for the crash recovery benefits. Fixes #445.
2016-06-21 22:51:42 -04:00
Kris Knigga 29c6787f17 convert from sysv init to systemd for the crash recovery benefits 2016-06-21 19:30:29 -05:00
Christopher Young 6dd64321dd Type match. 2016-06-21 15:31:03 -04:00
Christopher Young 19742db6b8 Typo. 2016-06-21 15:27:06 -04:00
Christopher Young 953a211aa8 Ignore compiled test binaries. 2016-06-21 15:25:15 -04:00
Christopher Young 344f0ac2c4 Error checking in UAT parsing. Addresses #420. 2016-06-21 15:21:17 -04:00
Christopher Young ada5b4ae3f dest/src patch. 2016-06-21 15:05:28 -04:00
Christopher Young fc5641cb69 Integrate @toofishes improvement: Unroll loop in convert_to_phi.
“This yields a 10% CPU savings vs the original single value per loop
iteration implementation on a Raspberry Pi 2 Model B.”

https://github.com/mutability/dump978/commit/b0958f4305d2c7355d07fa9b938
8f6ad1b31b161
2016-06-21 14:54:59 -04:00
Christopher Young e180f79855 Start Canadian regs with "C-". Formatting.
#442.
2016-06-21 12:28:49 -04:00
cyoung ec3c5a6ab9 Merge pull request #442 from AvSquirrel/tail-number-decoding
Automatic translation of Mode S codes to US/CA tail numbers
2016-06-21 12:27:27 -04:00
cyoung edb9e8023c Merge pull request #444 from egid/master
GPIO fan control script
2016-06-21 12:25:27 -04:00
Eric Gideon 837c6ec476 adding fancontrol to the root user's dir; no automation at this time. 2016-06-21 09:11:54 -07:00
Eric Gideon 43c0da7e21 adding @helno's GPIO fan control script. 2016-06-21 09:06:30 -07:00
Eric Gideon 50027d416c Merge pull request #1 from cyoung/master
Update fork
2016-06-21 08:56:35 -07:00
AvSquirrel 6d19f57e0e Add decoding of Canadian tail numbers 2016-06-20 05:07:00 +00:00
AvSquirrel efaaa8777d Decode US civil Mode S codes to N numbers 2016-06-20 03:30:40 +00:00
AvSquirrel c5f2193b87 Change FF error message back per cyoung request 2016-06-19 03:12:43 +00:00
AvSquirrel 5dc2aec687 Merge remote-tracking branch 'upstream/master' into gpsattitude-june2016 2016-06-19 03:00:08 +00:00
Christopher Young a062241c7a Add metar-to-text functions. 2016-06-14 10:29:55 -04:00
Christopher Young 275d72befa Add Makefile. 2016-06-14 10:29:30 -04:00
Christopher Young de89ee301a Initial commit, metar parser.
https://sourceforge.net/p/mdsplib/code/HEAD/tree/
2016-06-14 10:28:31 -04:00
Christopher Young 9ae8ff93a2 Cleanup. 2016-06-13 16:25:21 -04:00
Christopher Young 5eadf628ee ASCII Stratux /etc/motd. Add note about clock. #426
http://patorjk.com/software/taag-v1/, “Univers” font.
2016-06-13 16:12:41 -04:00
Christopher Young 60ec38c5bb Change 'Data' in 'msg' struct from []byte to string for logging. 2016-06-10 15:12:32 -04:00
AvSquirrel 7b02ff0b70 Update settings.js for AHRS GDL90 toggle 2016-06-08 03:38:45 +00:00
AvSquirrel c34c107f23 Comment cleanup. Remove bloat from UI status page. 2016-06-08 03:20:43 +00:00
AvSquirrel fbc2ee16d3 Add toggle for GDL90 AHRS output. Use GDL90 AHRS toggle for FF compatibility instead of disabling AHRS hardware. 2016-06-08 02:52:00 +00:00
AvSquirrel 065836ef4c Tweak filter width. Comment out a couple of debug messages 2016-06-08 01:47:19 +00:00
cyoung 1b02ce3611 Merge pull request #438 from AvSquirrel/logging-fix-20160607
Bug fix for logging
2016-06-07 20:39:20 -04:00
AvSquirrel e5a6046660 Set logfiles for non-FlightBox installations 2016-06-08 00:20:10 +00:00
AvSquirrel 3d4dec80a4 Add GPS attitude logging to sqlite log 2016-06-08 00:10:17 +00:00
AvSquirrel cbd117d216 Initial implementation of GPS attitude on v0.9 codebase. Needs debug. 2016-06-07 13:03:25 +00:00
cyoung f40ae217bf Merge pull request #436 from tonymorris/master
fix typo in comment
2016-06-06 20:09:33 -04:00
Tony Morris b0e4ca1772 fix typo in comment 2016-06-02 20:41:25 +10:00
Ryan Braun c8244bf96f Merge pull request #1 from cyoung/uavionix
Merge master changes. Some minor Ping-related fixes.
2016-05-31 15:05:59 -05:00
Christopher Young 62bb61ac00 Include 99-uavionix.rules in .sh update. 2016-05-31 10:42:05 -04:00
cyoung 94d2467e22 Merge pull request #435 from AvSquirrel/ownship-testing
Intial prototype for ownship traffic suppression. Fixes #421.
2016-05-31 09:13:11 -04:00
Christopher Young 68e2d32f1d Move tower stats processing out of parseInput(). Remove unused ADSBTower.Messages_total. 2016-05-31 09:00:02 -04:00
Christopher Young 2132585f76 Remove products_last_minute comments. 2016-05-31 08:29:06 -04:00
cyoung 8f310d0afc Merge pull request #428 from AvSquirrel/uat-mutex
Additional UAT stability improvements (tower mutex, array bounds checks)
2016-05-31 08:26:50 -04:00
cyoung 1493526807 Merge pull request #430 from jpoirier/development
Add support for RPi0 board rev 1.3
2016-05-31 08:20:03 -04:00
Joseph Poirier 4431f3cda3 Add support for RPi0 board rev 1.3 2016-05-29 11:17:00 -05:00
Christopher Young 9e6ba2094e Allow user to set ppm to a blank string.
13c6fef514
2016-05-29 01:45:13 -04:00
Christopher Young 404a4c9c05 FlightBox additions: log to /root. 2016-05-27 16:27:22 -04:00
Christopher Young 4313e02fc7 Cleanup old logging code. Comments. 2016-05-27 16:20:20 -04:00
Christopher Young 89107818b8 decodeAirmet() not used in gen_gdl90 stats and still in development.
#420.
2016-05-27 11:51:11 -04:00
Christopher Young 438a947aa5 Remove extra log message. 2016-05-27 00:18:48 -04:00
Christopher Young e81c640baf Fix fatal error when can't listen on :50113 UDP. 2016-05-26 23:48:13 -04:00
Christopher Young 751d211b38 Use only /dev/ping. Formatting. 2016-05-26 23:31:06 -04:00
Christopher Young 5bafa0d8b0 Update udev rules from 'make install'. 2016-05-26 23:27:23 -04:00
Christopher Young 7e915cc116 Merge remote-tracking branch 'origin/master' into uavionix 2016-05-26 23:25:46 -04:00
Christopher Young 566295a227 Undo last change. 2016-05-26 23:20:40 -04:00
Christopher Young f417414fad Update udev rules with 'make install'. 2016-05-26 23:19:35 -04:00
cyoung 3843350432 Merge pull request #427 from uavionix/master
Initial
2016-05-26 23:15:41 -04:00
AvSquirrel 72aa6b5583 Bounds checking for uatparse.go arrays 2016-05-26 03:30:24 +00:00
AvSquirrel 5be9ec80ef Comment out 'products_last_minute' references 2016-05-24 19:48:31 +00:00
AvSquirrel f1521d6e25 Initial commit of ADSBTower mutex protection (needs testing) 2016-05-24 19:39:11 +00:00
cyoung 47271df764 Merge pull request #418 from AvSquirrel/udev-updates
Udev updates. Fixes #424.
2016-05-23 23:44:43 -04:00
Christopher Young 744240da50 Typo. 2016-05-23 11:27:50 -04:00
cyoung 5bd4c84e53 Merge pull request #405 from peepsnet/patch-14
include hostapd-edimax.conf along with hostapd.conf during updates
2016-05-23 11:14:53 -04:00
AvSquirrel 401c372ef4 Intial prototype for ownship traffic suppression 2016-05-20 03:28:41 +00:00
AvSquirrel d9c9b87f42 Add udev rules to Makefile 2016-05-19 04:03:34 +00:00
AvSquirrel 7940417f1c Add u-blox 8 to udev rules. Use generic descriptions for ublox 6/7. 2016-05-19 03:48:58 +00:00
Christopher Young aae8e925ef Fix 2016-05-17 19:19:32 -04:00
Christopher Young 7881d6c53a Move away from ttyUSB0 and use udev-specific rules.
#416.
2016-05-17 17:17:01 -04:00
Christopher Young 8b85b41342 Deploy stratux udev rules.
#416.
2016-05-17 17:13:30 -04:00
Christopher Young 4928f9526b Typo. 2016-05-17 15:26:11 -04:00
Christopher Young 1a50587cc9 Upload to temporary directory in .sh builds, then move.
#417.
2016-05-17 15:15:56 -04:00
Ryan C. Braun ae40a08d7e Fix udev typo 2016-05-16 18:07:46 -05:00
Ryan C. Braun c709088be2 Update udev rule to symlink 2016-05-16 18:07:04 -05:00
Christopher Young c1fa523aaf Initial commit - udev rules for GPS devices and serialout devices.
#416.
2016-05-16 18:39:42 -04:00
cyoung 29915cb62e Merge pull request #412 from AvSquirrel/gps-backend-working
GPS improvements: Satellite info; multi-GNSS support; UI updates
2016-05-16 17:58:01 -04:00
Christopher Young 13c6fef514 Allow user to set watch list to a blank string. 2016-05-16 17:51:38 -04:00
AvSquirrel a39a870378 Bug fix for GSA SBAS 'inSolution' marking. Update comments. 2016-05-16 02:17:01 +00:00
Christopher Young fba162a4e9 es_dump_csv initial commit. 2016-05-14 00:35:51 -04:00
Christopher Young b9951241a5 GetTunerGain to confirm tuner gain setting. 2016-05-13 23:58:08 -04:00
Christopher Young 7dca721b4c Add slackin badge. 2016-05-13 23:29:58 -04:00
Christopher Young 86859f32f5 Typo. 2016-05-13 22:57:33 -04:00
AvSquirrel fc1870af6a Length check for PUBX,03 messages. Add inSolution status to debug messages 2016-05-14 02:32:11 +00:00
AvSquirrel f02fdf102e Add mutex lock on handleSatellitesRequest 2016-05-14 01:44:13 +00:00
Christopher Young 2231ee4972 Remove null characters from serial string.
Fixes #413.
2016-05-13 21:42:05 -04:00
AvSquirrel 4fa44bb766 Clean up web UI formatting, update GPS help file 2016-05-08 21:55:48 +00:00
AvSquirrel c202e72c1d UBX config updates; comments; clean up debug messages 2016-05-08 20:41:49 +00:00
AvSquirrel 861debafbf Improve satellite counts for multiGNSS GSA messages 2016-05-08 16:36:05 +00:00
AvSquirrel 1d4de4571f Remove more debug mesages 2016-05-08 05:33:05 +00:00
AvSquirrel 65beb92208 Re-initialize on disconnect. Improvements for multi-GNSS 'in solution' counts. 2016-05-08 05:14:20 +00:00
AvSquirrel 653bb53cf6 Add UBX support. Enable GLONASS for M8N Neo. Reduce sampling to 5 Hz 2016-05-08 01:53:12 +00:00
AvSquirrel e71ede9007 Add GLONASS support to GSV parsing 2016-05-07 20:48:02 +00:00
AvSquirrel d692c4d732 Add satellite in solution indicator 2016-05-07 15:19:42 +00:00
AvSquirrel 06fc9a74b6 Suppress '-999' value for invalid elev/az in GPS UI 2016-05-07 06:44:18 +00:00
AvSquirrel a00e4d2afa Remove debug messages 2016-05-07 06:27:53 +00:00
AvSquirrel 34e4ff2dd0 Add satellite status to GPS UI page 2016-05-07 06:14:36 +00:00
AvSquirrel 34791c638a Create JSON interface for satellite constellation. 2016-05-07 05:18:10 +00:00
AvSquirrel df720ee23e Create and populate 'Satellites' structure 2016-05-06 05:50:45 +00:00
AvSquirrel a8f7728b11 Parse GPGSV fields into local variables 2016-05-05 05:16:16 +00:00
AvSquirrel 883509b076 Create Satellites data structure 2016-05-05 04:01:10 +00:00
AvSquirrel 26fce60fd4 Parse satellites tracked from GPGSV messages 2016-05-05 03:28:28 +00:00
Christopher Young 0a62fd2d9a Don't assign struct val directly. 2016-05-03 09:50:59 -04:00
Christopher Young 6db8ba6fc0 Type fix. 2016-05-03 09:39:16 -04:00
Christopher Young 64f1ae1154 Add MessageQueueLen (messageQueue length) to networkConnection struct.
Debugging for #409.
2016-05-03 09:31:57 -04:00
Christopher Young d01bdfee43 Typo. 2016-05-03 09:12:49 -04:00
Christopher Young 141045bb0e Add displayable error when SQLite logging is behind. 2016-05-03 09:05:54 -04:00
cyoung 8043ff79fd Merge pull request #410 from AvSquirrel/logging
Graceful shutdown of SQLite logs
2016-05-03 08:53:53 -04:00
cyoung 81b950c846 Merge pull request #408 from AvSquirrel/gps-backend
GPS backend improvements
2016-05-03 08:50:06 -04:00
AvSquirrel 29948156d6 Additional stability improvements 2016-05-03 04:59:13 +00:00
AvSquirrel 57197c55eb Split out traffic source from DEBUG. Fix panic closing closed channel. 2016-05-03 04:40:51 +00:00
AvSquirrel 5478cdaeb8 Add comments and clean up debug messages 2016-05-03 03:50:42 +00:00
AvSquirrel aaf03acd8c Close datalog.go channels on sqlite shutdown 2016-05-03 03:02:44 +00:00
AvSquirrel 24a6da3da9 Added graceful shutdown for SQLite logging 2016-05-02 05:03:21 +00:00
AvSquirrel 2dd8a14d62 Status and settings logged only when replay log enabled 2016-05-01 20:02:56 +00:00
AvSquirrel 837d98de25 Avoid false positive isGPSValid() check at startup 2016-04-29 08:54:04 -05:00
peepsnet 1555b2a5c8 hostapd-edimax.conf
I don't know if this was an oversight but I believe this should of been included
2016-04-29 09:22:25 -04:00
AvSquirrel 313f16e433 Improved isGPSValid(); reordered GPS port priority 2016-04-29 03:18:34 +00:00
Christopher Young feeeaea708 Remove wifi_watch.sh and associated rc.local entry. 2016-04-28 12:41:55 -04:00
cyoung bd2402f0fb Merge pull request #398 from AvSquirrel/traffic-ui-new
Traffic UI improvements
2016-04-24 12:32:43 -04:00
cyoung cfc54bba8b Merge pull request #399 from AvSquirrel/sirf-config-script
Shell script for offline SIRF-IV / BU-353-S4 configuration
2016-04-24 12:28:45 -04:00
AvSquirrel 054771e3f2 Add shell script for offline SIRF-IV / BU-353-S4 config 2016-04-24 15:53:11 +00:00
AvSquirrel 3769dfafbc TrafficUI helpfile update and minor UI fixes 2016-04-24 03:49:04 +00:00
AvSquirrel dc9292acbd Reformat non-position table for better reflow 2016-04-24 00:05:06 +00:00
AvSquirrel 749480f1c3 Zero-pad single-digit lat/lng in traffic UI 2016-04-23 23:34:50 +00:00
AvSquirrel 614cd875b2 Reformat ADS-B traffic table for better reflow 2016-04-23 23:10:53 +00:00
AvSquirrel 75923725ea Make mtk_config.sh executable 2016-04-23 04:33:34 +00:00
AvSquirrel 36d69c3fda Merge remote-tracking branch 'upstream/master' into traffic-ui-new 2016-04-23 04:32:13 +00:00
Christopher Young d8624016f6 Track startups in sqlite. 2016-04-22 16:10:56 -04:00
cyoung 6e5d449af0 Merge pull request #394 from AvSquirrel/gps-uart-fix
GPS UART fix for RPi 3. Fixes #393.
2016-04-22 07:22:11 -04:00
cyoung 14f35ba81e Merge pull request #396 from peepsnet/patch-13
Typo in stxAliases.txt
2016-04-22 07:20:35 -04:00
peepsnet f6f3431ab9 Typo 2016-04-20 15:28:22 -04:00
AvSquirrel f6d2ee1898 config.txt updates for RPi 3 2016-04-20 11:51:09 +00:00
AvSquirrel d83ec11ea9 Remove /dev/ttyS0 from GPS initialization 2016-04-20 03:45:24 +00:00
AvSquirrel 3d1af90d3d Add setup script for MTK3339 based receivers 2016-04-20 02:11:53 +00:00
Christopher Young da5f5d003d Remove unused code in comments. 2016-04-19 08:51:47 -04:00
Christopher Young a2ca212a52 Un-do dump1090 version change in #390. 2016-04-19 08:38:18 -04:00
Christopher Young 827bf13fde Comments update.
#390.
2016-04-19 08:37:22 -04:00
cyoung 6545c154c2 Merge pull request #390 from AvSquirrel/traffic-backend-working
Traffic backend updates
2016-04-19 08:28:36 -04:00
AvSquirrel d00ab538cd Traffic UI updates from gpsattitude branch 2016-04-17 12:17:11 +00:00
AvSquirrel 0292aeead3 Merge remote-tracking branch 'upstream/master' into traffic-ui-new 2016-04-17 12:11:57 +00:00
cyoung c327c0220b Merge pull request #391 from cyoung/reboot_repeat_fix
trigger reboot as a webservice and redirect webui to status page. Fixes #389.
2016-04-13 12:56:40 -04:00
bradanlane 70269dd442 trigger reboot as a webservice and redirect webui to wait on the status page for the reboot to complete 2016-04-13 12:38:37 -04:00
AvSquirrel 955fd13195 Separate ES:30006 logging into its own SQLite table 2016-04-13 05:21:05 +00:00
AvSquirrel 8b9c89542f Add distance / bearing calculation. Don't log stale traffic. 2016-04-13 04:04:28 +00:00
AvSquirrel d407c513c9 Reduce SQLite traffic to 1/sec. Backend improvements from gpsattitude branch 2016-04-13 03:41:08 +00:00
AvSquirrel c8ad41c8bc Update to AvSquirrel/dump1090@1ab6062 2016-04-13 02:52:55 +00:00
cyoung 43c5ff3b8c Merge pull request #387 from peepsnet/patch-12
typo
2016-04-12 11:46:45 -04:00
peepsnet f26ae164a7 typo 2016-04-12 11:36:20 -04:00
Christopher Young acee114964 Fixed race condition that caused CPUTemp = -99.00ºC. 2016-04-12 11:13:48 -04:00
Christopher Young 23619fad1b Add disk usage webUI warning. 2016-04-12 10:59:07 -04:00
Christopher Young e8f8a27bc3 Formatting (gofmt). 2016-04-12 10:38:04 -04:00
cyoung 20c09340d7 Merge pull request #376 from AvSquirrel/ownship-track
Improve ownship track accuracy. Add disk usage to logs.
2016-04-12 10:37:20 -04:00
cyoung 3f495ef0b5 Merge pull request #386 from AvSquirrel/sqlite-timestamp-slice
SQLite logging - Change dataLogTimestamps[] to slice
2016-04-12 10:30:10 -04:00
Christopher Young d9e556acba Add old Pi2 AMA0. 2016-04-11 22:52:07 -04:00
Christopher Young cc49ea9813 Fixes PR #382. 2016-04-11 17:25:09 -04:00
cyoung 36723d446f Merge pull request #385 from peepsnet/patch-11
Update update_footer.sh
2016-04-11 17:23:32 -04:00
cyoung 0e9adca4ab Merge pull request #383 from peepsnet/patch-9
Update mkimg.sh
2016-04-11 17:22:24 -04:00
cyoung ff3594b597 Merge pull request #382 from peepsnet/patch-8
adding .sxtAliases
2016-04-11 17:21:43 -04:00
cyoung 2cf27665cc Merge pull request #381 from peepsnet/patch-7
update for .stxAliases
2016-04-11 17:21:14 -04:00
cyoung 3ce1c5be3d Merge pull request #380 from peepsnet/patch-6
Add aliases and hostapd_manager.sh
2016-04-11 17:20:53 -04:00
cyoung 750cebe7a8 Merge pull request #379 from peepsnet/patch-5
Debugging aliases
2016-04-11 17:18:37 -04:00
cyoung 690a03f9d2 Merge pull request #375 from AvSquirrel/geometric-ownship-fix
Fix geometric ownship alt overflow
2016-04-11 17:15:11 -04:00
cyoung 3768370411 Merge pull request #367 from peepsnet/patch-4
keep an alias file after this file is modified and Stratux Specific Aliases
2016-04-11 17:14:03 -04:00
AvSquirrel 002105bb39 Change dataLogTimestamps from map to slice 2016-04-10 05:21:13 +00:00
Christopher Young fffe2b7505 Change hardware-specific /dev/ttyAMA0 to more general /dev/ttyS0. 2016-04-09 22:02:18 -04:00
peepsnet 781b0d64a3 Update update_footer.sh 2016-04-08 19:21:24 -04:00
peepsnet 4ca7fa94fc Update mkimg.sh 2016-04-08 19:17:54 -04:00
peepsnet 0f8c352ae6 adding .sxtAliases 2016-04-08 12:03:18 -04:00
peepsnet ad0f1a3c55 update for .stxAliases 2016-04-08 11:59:57 -04:00
peepsnet e8dff7d1cb Add aliases and hostapd_manager.sh
adding the lines to include stxAliases and hostapd_manager.sh to makefile
2016-04-08 11:56:38 -04:00
peepsnet 635d2fd106 filename 2016-04-08 11:53:31 -04:00
peepsnet 905b268893 Debugging aliases
Some shortcuts to help us get users to be able to debug stratux
2016-04-08 11:50:59 -04:00
peepsnet 78fcc855a9 typo 2016-04-08 10:59:32 -04:00
peepsnet 98b340e51a typo 2016-04-08 10:59:10 -04:00
peepsnet b0e58058a4 Stratux specific alias file 2016-04-08 10:56:33 -04:00
AvSquirrel 859e8da9c2 Additional mutex lock for insertData() 2016-04-07 22:34:01 +00:00
AvSquirrel 0de359ec0e Remove extraneous LF 2016-04-07 08:27:07 +00:00
AvSquirrel 21bc97e9b6 Add disk usage / free space to log 2016-04-07 08:21:15 +00:00
AvSquirrel 1be1c9fdcf Improved binning for ownship track message 2016-04-07 06:31:50 +00:00
AvSquirrel be3e487267 Use float for GPS track. Rebin ownship track. 2016-04-07 05:24:12 +00:00
AvSquirrel d1ebc2df1d Fix geometric ownship alt overflow 2016-04-07 04:18:57 +00:00
AvSquirrel 64b20d2bca Testing more mutex protection for checkTimestamp() 2016-04-06 09:41:23 -05:00
AvSquirrel 23e2721c90 Add datalog mutex for timestamp 2016-04-06 03:01:10 +00:00
peepsnet 77f9708d56 keep an alias file after this file is modified
Since I am tired of my aliases being over written I am adding this so I can make my own alias file and not have it overwritten!!!!!!!!!!!!!

create a file called .aliases in /root and they will be included
2016-04-04 12:20:34 -04:00
Christopher Young 22a019b9a7 Remove temporary files on update. 2016-04-03 14:41:06 -04:00
Christopher Young 5da86d919f Comment out debugging data. 2016-04-03 14:16:00 -04:00
Christopher Young 8545a9ba0d Fix bulkInsert query logic problem. Maximum rows based on column limitation (999). Issue warning if SQLite is taking too long. 2016-04-03 14:10:42 -04:00
cyoung a39bc203a2 Merge pull request #361 from peepsnet/patch-1
Update mkimg.sh for hostapd_manager.sh
2016-04-03 13:56:06 -04:00
Christopher Young 0b1ca4b2da Fix temporary fix for generic NMEA GPS - Satellites = SatellitesTracked = SatellitesSeen. 2016-04-03 13:42:38 -04:00
cyoung a37855225c Merge pull request #366 from peepsnet/patch-3
Correct typo and clarify instructions for hostapd_manager.sh
2016-04-03 11:00:33 -04:00
peepsnet 9cdd5e3af2 Correct typo and clarify instructions 2016-04-03 01:27:14 -04:00
cyoung 73236d73c8 Merge pull request #363 from cyoung/sqlite_logging
Sqlite logging.
2016-04-02 16:18:35 -04:00
Christopher Young feaffc07fc Compile with 4 cores. 2016-04-02 16:01:07 -04:00
Christopher Young 9607311dbe Increase batch size to 1,000 up to a maximum query size 750,000 bytes. 2016-04-02 15:57:05 -04:00
Christopher Young da4eb3dfc8 Type fix. 2016-04-02 15:40:25 -04:00
Christopher Young 1b093ef1bb INSERT speed fixes. 2016-04-02 15:33:19 -04:00
peepsnet 0b4df811ab Update mkimg.sh for hostapd_manager.sh
copy file to location and chmod
2016-04-01 19:42:54 -04:00
cyoung 2d10744cfe Merge pull request #360 from cyoung/sqlite_logging
Sqlite logging.
2016-04-01 18:44:11 -04:00
Christopher Young 980977146e Remove debugging code. 2016-04-01 18:42:28 -04:00
Christopher Young 8cc6534761 Remove debugging code. 2016-04-01 18:33:01 -04:00
Christopher Young 62dd58b07f Use batched inserts instead of prepared statements. 2016-04-01 18:25:53 -04:00
cyoung 8b56f1f6de Merge pull request #359 from peepsnet/patch-1
Bash script to modify hostapd.conf and hostapd-edimax.conf
2016-04-01 16:53:16 -04:00
Christopher Young f1f3977e5b Used prepared statements for SQLite inserts. 2016-04-01 15:42:46 -04:00
peepsnet 47bc631568 Completely rewritten for command line flags
Help documentation for go.sh.

Basic usage: hostapd_manager.sh -s ssid -c chan -e pass

Command line switches are optional. The following switches are recognized.
-s  --Sets the SSID to ssid. "-s stratux"
-c  --Sets the channel to chan. "-c 1"
-e  --Turns on encryption with passphrase pass. 8-13 Printable Characters. Cannot be used with -o. "-e password!"
-o  --Turns off encryption and sets network to open. Cannot be used with -e.
-h  --Displays this help message. No further functions are performed.

Example: hostapd_manager.sh -s stratux -c 1 -e N3558D
2016-04-01 15:00:51 -04:00
Christopher Young dbacc6b6e7 Move db writes to a separate goroutine. 2016-04-01 14:05:23 -04:00
peepsnet cb8a531710 Update hostapd_manager.sh
typo
2016-04-01 12:37:28 -04:00
Christopher Young 044a95d801 Stratux shutdown and archive log database when upgrading. 2016-04-01 12:00:21 -04:00
Christopher Young 268ea23ce5 Use tmp variable to assign. 2016-04-01 08:40:09 -04:00
Christopher Young 2bfb5d8c33 Typo. 2016-04-01 08:36:10 -04:00
Christopher Young fdbde39e96 Extrapolate GPS timestamps with stratuxClock. 2016-04-01 08:34:37 -04:00
Christopher Young b87aa52044 Batch data writes.
This will be done as part of a system where the database file is
compressed and moved periodically.
2016-04-01 08:26:37 -04:00
peepsnet 93841cc4f5 Update hostapd_manager.sh 2016-04-01 01:48:49 -04:00
peepsnet 267c906354 Update hostapd_manager.sh 2016-04-01 01:45:50 -04:00
peepsnet 6a8eb2b3c9 Update hostapd_manager.sh 2016-04-01 01:44:59 -04:00
peepsnet 5612e70e27 Update hostapd_manager.sh 2016-04-01 01:44:23 -04:00
peepsnet 039e0c231e Hostapd_manager.sh
File to modify:
/etc/hostapd/hostapd.conf
/etc/hostapd/hostapd-edimax.conf

This is a improvement on the script that was uploaded to reddit. 
https://www.reddit.com/r/stratux/comments/4c0ffw/change_ssid_bash_script/

usage:
hostapd_manager.sh ssid channel passphrase
2016-04-01 00:59:50 -04:00
Christopher Young 4e5513ce95 Send traffic update to logTraffic(). 2016-03-31 20:39:02 -04:00
Christopher Young 7ad31e9414 Temp. 2016-03-26 17:25:32 -04:00
Christopher Young ce1617af93 Remove further remnants of replay logging. 2016-03-26 17:24:08 -04:00
Christopher Young c6c8c22b63 Stratux plugin beginning. 2016-03-26 17:23:08 -04:00
Christopher Young 480426cdd1 Remove further remnants of replay logging. 2016-03-26 17:19:59 -04:00
Christopher Young e0f82b0a29 Data logging graceful shutdown. 2016-03-26 17:15:59 -04:00
Christopher Young 0199d49238 Move dump1090 terminal logging to datalog package. Remove remnants of replay logging. 2016-03-26 17:12:26 -04:00
Christopher Young fa28ac210c Remove UAT and ES replay logging. Add datalog functions for UAT and ES messages. 2016-03-26 16:49:57 -04:00
Christopher Young cb113cb804 Remove AHRS replay log. 2016-03-26 16:37:33 -04:00
Christopher Young aa2bd06fd0 Remove GPS replay log. 2016-03-26 16:34:02 -04:00
Christopher Young bcf20249e8 Don't log situation or traffic data unless globalSettings.ReplayLog is true. 2016-03-25 11:58:44 -04:00
Christopher Young 8de91a55f0 Remove extra help info.
PR #268.
2016-03-24 19:31:42 -04:00
Christopher Young 7c5da8ab55 Newline. 2016-03-24 18:08:42 -04:00
Christopher Young 32097e3b61 Debug output cleanup. 2016-03-24 17:28:00 -04:00
Christopher Young a86314e883 Cleanup. 2016-03-24 17:26:59 -04:00
Christopher Young ce566ae5d3 Use stratuxClock to check timestamp age. 2016-03-24 12:59:29 -04:00
Christopher Young d9bbe5881c Revert PR #352. 2016-03-24 12:39:26 -04:00
Christopher Young fbc7c6f168 Typo. 2016-03-24 12:13:08 -04:00
Christopher Young bd4f4c8743 Log status. 2016-03-24 10:51:12 -04:00
Christopher Young 5680908301 Track the last NMEA message in SituationData. 2016-03-24 10:37:24 -04:00
cyoung 5073fdadb6 Merge pull request #352 from jpoirier/go-checker
check for the go command not GOROOT
2016-03-24 10:34:44 -04:00
Christopher Young 937bbecd28 Refactoring and cleanup. 2016-03-24 10:23:29 -04:00
Joseph Poirier a1ee8dd5e1 check for the go command not GOROOT 2016-03-24 08:45:59 -05:00
Christopher Young 854b96f608 More data logger boilerplate. Add to Makefile and init in main(). 2016-03-24 09:33:11 -04:00
Christopher Young 67d62184d3 Save GPSTime in SituationData struct. 2016-03-24 08:59:34 -04:00
Christopher Young bcef2ba823 Improve main logger goroutine. 2016-03-24 01:14:48 -04:00
Christopher Young 275c1740f0 Export all possible status fields. 2016-03-24 00:29:08 -04:00
Christopher Young 0a26cfc240 Export all possible SituationData fields. 2016-03-24 00:26:56 -04:00
Christopher Young 934c24ee71 Generalized logData(), added test code. 2016-03-24 00:23:12 -04:00
Christopher Young 80f1007a6a Add struct .String() marshaling. Insert data function. 2016-03-23 23:08:00 -04:00
Christopher Young e12611e8d4 Initial commit: data logger functions. 2016-03-23 12:31:13 -04:00
cyoung 3272867964 Merge pull request #349 from jpoirier/circleci-prs
circleci: allows PRs to correctly build themselves when the PR happens
2016-03-23 11:08:42 -04:00
Joseph Poirier b63dfb198d circleci: allows PRs to correctly build themselves when the PR happens 2016-03-23 09:57:01 -05:00
cyoung fe8b440e9e Merge pull request #347 from jpoirier/development
image: add rpi0 and explicit edimax dongle check
2016-03-23 10:07:42 -04:00
Christopher Young 9754f19be2 Hide more debug printing. 2016-03-23 09:19:11 -04:00
Christopher Young f1ce8a75bc Hide more debug printing. 2016-03-23 09:18:28 -04:00
Joseph Poirier 7790f4e6ff image: add rpi0 and explicit edimax dongle check 2016-03-23 03:03:35 -05:00
Christopher Young b8c17e0460 Checking for specific hardware builds. 2016-03-22 11:43:00 -04:00
cyoung 9f40afdc21 Merge pull request #344 from egid/master
Tweak error messages to use FontAwesome icon and stock angular maui colors.
2016-03-22 10:39:43 -04:00
Eric Gideon 13ccff9842 Tweak error messages to use FontAwesome icon and stock angular maui colors. 2016-03-21 20:49:32 -07:00
Christopher Young 1a808ca591 Redefine "connected"/"recent" clients = recently pingable hosts. 2016-03-21 20:32:24 -04:00
Christopher Young 65537dbdc8 Issue a warning and disable features when FF broadcast messages are received.
Fixes #332.
2016-03-21 16:31:56 -04:00
Christopher Young a93501f8f4 Debug output. 2016-03-21 16:16:12 -04:00
Christopher Young 6afb4ec415 Cleanup. 2016-03-21 15:58:48 -04:00
Christopher Young f732eb2289 Add /etc/modules to mkimg and makeupdate. 2016-03-21 14:48:38 -04:00
Christopher Young db130aab76 Add /root/.bashrc to mkimg and makeupdate. 2016-03-21 13:42:10 -04:00
Christopher Young 6a9f1ff8e6 Add /etc/modprobe.d/rtl-sdr-blacklist.conf to mkimg and makeupdate. 2016-03-21 13:38:12 -04:00
Christopher Young 5c6e493fca Add /boot/config.txt to mkimg and makeupdate. 2016-03-21 13:05:42 -04:00
Christopher Young dfc6635f94 Cleanup. 2016-03-21 13:04:05 -04:00
Christopher Young b2eb382c1a Remove DHCP lease expiry code.
Fixes #325.
2016-03-20 00:56:21 -04:00
Christopher Young 1f9a5dde35 Update hostapd.conf with .sh update. 2016-03-18 15:59:53 -04:00
cyoung 2319b53ad1 Merge pull request #341 from jpoirier/hostapd_conf_fix
fix wmm parameter name
2016-03-18 15:58:19 -04:00
Joseph Poirier 279ab071ac fix wmm parameter name 2016-03-18 14:29:46 -05:00
Christopher Young 070626dc1f Temp. 2016-03-17 16:56:12 -04:00
Christopher Young 616a2b9fbd Add /boot/config.txt settings. 2016-03-17 16:55:03 -04:00
Christopher Young 2b1acf49a2 Remove wifi_watch.sh and rc.local start. 2016-03-17 16:54:45 -04:00
Christopher Young c3ecbf0b7c More setup changes. 2016-03-16 12:13:07 -04:00
Christopher Young a6b7ac17ab Update filename. 2016-03-16 11:55:47 -04:00
Christopher Young 6ced449faa Update script name. 2016-03-16 11:37:56 -04:00
Christopher Young b38045da03 Eliminate wifi_watch.sh by using post-up. 2016-03-16 11:32:58 -04:00
Christopher Young a6ffea0122 Eliminate hostapd startup scripts. Create stratux-wifi wifi start script. Use post-up for hostapd/dhcpd start. 2016-03-16 11:32:22 -04:00
Christopher Young 63491e525c Added two hostapd versions, two hostapd confs. 2016-03-16 10:37:19 -04:00
Christopher Young 84edd98b7e Initial commit - RPi2 (Edimax) and RPi3 confs, Edimax hostapd binary. 2016-03-16 09:44:37 -04:00
Christopher Young b160566288 Update test program. 2016-03-16 08:40:29 -04:00
cyoung bf86dc2ea3 Merge pull request #337 from jpoirier/development
fix cb funct type arg count, circleci branch specific builds, move cgo flag
2016-03-16 08:23:10 -04:00
cyoung 3ae0439429 Merge pull request #338 from jpoirier/godump978_init
auto init on package import
2016-03-16 08:20:39 -04:00
Joseph Poirier 799ee42bc1 fix circleci checkouts so PRs work 2016-03-16 07:14:07 -05:00
Joseph Poirier dbca0fb0b0 auto init on package import 2016-03-16 06:58:01 -05:00
Joseph Poirier 634c3abf3a fix cb function type arg count, circleci branch specific builds, move cgo flag 2016-03-16 06:41:19 -05:00
Christopher Young d3ee8dce97 Comment update. 2016-03-15 22:41:47 -04:00
cyoung 2224d131b6 Merge pull request #334 from jpoirier/xdump1090_fix
sdr: fix 1090 shutdown hang, add shutdown completed messages
2016-03-15 22:40:59 -04:00
Christopher Young c96ee7bce4 RPi3/RPi2 detect. 2016-03-15 00:27:47 -04:00
Christopher Young fae350408f Initial commit. 2016-03-14 23:29:41 -04:00
Christopher Young 4d475587a9 Initial commit. 2016-03-14 23:28:14 -04:00
Joseph Poirier 9d2d4850af sdr: fix type 2016-03-14 15:49:00 -05:00
Joseph Poirier c5aacf0fbd sdr: capture state locally prior to processing 2016-03-14 15:47:33 -05:00
Joseph Poirier 529b453ba2 sdr: replace Scan due to a report that it was still blocking, split stderr and stdout 2016-03-14 02:23:03 -05:00
Joseph Poirier 336d17d615 fix stray curley brace 2016-03-13 00:09:31 -06:00
Joseph Poirier 6f1625f1f7 Merge pull request #1 from zendor/dump1090_fix
updated shutdown to use a separate thread to kill dump1090
2016-03-12 20:54:34 -06:00
Allan Feldman 5939c0c368 fix a bad merge which deleted a brace 2016-03-12 18:19:07 -08:00
Allan Feldman cf94e0c79f updated shutdown to use a separate thread to kill dump1090 2016-03-12 18:13:03 -08:00
Joseph Poirier dea3374242 sdr: handle premature dump1090 process exit 2016-03-12 16:58:11 -06:00
Joseph Poirier 10c9f73e2a fix 1090 shutdown hang, add shutdown completed messages 2016-03-11 19:29:46 -06:00
Christopher Young 4e452956dc Typos. 2016-03-10 15:03:38 -05:00
Christopher Young 66c29aa9a6 RO Partition rebuild from WebUI. 2016-03-10 14:57:54 -05:00
Christopher Young e356194eb2 Add "System Errors" to main status page. 2016-03-10 14:41:30 -05:00
Christopher Young ac5a054e7d Logic error. 2016-03-10 13:29:07 -05:00
Christopher Young e5026f66c1 Add HardwareBuild to globalStatus - only used for FlightBox currently. 2016-03-10 13:09:25 -05:00
Christopher Young e6bb6ce477 Add system-wide errors concept for display in WebUI. 2016-03-10 13:06:14 -05:00
Christopher Young dbe8ed5c3a Change default settings: GPS enabled. 2016-03-10 12:34:06 -05:00
Christopher Young 2e621cb426 Cleanup. 2016-03-10 12:33:03 -05:00
Christopher Young f880d1e61a Add DroidEFB. 2016-03-10 10:33:43 -05:00
Christopher Young e4d74e221c Only show some debug output depending on globalSettings.DEBUG. 2016-03-10 10:20:46 -05:00
Christopher Young 009d7219f2 Sudo needed for CircleCI. 2016-03-09 09:01:55 -05:00
Christopher Young ee42e324f2 Remove sudo. 2016-03-09 08:54:13 -05:00
Ryan C. Braun 6594cdf5f4 Enhance Ping support, add RSSI and RS bit errors 2016-02-26 11:18:22 +00:00
Ryan C. Braun 6ae392af6d Merge branch 'master' of https://github.com/cyoung/stratux
Conflicts:
	main/gen_gdl90.go
	web/plates/js/settings.js
2016-05-04 05:50:52 +00:00
Ryan C. Braun e1e02a4bc7 Change network reconnect behavior from ping to dump1090 2016-05-04 05:45:18 +00:00
Ryan C. Braun 3348cf81da Add uAvionix Ping udev rules 2016-04-20 09:36:45 +00:00
Ryan C. Braun 69a933efdd Merge branch 'master' of https://github.com/cyoung/stratux
Conflicts:
	Makefile
	main/traffic.go
2016-04-20 09:29:56 +00:00
Ryan C. Braun 91fd133271 First cut of uAvionix Ping changes 2016-04-20 08:59:55 +00:00
162 zmienionych plików z 40422 dodań i 38797 usunięć

30
.gitignore vendored
Wyświetl plik

@ -6,9 +6,39 @@ dump978/uat2json
dump978/uat2text
gen_gdl90
libdump978.so
fancontrol
*.mp4
*.img
*.zip
test/bmp180_read
test/es_dump_csv
test/extract_latlng
test/extract_metar
test/getairmet
test/icao2reg
test/maxgap
test/nexrad_annunciator
test/packetrate
test/replay
test/sensortest
test/uat_read
test/uatsummary
.DS_Store

8
.gitmodules vendored
Wyświetl plik

@ -1,6 +1,6 @@
[submodule "linux-mpu9150"]
path = linux-mpu9150
url = git://github.com/cyoung/linux-mpu9150
[submodule "dump1090"]
path = dump1090
url = https://github.com/AvSquirrel/dump1090
url = https://github.com/stratux/dump1090
[submodule "goflying"]
path = goflying
url = https://github.com/cyoung/goflying

Wyświetl plik

@ -2,17 +2,17 @@
2. Stratux config:
SDR
[ ] single
[ ] dual
- [ ] single
- [ ] dual
GPS
[ ] yes
[ ] no
- [ ] yes
- [ ] no
type:
AHRS
[ ] yes
[ ] no
- [ ] yes
- [ ] no
power source:

Wyświetl plik

@ -1,20 +1,25 @@
ifeq "$(CIRCLECI)" "true"
BUILDINFO=
PLATFORMDEPENDENT=
else
BUILDINFO=-ldflags "-X main.stratuxVersion=`git describe --tags --abbrev=0` -X main.stratuxBuild=`git log -n 1 --pretty=%H`"
LDFLAGS_VERSION=-X main.stratuxVersion=`git describe --tags --abbrev=0` -X main.stratuxBuild=`git log -n 1 --pretty=%H`
BUILDINFO=-ldflags "$(LDFLAGS_VERSION)"
BUILDINFO_STATIC=-ldflags "-extldflags -static $(LDFLAGS_VERSION)"
$(if $(GOROOT),,$(error GOROOT is not set!))
PLATFORMDEPENDENT=fancontrol
endif
all:
make xdump978
make xdump1090
make xlinux-mpu9150
make xgen_gdl90
make xdump978 xdump1090 xgen_gdl90 $(PLATFORMDEPENDENT)
xgen_gdl90:
go get -t -d -v ./main ./test ./linux-mpu9150/mpu ./godump978 ./mpu6050 ./uatparse
go build $(BUILDINFO) main/gen_gdl90.go main/traffic.go main/ry835ai.go main/network.go main/managementinterface.go main/sdr.go main/uibroadcast.go main/monotonic.go
go get -t -d -v ./main ./godump978 ./uatparse ./sensors
go build $(BUILDINFO) -p 4 main/gen_gdl90.go main/traffic.go main/gps.go main/network.go main/managementinterface.go main/sdr.go main/ping.go main/uibroadcast.go main/monotonic.go main/datalog.go main/equations.go main/sensors.go main/cputemp.go main/lowpower_uat.go
fancontrol:
go get -t -d -v ./main
go build $(BUILDINFO_STATIC) -p 4 main/fancontrol.go main/equations.go main/cputemp.go
xdump1090:
git submodule update --init
@ -24,10 +29,6 @@ xdump978:
cd dump978 && make lib
sudo cp -f ./libdump978.so /usr/lib/libdump978.so
xlinux-mpu9150:
git submodule update --init
cd linux-mpu9150 && make -f Makefile-native-shared
.PHONY: test
test:
make -C test
@ -38,15 +39,25 @@ www:
install:
cp -f gen_gdl90 /usr/bin/gen_gdl90
chmod 755 /usr/bin/gen_gdl90
cp init.d-stratux /etc/init.d/stratux
chmod 755 /etc/init.d/stratux
ln -sf /etc/init.d/stratux /etc/rc2.d/S01stratux
ln -sf /etc/init.d/stratux /etc/rc6.d/K01stratux
cp -f fancontrol /usr/bin/fancontrol
chmod 755 /usr/bin/fancontrol
-/usr/bin/fancontrol remove
/usr/bin/fancontrol install
cp image/10-stratux.rules /etc/udev/rules.d/10-stratux.rules
cp image/99-uavionix.rules /etc/udev/rules.d/99-uavionix.rules
rm -f /etc/init.d/stratux
cp __lib__systemd__system__stratux.service /lib/systemd/system/stratux.service
cp __root__stratux-pre-start.sh /root/stratux-pre-start.sh
chmod 644 /lib/systemd/system/stratux.service
chmod 744 /root/stratux-pre-start.sh
ln -fs /lib/systemd/system/stratux.service /etc/systemd/system/multi-user.target.wants/stratux.service
make www
cp -f libdump978.so /usr/lib/libdump978.so
cp -f dump1090/dump1090 /usr/bin/
cp -f image/hostapd_manager.sh /usr/sbin/
cp -f image/stratux-wifi.sh /usr/sbin/
clean:
rm -f gen_gdl90 libdump978.so
rm -f gen_gdl90 libdump978.so fancontrol ahrs_approx
cd dump1090 && make clean
cd dump978 && make clean
rm -f linux-mpu9150/*.o linux-mpu9150/*.so

Wyświetl plik

@ -1,22 +1,31 @@
[![stratux version](https://img.shields.io/github/tag/cyoung/stratux.svg?style=flat&label=stratux)](https://github.com/cyoung/stratux/releases)
[![Build Status](http://circleci-badges-max.herokuapp.com/img/cyoung/stratux/master?token=:circle-ci-token)](https://circleci.com/gh/cyoung/stratux/tree/master)
[![stratux version](https://img.shields.io/github/tag/cyoung/stratux.svg?style=flat&label=stratux)](https://github.com/b3nn0/stratux/releases)
[![BSD3 License](http://img.shields.io/badge/license-BSD3-brightgreen.svg)](https://tldrlegal.com/license/bsd-3-clause-license-%28revised%29)
# stratux
[![](https://dcbadge.limes.pink/api/server/https://discord.gg/D9NQ6xe4nF)](https://discord.gg/D9NQ6xe4nF)
# Stratux - deprecated branch (as of 2020)
This branch is no longer maintained. Do not report issues here! Active development is taking place on the [@b3nn0 branch](https://github.com/b3nn0/stratux).
**[Current branch](https://github.com/b3nn0/stratux)**
[Current release](https://github.com/b3nn0/stratux/releases)
[Stratux developer Discord](https://discord.gg/D9NQ6xe4nF)
## History
Stratux was founded in 2015 by [@cyoung](https://github.com/cyoung) and other developers with the mission of creating an open-source, modular, ADS-B solution using affordable microchips and a Raspberry Pi board. After building the project to include a dual band receiver, GPS, and AHRS [@cyoung](https://github.com/cyoung) moved on to other projects in 2020. [@b3nn0](https://github.com/b3nn0) took the reins as the main developer building out many features for the OpenGliderNetwork (OGN) and other Europe specific enhancements while maintaining the Stratux code base for users around the world.
Stratux is still under active development with hardward upgrades, new features, [Reddit](https://www.reddit.com/r/stratux) and [Discord](https://discord.gg/D9NQ6xe4nF) communities. You can find parts, pre-built units, and build guides on the [Stratux website](http://stratux.me). You can also [support the developers](https://www.paypal.com/paypalme/stratuxeu) or reach out to the community with new ideas.
## Old readme
RTL-SDR UAT tools
Use with Raspberry Pi 3B. The 3B+ and Pi 4B will work but use a lot more power.
Use Pi 2 and ForeFlight 7.3.1 (1792) (Sep 18, 2015).
Supported WiFi adapters:
* Edimax EW-7811Un
Tested RTL-SDR:
* NooElec NESDR Nano 2 (best)
* NooElec NESDR Mini 2
* Generic R820T (degraded performance)
Tested and works well with most common R820T and R820T2 RTL-SDR devices.
Apps with stratux recognition/support:
* ForeFlight 10+ - weather, traffic, AHRS.
* Seattle Avionics FlyQ EFB 2.1.1+.
* AvNav EFB 2.0.0+.
* Naviator.
@ -25,13 +34,30 @@ Apps with stratux recognition/support:
* AerovieReports.
* AvPlan EFB.
* iFly GPS 9.4+.
* DroidEFB 2.1.1+.
* kwikEFIS
* Pilots Atlas
Tested weather/traffic displays:
* ForeFlight 7+ - weather, traffic, AHRS.
* Avare
Other EFBs? See the [app vendor integration guide](https://github.com/cyoung/stratux/blob/master/notes/app-vendor-integration.md).
Questions? [See the FAQ](https://github.com/cyoung/stratux/wiki/FAQ)
http://stratux.me/
http://slack.stratux.me/
https://www.reddit.com/r/stratux
Jet tests (high gain antennas):
* Dassault Falcon 20
* Embraer ERJ 145
* Cessna Citation 501
* Citation Sovereign+
* Lear 35
* Rockwell B-1b
* Boeing C-17
* Gulfstream G450

Wyświetl plik

@ -0,0 +1,16 @@
[Unit]
Description=Stratux
After=network.target
[Service]
ExecStartPre=/root/stratux-pre-start.sh
ExecStart=/usr/bin/gen_gdl90
ExecStop=/usr/bin/pkill dump1090
KillMode=process
Restart=always
RestartSec=5
LimitCORE=1073741824
[Install]
WantedBy=multi-user.target

Wyświetl plik

@ -0,0 +1,41 @@
#!/bin/bash
echo powersave >/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
#Logging Function
SCRIPT=`basename ${BASH_SOURCE[0]}`
STX_LOG="/var/log/stratux.log"
function wLog () {
echo "$(date +"%Y/%m/%d %H:%m:%S") - $SCRIPT - $1" >> ${STX_LOG}
}
wLog "Running Stratux Updater Script."
SCRIPT_MASK="update*stratux*v*.sh"
TEMP_LOCATION="/boot/StratuxUpdates/$SCRIPT_MASK"
UPDATE_LOCATION="/root/$SCRIPT_MASK"
if [ -e ${TEMP_LOCATION} ]; then
wLog "Found Update Script in $TEMP_LOCATION$SCRIPT_MASK"
TEMP_SCRIPT=`ls -1t ${TEMP_LOCATION} | head -1`
wLog "Moving Script $TEMP_SCRIPT"
cp -r ${TEMP_SCRIPT} /root/
wLog "Changing permissions to chmod a+x $UPDATE_LOCATION"
chmod a+x ${UPDATE_LOCATION}
wLog "Removing Update file from $TEMP_LOCATION"
rm -rf ${TEMP_SCRIPT}
fi
# Check if we need to run an update.
if [ -e ${UPDATE_LOCATION} ]; then
UPDATE_SCRIPT=`ls -1t ${UPDATE_LOCATION} | head -1`
if [ -n ${UPDATE_SCRIPT} ] ; then
# Execute the script, remove it, then reboot.
wLog "Running update script ${UPDATE_SCRIPT}..."
bash ${UPDATE_SCRIPT}
wLog "Removing Update SH"
rm -f ${UPDATE_SCRIPT}
wLog "Finished... Rebooting... Bye"
reboot
fi
fi
wLog "Exited without updating anything..."

Wyświetl plik

@ -5,13 +5,13 @@ machine:
dependencies:
pre:
- sudo apt-get update; sudo apt-get install libusb-1.0-0-dev; cd ~/; git clone https://github.com/jpoirier/librtlsdr; cd librtlsdr; mkdir build; cd build; cmake ../; make; sudo make install; sudo ldconfig; cd ~/; mkdir gopath; cd ~/; mkdir gopath; wget https://storage.googleapis.com/golang/go1.6.src.tar.gz; tar -zxvf go1.6.src.tar.gz; cd go/src; export GOROOT_BOOTSTRAP=/usr/local/go; ./make.bash; echo $PATH; echo $GOPATH; go version; env
- sudo apt-get update; sudo apt-get install libusb-1.0-0-dev mercurial; cd ~/; git clone https://github.com/jpoirier/librtlsdr; cd librtlsdr; mkdir build; cd build; cmake ../; make; sudo make install; sudo ldconfig; cd ~/; rm -rf gopath; mkdir gopath; wget https://dl.google.com/go/go1.9.2.linux-amd64.tar.gz; tar -zxvf go1.9.2.linux-amd64.tar.gz; go version; env
override:
- cd .. ; rm -rf stratux ; git clone --recursive https://github.com/cyoung/stratux ; cd stratux ; make
- cd .. ; rm -rf stratux ; git clone --recursive https://github.com/cyoung/stratux ; cd stratux ; git config --add remote.origin.fetch "+refs/pull/*/head:refs/remotes/origin/pr/*" ; git fetch origin ; BRANCH=`echo "$CIRCLE_BRANCH" | sed 's/pull\//pr\//g'` ; git checkout $BRANCH ; make
test:
override:
- make test
- make
deployment:
production:

Plik binarny nie jest wyświetlany.

Plik binarny nie jest wyświetlany.

Wyświetl plik

@ -144,10 +144,21 @@ void make_atan2_table(void) {
}
static void convert_to_phi(uint16_t *dest, uint16_t *src, int n) {
int i;
int i;
for (i = 0; i < n; ++i)
dest[i] = iqphase[src[i]];
// unroll the loop. n is always > 2048, usually 36864
for (i = 0; i+8 <= n; i += 8) {
dest[i] = iqphase[src[i]];
dest[i+1] = iqphase[src[i+1]];
dest[i+2] = iqphase[src[i+2]];
dest[i+3] = iqphase[src[i+3]];
dest[i+4] = iqphase[src[i+4]];
dest[i+5] = iqphase[src[i+5]];
dest[i+6] = iqphase[src[i+6]];
dest[i+7] = iqphase[src[i+7]];
}
for (; i < n; ++i)
dest[i] = iqphase[src[i]];
}
static void calc_power(uint16_t *samples, int len) { // sets signal_strength to scaled amplitude. 0 = no signal, 1000 = saturated receiver on all samples in measurement.

Wyświetl plik

@ -28,7 +28,7 @@ package godump978
#include <stdint.h>
#include "../dump978/dump978.h"
extern void dump978Cb(char updown, uint8_t *data, int len);
extern void dump978Cb(char updown, uint8_t *data, int len, int rs_errors, int signal_strength);
static inline CallBack GetGoCb() {
return (CallBack)dump978Cb;
}
@ -42,10 +42,9 @@ var PackageVersion = "v0.1"
// InChan is a buffered input channel for raw data.
var InChan = make(chan []byte, 100)
type UserCbT func(C.char, *C.uint8_t, C.int)
type UserCbT func(C.char, *C.uint8_t, C.int, C.int, C.int)
// Dump978Init must be the first function called in this package.
func Dump978Init() {
func init() {
C.Dump978Init((C.CallBack)(C.GetGoCb()))
}

Wyświetl plik

@ -12,9 +12,10 @@ import (
"unsafe"
"strconv"
)
// #cgo CFLAGS: -L../
/*
#cgo CFLAGS: -L../
#include <stdint.h>
#include "../dump978/dump978.h"
*/

1
goflying 160000

@ -0,0 +1 @@
Subproject commit 1da95360a858bfdc5af2b4e7d5caa66542f164e1

Wyświetl plik

@ -0,0 +1,48 @@
# To be placed in /etc/udev/rules.d.
# Auto-detect common USB stratux peripherals.
# u-blox devices. Known devices include
# ublox9: experimental boards
# ublox8: RY835AI, RY836AI, GPYes 2.0
# ublox7: VK-172, RY725AI, GPYes
# ublox6: VK-162
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1546", ATTRS{idProduct}=="01a9", SYMLINK+="ublox9"
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1546", ATTRS{idProduct}=="01a8", SYMLINK+="ublox8"
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1546", ATTRS{idProduct}=="01a7", SYMLINK+="ublox7"
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1546", ATTRS{idProduct}=="01a6", SYMLINK+="ublox6"
#SUBSYSTEMS=="usb", ATTRS{idVendor}=="1546", ATTRS{idProduct}=="01a7", SYMLINK+="vk172"
#SUBSYSTEMS=="usb", ATTRS{idVendor}=="1546", ATTRS{idProduct}=="01a6", SYMLINK+="vk162"
# Stratux uatradio.
# 0403:7028 (Stratux UATRadio)
ATTRS{idProduct}=="7028", ATTRS{idVendor}=="0403", RUN+="/sbin/modprobe -q ftdi_sio" RUN+="/bin/sh -c 'echo 0403 7028 > /sys/bus/usb-serial/drivers/ftdi_sio/new_id'", OWNER="root", MODE="0666", SYMLINK+="uatradio"
# pl2303 devices are indistinguishable using idVendor and idProduct.
# Currently the BU-353-S4 and the TU-S9 (serialout) use the pl2303.
SUBSYSTEMS=="usb", ATTRS{idVendor}=="067b", ATTRS{idProduct}=="2303", SYMLINK+="prolific%n"
#SUBSYSTEMS=="usb", ATTRS{idVendor}=="067b", ATTRS{idProduct}=="2303", SYMLINK+="bu353s4"
#SUBSYSTEMS=="usb", ATTRS{idVendor}=="067b", ATTRS{idProduct}=="2303", SYMLINK+="tu-s9"
# CP2102-based serial adapters. Assume that all devices plugged in with this idVendor and idProduct are for serialout.
#cp210x-program --write-cp210x -m 10C4:EA60 \
# --set-product-string="Stratux Serialout" \
# --set-max-power=100 \
# --set-bus-powered=no
SUBSYSTEMS=="usb", ATTRS{interface}=="Stratux Serialout", SYMLINK+="serialout%n"
# SoftRF.
# SoftRF Standalone (NodeMCU or DoIt ESP32 devkit with CP2102 chip)
SUBSYSTEMS=="usb", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", ATTRS{product}=="DIY SoftRF", SYMLINK+="softrf"
# TTGO T-Beam (ESP32 with OTP CP2104 chip)
SUBSYSTEMS=="usb", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", ATTRS{product}=="CP2104 USB to UART Bridge Controller", SYMLINK+="softrf"
# Dongle Edition (LilyGO & SoftRF T-Motion. USB CDC ACM output)
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="5740", SYMLINK+="softrf"
# end of SoftRF section

Wyświetl plik

@ -0,0 +1,6 @@
# uAvionix Ping Mavlink
ATTRS{idProduct}=="74f0", ATTRS{idVendor}=="0403", RUN+="/sbin/modprobe -q ftdi_sio" RUN+="/bin/sh -c 'echo 0403 74f0 > /sys/bus/usb-serial/drivers/ftdi_sio/new_id'", OWNER="root", MODE="0666", SYMLINK+="ping"
# uAvionix Ping Raw
ATTRS{idProduct}=="74f1", ATTRS{idVendor}=="0403", RUN+="/sbin/modprobe -q ftdi_sio" RUN+="/bin/sh -c 'echo 0403 74f1 > /sys/bus/usb-serial/drivers/ftdi_sio/new_id'", OWNER="root", MODE="0666", SYMLINK+="ping"

31
image/bashrc.txt 100644
Wyświetl plik

@ -0,0 +1,31 @@
# ~/.bashrc: executed by bash(1) for non-login shells.
# Note: PS1 and umask are already set in /etc/profile. You should not
# need this unless you want different defaults for root.
# PS1='${debian_chroot:+($debian_chroot)}\h:\w\$ '
# umask 022
# You may uncomment the following lines if you want `ls' to be colorized:
# export LS_OPTIONS='--color=auto'
# eval "`dircolors`"
# alias ls='ls $LS_OPTIONS'
# alias ll='ls $LS_OPTIONS -l'
# alias l='ls $LS_OPTIONS -lA'
#
# Some more alias to avoid making mistakes:
# alias rm='rm -i'
# alias cp='cp -i'
# alias mv='mv -i'
export PATH=/root/go/bin:${PATH}
export GOROOT=/root/go
export GOPATH=/root/go_path
# This will allow users to keep an alias file after this file is added
if [ -f /root/.aliases ]; then
. /root/.aliases
fi
# Useful aliases for stratux debugging
if [ -f /root/.stxAliases ]; then
. /root/.stxAliases
fi

20
image/config.txt 100644
Wyświetl plik

@ -0,0 +1,20 @@
# RPi /boot/config.txt
dtparam=audio=on
max_usb_current=1
dtparam=i2c_arm=on
dtparam=i2c1=on
dtparam=i2c1_baudrate=400000
dtparam=i2c_arm_baudrate=400000
# move RPi3 Bluetooth off of hardware UART to free up connection for GPS
dtoverlay=pi3-miniuart-bt
# disable default (mmc0) behavior on the ACT LED.
dtparam=act_led_trigger=none
dtparam=act_led_activelow=off
# The below has been added as a proposed EMI reduction measure. Issue #573.
sdram_freq=450
core_freq=450
arm_freq=900

Wyświetl plik

@ -0,0 +1,14 @@
ddns-update-style none;
default-lease-time 86400; # 24 hours
max-lease-time 172800; # 48 hours
authoritative;
log-facility local7;
subnet 192.168.10.0 netmask 255.255.255.0 {
range 192.168.10.10 192.168.10.50;
option broadcast-address 192.168.10.255;
option routers 192.168.10.1;
default-lease-time 12000;
max-lease-time 12000;
option domain-name "stratux.local";
option domain-name-servers 4.2.2.2;
}

Wyświetl plik

@ -0,0 +1,13 @@
ddns-update-style none;
default-lease-time 86400; # 24 hours
max-lease-time 172800; # 48 hours
authoritative;
log-facility local7;
subnet 192.168.10.0 netmask 255.255.255.0 {
range 192.168.10.10 192.168.10.50;
option broadcast-address 192.168.10.255;
default-lease-time 12000;
max-lease-time 12000;
option domain-name "stratux.local";
option domain-name-servers 4.2.2.2;
}

Wyświetl plik

@ -1,117 +0,0 @@
#
# Sample configuration file for ISC dhcpd for Debian
#
#
# The ddns-updates-style parameter controls whether or not the server will
# attempt to do a DNS update when a lease is confirmed. We default to the
# behavior of the version 2 packages ('none', since DHCP v2 didn't
# have support for DDNS.)
ddns-update-style none;
# option definitions common to all supported networks...
#option domain-name "stratux.local";
#option domain-name-servers ns1.example.org, ns2.example.org;
default-lease-time 86400; # 24 hours
max-lease-time 172800; # 48 hours
# If this DHCP server is the official DHCP server for the local
# network, the authoritative directive should be uncommented.
authoritative;
# Use this to send dhcp log messages to a different log file (you also
# have to hack syslog.conf to complete the redirection).
log-facility local7;
# No service will be given on this subnet, but declaring it helps the
# DHCP server to understand the network topology.
#subnet 10.152.187.0 netmask 255.255.255.0 {
#}
# This is a very basic subnet declaration.
#subnet 10.254.239.0 netmask 255.255.255.224 {
# range 10.254.239.10 10.254.239.20;
# option routers rtr-239-0-1.example.org, rtr-239-0-2.example.org;
#}
# This declaration allows BOOTP clients to get dynamic addresses,
# which we don't really recommend.
#subnet 10.254.239.32 netmask 255.255.255.224 {
# range dynamic-bootp 10.254.239.40 10.254.239.60;
# option broadcast-address 10.254.239.31;
# option routers rtr-239-32-1.example.org;
#}
# A slightly different configuration for an internal subnet.
#subnet 10.5.5.0 netmask 255.255.255.224 {
# range 10.5.5.26 10.5.5.30;
# option domain-name-servers ns1.internal.example.org;
# option domain-name "internal.example.org";
# option routers 10.5.5.1;
# option broadcast-address 10.5.5.31;
# default-lease-time 600;
# max-lease-time 7200;
#}
# Hosts which require special configuration options can be listed in
# host statements. If no address is specified, the address will be
# allocated dynamically (if possible), but the host-specific information
# will still come from the host declaration.
#host passacaglia {
# hardware ethernet 0:0:c0:5d:bd:95;
# filename "vmunix.passacaglia";
# server-name "toccata.fugue.com";
#}
# Fixed IP addresses can also be specified for hosts. These addresses
# should not also be listed as being available for dynamic assignment.
# Hosts for which fixed IP addresses have been specified can boot using
# BOOTP or DHCP. Hosts for which no fixed address is specified can only
# be booted with DHCP, unless there is an address range on the subnet
# to which a BOOTP client is connected which has the dynamic-bootp flag
# set.
#host fantasia {
# hardware ethernet 08:00:07:26:c0:a5;
# fixed-address fantasia.fugue.com;
#}
# You can declare a class of clients and then do address allocation
# based on that. The example below shows a case where all clients
# in a certain class get addresses on the 10.17.224/24 subnet, and all
# other clients get addresses on the 10.0.29/24 subnet.
#class "foo" {
# match if substring (option vendor-class-identifier, 0, 4) = "SUNW";
#}
#shared-network 224-29 {
# subnet 10.17.224.0 netmask 255.255.255.0 {
# option routers rtr-224.example.org;
# }
# subnet 10.0.29.0 netmask 255.255.255.0 {
# option routers rtr-29.example.org;
# }
# pool {
# allow members of "foo";
# range 10.17.224.10 10.17.224.250;
# }
# pool {
# deny members of "foo";
# range 10.0.29.10 10.0.29.230;
# }
#}
subnet 192.168.10.0 netmask 255.255.255.0 {
range 192.168.10.10 192.168.10.50;
option broadcast-address 192.168.10.255;
default-lease-time 12000;
max-lease-time 12000;
option domain-name "stratux.local";
option domain-name-servers 4.2.2.2;
}

Plik binarny nie jest wyświetlany.

Wyświetl plik

@ -0,0 +1,6 @@
interface=wlan0
driver=rtl871xdrv
hw_mode=g
wme_enabled=1
ieee80211n=1
ignore_broadcast_ssid=0

Wyświetl plik

@ -1,8 +1,5 @@
interface=wlan0
driver=rtl871xdrv
ssid=stratux
hw_mode=g
channel=1
wme_enabled=1
wmm_enabled=1
ieee80211n=1
ignore_broadcast_ssid=0

Wyświetl plik

@ -0,0 +1,319 @@
#!/bin/bash
######################################################################
# STRATUX HOSTAPD MANAGER #
######################################################################
#Logging Function
SCRIPT=`basename ${BASH_SOURCE[0]}`
STX_LOG="/var/log/stratux.log"
function wLog () {
echo "$(date +"%Y/%m/%d %H:%m:%S") - $SCRIPT - $1" >> $STX_LOG
}
wLog "Running Hostapd Manager Script."
# files to edit
HOSTAPD=('/etc/hostapd/hostapd.user')
# values to be added to hostapd.user for security.
HOSTAPD_SECURE_VALUES_DELETE=('auth_algs=1' 'wpa=3' 'wpa_passphrase=' 'wpa_key_mgmt=WPA-PSK' 'wpa_pairwise=TKIP' 'rsn_pairwise=CCMP')
# 'wpa_passphrase=' was left out of this to set it with the $wifiPass. I assume you can not evaluate a variable from within an array variable
HOSTAPD_SECURE_VALUES_WRITE=('auth_algs=1' 'wpa=3' 'wpa_key_mgmt=WPA-PSK' 'wpa_pairwise=TKIP' 'rsn_pairwise=CCMP')
#Initialize variables to default values.
OPT_S=false
OPT_C=false
OPT_E=false
OPT_O=false
OPT_P=false
wifiPass="SquawkDirtyToMe!"
parm="*"
err="####"
att="+++"
#Set fonts for Help.
BOLD=$(tput bold)
STOT=$(tput smso)
UNDR=$(tput smul)
REV=$(tput rev)
RED=$(tput setaf 1)
GREEN=$(tput setaf 2)
YELLOW=$(tput setaf 3)
MAGENTA=$(tput setaf 5)
WHITE=$(tput setaf 7)
NORM=$(tput sgr0)
NORMAL=$(tput sgr0)
#Help function
function HELP {
echo -e \\n"Help documentation for ${BOLD}${SCRIPT}.${NORM}"\\n
echo -e "${REV}Basic usage:${NORM} ${BOLD}$SCRIPT -s ssid -c chan -p pass ${NORM}"\\n
echo "The following command line switches are recognized."
echo "${REV}-s${NORM} --Sets the SSID to ${BOLD}ssid${NORM}. \"-s stratux\""
echo "${REV}-c${NORM} --Sets the channel to ${BOLD}chan${NORM}. \"-c 1\""
echo "${REV}-o${NORM} --Turns off encryption and sets network to open. Cannot be used with -e or -p."
echo "${REV}-e${NORM} --Turns on encryption with passphrase ${BOLD}$wifiPass${NORM}. Cannot be used with -o or -p"
echo "${REV}-p${NORM} --Turns on encryption with your chosen passphrase ${BOLD}pass${NORM}. 8-63 Printable Characters(ascii 32-126). Cannot be used with -o or -e. \"-p password!\""
echo -e "${REV}-h${NORM} --Displays this help message. No further functions are performed."\\n
echo -e "Example: ${BOLD}$SCRIPT -s Stratux-N3558D -c 5 -p SquawkDirty!${NORM}"\\n
exit 1
}
function confirm() {
# call with a prompt string or use a default
read -r -p "$1 " response
case "$response" in
[yY][eE][sS]|[yY])
true
;;
*)
exit 1
;;
esac
}
function cleanhostapd () {
wLog "Cleaning hostapd config at $1"
for j in "${HOSTAPD_SECURE_VALUES_DELETE[@]}"
do
sed -i "/$j/ d" ${1}
done
sed -i '/^\s*$/d' ${1}
}
function writehostapd () {
wLog "Writing hostapd config at $1"
sed -i '/^\s*$/d' ${1}
echo "" >> ${1}
for j in "${HOSTAPD_SECURE_VALUES_WRITE[@]}"
do
echo "${j}" >> ${1}
done
echo "wpa_passphrase=$wifiPass" >> ${1}
}
#apply settings and restart all processes
function APPLYSETTINGS {
wLog "Restarting all wifi settings."
echo "${RED}${BOLD} $att At this time the script will restart your WiFi services.${WHITE}${NORMAL}"
echo "If you are connected to Stratux through the ${BOLD}192.168.10.1${NORMAL} interface then you will be disconnected"
echo "Please wait up to 1 min and look for the new SSID on your wireless device."
sleep 3
echo "${YELLOW}$att Restarting Stratux WiFi Services... $att ${WHITE}"
echo "${YELLOW}$att SSH will now disconnect if connected to http://192.168.10.1 ... $att ${WHITE}"
echo "ifdown wlan0..."
ifdown wlan0
sleep 0.5
echo "ifup wlan0..."
echo "Calling Stratux WiFI Start Script(stratux-wifi.sh) via ifup wlan0..."
ifup wlan0
sleep 0.5
echo ""
echo ""
echo "All systems should be up and running and you should see your new SSID!"
}
clear
echo ""
echo "#### Stratux HOSTAPD Settings ####"
echo ""
if [ $(whoami) != 'root' ]; then
echo "${BOLD}${RED}This script must be executed as root, exiting...${WHITE}${NORMAL}"
echo "${BOLD}${RED}USAGE${WHITE}${NORMAL}"
exit 1
fi
#Check the number of arguments. If none are passed, print help and exit.
NUMARGS=$#
if [ $NUMARGS -eq 0 ]; then
HELP
fi
### Start getopts code ###
#Parse command line flags
#If an option should be followed by an argument, it should be followed by a ":".
#Notice there is no ":" after "eoqh". The leading ":" suppresses error messages from
#getopts. This is required to get my unrecognized option code to work.
options=':s:c:p:eoh'
#options=':s:c:h'
while getopts $options option; do
case $option in
s) #set option "s"
if [[ -z "${OPTARG}" || "${OPTARG}" == *[[:space:]]* || "${OPTARG}" == -* ]]; then
echo "${BOLD}${RED}$err No SSID for -s, exiting...${WHITE}${NORMAL}"
wLog "No SSID for -s, exiting..."
exit 1
else
OPT_S=$OPTARG
echo "$parm SSID Option -s used: $OPT_S"
echo "${GREEN} SSID will now be ${BOLD}${UNDR}$OPT_S${NORMAL}.${WHITE}"
fi
;;
c) #set option "c"
if [[ -z "${OPTARG}" || "${OPTARG}" == *[[:space:]]* || "${OPTARG}" == -* ]]; then
echo "${BOLD}${RED}$err Channel option(-c) used without value, exiting... ${WHITE}${NORMAL}"
wLog "Channel option(-c) used without value, exiting..."
exit 1
else
OPT_C=$OPTARG
echo "$parm Channel option -c used: $OPT_C"
if [[ "$OPT_C" =~ ^[0-9]+$ ]] && [ "$OPT_C" -ge 1 -a "$OPT_C" -le 13 ]; then
echo "${GREEN} Channel will now be set to ${BOLD}${UNDR}$OPT_C${WHITE}${NORMAL}."
else
echo "${BOLD}${RED}$err Channel is not within acceptable values, exiting...${WHITE}${NORMAL}"
wLog "Channel is not within acceptable values, exiting..."
exit 1
fi
fi
;;
e) #set option "e" with default passphrase
if [[ -z "${OPTARG}" || "${OPTARG}" == *[[:space:]]* || "${OPTARG}" == -* ]]; then
echo "$parm Encrypted WiFI Option -e used."
OPT_E=$wifiPass
echo "${GREEN} WiFi will be encrypted using ${BOLD}${UNDR}$OPT_E${NORMAL}${GREEN} as the passphrase!${WHITE}${NORMAL}"
else
echo "${BOLD}${RED}$err Option -e does not require argument. exiting...${WHITE}${NORMAL}"
wLog "Option -e does not require argument."
exit 1
fi
;;
p) #set encryption with user specified passphrase
if [[ -z "${OPTARG}" || "${OPTARG}" =~ ^[[:space:]]*$ || "${OPTARG}" == -* ]]; then
echo "${BOLD}${RED}$err Encryption option(-p) used without passphrase!${WHITE}${NORMAL}"
echo "${BOLD}${RED}$err Encryption option(-p) required an argument \"-p passphrase\". exiting...${WHITE}${NORMAL}"
wLog "Encryption option(-p) used without passphrase!"
else
OPT_P=$OPTARG
wifiPass=$OPTARG
fi
echo "$parm Encryption option -p used:"
if [ -z `echo $OPT_P | tr -d "[:print:]"` ] && [ ${#OPT_P} -ge 8 ] && [ ${#OPT_P} -le 63 ]; then
echo "${GREEN} WiFi will be encrypted using ${BOLD}${UNDR}$OPT_P${NORMAL}${GREEN} as the passphrase!${WHITE}${NORMAL}"
else
echo "${BOLD}${RED}$err Invalid PASSWORD: 8 - 63 printable characters, exiting...${WHITE}${NORMAL}"
wLog "Invalid PASSWORD: 8 - 63 printable characters, exiting..."
exit 1
fi
;;
o) #set option "o"
if [[ -z "${OPTARG}" || "${OPTARG}" == *[[:space:]]* || "${OPTARG}" == -* ]]; then
echo "$parm Open WiFI Option -o used."
echo "${GREEN} WiFi will be set to ${BOLD}${UNDR}OPEN${NORMAL}${GREEN} or ${BOLD}${UNDR}UNSECURE${WHITE}${NORMAL}"
OPT_O=true
else
echo "${BOLD}${RED}$err Option -o does not require argument. exiting...${WHITE}${NORMAL}"
wLog "Option -o does not require argument. exiting..."
exit 1
fi
;;
h) #show help
HELP
;;
\?) # invalid option
echo "${BOLD}${RED}$err Invalid option -$OPTARG ${WHITE}${NORMAL}" >&2
HELP
exit 1
;;
:) # Missing Arg
echo "${BOLD}${RED}$err Missing option for argument -$OPTARG ${WHITE}${NORMAL}" >&2
HELP
exit 1
;;
*) # Invalid
echo "${BOLD}${RED}$err Unimplemented option -$OPTARG ${WHITE}${NORMAL}" >&2
HELP
exit 1
;;
esac
done
shift $((OPTIND-1)) #This tells getopts to move on to the next argument.
### End getopts code ###
### Main loop to process files ###
#This is where your main file processing will take place. This example is just
#printing the files and extensions to the terminal. You should place any other
#file processing tasks within the while-do loop.
if [[ $OPT_O == true && ( $OPT_E != false || $OPT_P != false ) ]]; then
echo "${BOLD}${RED}$err Option -e , -p and -o cannot be used simultaneously. Exiting... ${WHITE}${NORMAL}"
wLog "Option -e , -p and -o cannot be used simultaneously."
exit 1
fi
if [ $OPT_P != false ] && [ $OPT_E != false ]; then
echo "${BOLD}${RED}$err Option -e and -p cannot be used simultaneously. Exiting... ${WHITE}${NORMAL}"
wLog "Option -e and -p cannot be used simultaneously."
exit 1
fi
echo ""
echo "${BOLD}No errors found. Continuing...${NORMAL}"
echo ""
confirm "Are you ready to apply these settings? [y/n]"
####
#### File modification loop
####
for i in "${HOSTAPD[@]}"
do
if [ -f ${i} ]; then
echo "Working on $i..."
wLog "Working on $i..."
if [ $OPT_S != false ]; then
wLog "Writing SSID $OPT_S to file $i"
echo "${MAGENTA}Setting ${YELLOW}SSID${MAGENTA} to ${YELLOW}$OPT_S ${MAGENTA}in $i...${WHITE}"
if grep -q "^ssid=" ${HOSTAPD[$x]}; then
sed -i "s/^ssid=.*/ssid=${OPT_S}/" ${i}
else
echo ${OPT_S} >> ${i}
fi
fi
if [ $OPT_C != false ]; then
wLog "Writing channel $OPT_C to file $i"
echo "${MAGENTA}Setting ${YELLOW}Channel${MAGENTA} to ${YELLOW}$OPT_C ${MAGENTA}in $i...${WHITE}"
if grep -q "^channel=" ${i}; then
sed -i "s/^channel=.*/channel=${OPT_C}/" ${i}
else
echo ${OPT_C} >> ${i}
fi
fi
if [ $OPT_E != false ] || [ $OPT_P != false ]; then
wLog "Writing security and setting passphrase to $wifiPass to file $i"
echo "${MAGENTA}Adding WPA encryption with passphrase: ${YELLOW}$wifiPass ${MAGENTA}to $i...${WHITE}"
cleanhostapd $i
writehostapd $i
fi
if [ $OPT_O != false ]; then
wLog "Removing WiFi security in file $i"
echo "${MAGENTA}Removing WPA encryption in $i...${WHITE}"
cleanhostapd $i
fi
echo "${GREEN}Modified ${i}...done${WHITE}"
echo ""
else
echo "${MAGENTA}No ${i} file found...${WHITE}${NORMAL}"
echo ""
fi
done
### End main loop ###
### Apply Settings and restart all services
APPLYSETTINGS
exit 0

Wyświetl plik

@ -1,35 +1,59 @@
auto lo
iface lo inet loopback
allow-hotplug eth0
iface eth0 inet dhcp
allow-hotplug wlan0
#iface wlan0 inet manual
#wpa-roam /etc/wpa_supplicant/wpa_supplicant.conf
#iface default inet dhcp
iface wlan0 inet static
address 192.168.10.1
netmask 255.255.255.0
post-up /usr/sbin/stratux-wifi.sh
wireless-power off
#####################################################################
## Custom settings not for novice users!!!!!!
## Modify at your own risk!!!!!!!!!!!!!!!!!!!
##
## Second Wifi Dongle for local work and internet access
## wifi mist be open for these settings to work
## This template is for adding a second wifi dongle to your PI for internet access while debugging
## Modify /etc/wpa_supplicant/wpa_supplicant.conf with your settings also( see below )
##
## uncomment the next two lines to activate the service as well as modify the settings and comments below
#allow-hotplug wlan1
#iface wlan1 inet static
## Uncomment the following lines as needed.
# The SSID you want to connect to
# uncomment the next line and modify if necessary
# wireless-essid 6719
# The address you want to use on your network
# uncomment the next line and modify if necessary
# address 192.168.1.50
# The address of your netmask
# uncomment the next line and modify if necessary
# netmask 255.255.255.0
# The gateway of your router that you are connecting to
# uncomment the next line and modify
# gateway 192.168.1.1
# allow-hotplug wlan1
# iface wlan1 inet manual
# wpa-roam /etc/wpa_supplicant/wpa_supplicant.conf
# iface name_of_WPA_Config inet dhcp
# iface name_of_other_WPA_Config inet dhcp
## End of interfaces
#contents of wpa_supplicant.conf
#############################################################
# ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
# update_config=1
# network={
# ssid="SSID_1"
# id_str="name_of_WPA_Config"
# scan_ssid=1
# key_mgmt=WPA-PSK
# psk="mypassword"
# priority=1
# }
# network={
# ssid="SSID_2"
# id_str="name_of_other_WPA_Config"
# scan_ssid=1
# key_mgmt=WPA-PSK
# psk="mypassword"
# priority=3
# }
#############################################################

Wyświetl plik

@ -0,0 +1,32 @@
# see "man logrotate" for details
# rotate log files weekly
daily
# keep 2 days worth of backlogs
rotate 2
# create new (empty) log files after rotating old ones
create
# uncomment this if you want your log files compressed
compress
# packages drop log rotation information into this directory
include /etc/logrotate.d
# no packages own wtmp, or btmp -- we'll rotate them here
/var/log/wtmp {
missingok
monthly
create 0664 root utmp
rotate 1
}
/var/log/btmp {
missingok
monthly
create 0660 root utmp
rotate 1
}
# system-specific logs may be configured here

Wyświetl plik

@ -0,0 +1,12 @@
# Keep 10 days of stratux logfiles.
/var/log/stratux.log
{
rotate 10
daily
missingok
notifempty
compress
postrotate
/usr/bin/killall -HUP gen_gdl90
endscript
}

172
image/mkimg.sh 100755
Wyświetl plik

@ -0,0 +1,172 @@
#!/bin/bash
#kpartx -a asdfsadf.img
##dd if=/dev/zero bs=1M count=200 >>2016-02-26-raspbian-jessie-lite.img
#mount root partition
##mount -o loop,offset=67108864 2016-02-26-raspbian-jessie-lite.img mnt/
##resize2fs /dev/loop0
#mount boot partition
##mount -o loop,offset=4194304 2016-02-26-raspbian-jessie-lite.img mnt/boot/
chroot mnt/ apt-get update
#update firmware
chroot mnt/ apt-get -y install rpi-update
chroot mnt/ rpi-update
#wifi
chroot mnt/ apt-get install -y hostapd isc-dhcp-server
#troubleshooting
chroot mnt/ apt-get install -y tcpdump
#wifi startup
chroot mnt/ systemctl enable isc-dhcp-server
#ssh startup
chroot mnt/ systemctl enable ssh
#disable ntpd autostart
chroot mnt/ systemctl disable ntp
#root key
mkdir -p mnt/etc/ssh/authorized_keys
cp -f root mnt/etc/ssh/authorized_keys/root
chown root.root mnt/etc/ssh/authorized_keys/root
chmod 644 mnt/etc/ssh/authorized_keys/root
#motd
cp -f motd mnt/etc/motd
#dhcpd config
cp -f dhcpd.conf mnt/etc/dhcp/dhcpd.conf
#hostapd config
cp -f hostapd.conf mnt/etc/hostapd/hostapd.conf
cp -f hostapd-edimax.conf mnt/etc/hostapd/hostapd-edimax.conf
#hostapd manager script
cp -f hostapd_manager.sh mnt/usr/sbin/hostapd_manager.sh
chmod 755 mnt/usr/sbin/hostapd_manager.sh
#hostapd
cp -f hostapd-edimax mnt/usr/sbin/hostapd-edimax
chmod 755 mnt/usr/sbin/hostapd-edimax
#remove hostapd startup scripts
rm -f mnt/etc/rc*.d/*hostapd mnt/etc/network/if-pre-up.d/hostapd mnt/etc/network/if-post-down.d/hostapd mnt/etc/init.d/hostapd mnt/etc/default/hostapd
#interface config
cp -f interfaces mnt/etc/network/interfaces
#custom hostapd start script
cp stratux-wifi.sh mnt/usr/sbin/
chmod 755 mnt/usr/sbin/stratux-wifi.sh
#SDR Serial Script
cp -f sdr-tool.sh mnt/usr/sbin/sdr-tool.sh
chmod 755 mnt/usr/sbin/sdr-tool.sh
#ping udev
cp -f 99-uavionix.rules mnt/etc/udev/rules.d
#logrotate conf
cp -f logrotate.conf mnt/etc/logrotate.conf
#fan/temp control script
#remove old script
rm -rf mnt/usr/bin/fancontrol.py
#install new program
cp ../fancontrol mnt/usr/bin
chmod 755 mnt/usr/bin/fancontrol
chroot mnt/ /usr/bin/fancontrol remove
chroot mnt/ /usr/bin/fancontrol install
#isc-dhcp-server config
cp -f isc-dhcp-server mnt/etc/default/isc-dhcp-server
#sshd config
cp -f sshd_config mnt/etc/ssh/sshd_config
#udev config
cp -f 10-stratux.rules mnt/etc/udev/rules.d
#stratux files
cp -f ../libdump978.so mnt/usr/lib/libdump978.so
#go1.5.1 setup
cp -rf /root/go mnt/root/
cp -f bashrc.txt mnt/root/.bashrc
#debug aliases
cp -f stxAliases.txt mnt/root/.stxAliases
#rtl-sdr setup
cp -f rtl-sdr-blacklist.conf mnt/etc/modprobe.d/
chroot mnt/ apt-get install -y git cmake libusb-1.0-0.dev build-essential
rm -rf mnt/root/librtlsdr
git clone https://github.com/jpoirier/librtlsdr mnt/root/librtlsdr
mkdir -p mnt/root/librtlsdr/build
#FIXME
chroot mnt/ 'cd /root/librtlsdr/build && cmake ../ && make && make install && ldconfig'
#stratux setup
cd /root
apt-get install -y mercurial
apt-get install -y build-essential
rm -rf stratux
git clone https://github.com/cyoung/stratux --recursive
cd stratux
make
make install
#system tweaks
cp -f modules.txt mnt/etc/modules
#kalibrate-rtl
cd /root
rm -rf kalibrate-rtl
git clone https://github.com/steve-m/kalibrate-rtl
cd kalibrate-rtl
apt-get install -y autoconf fftw3 fftw3-dev libtool
./bootstrap
./configure
make
make install
#disable serial console
sed -i mnt/boot/cmdline.txt -e "s/console=ttyAMA0,[0-9]\+ //"
#Set the keyboard layout to US.
sed -i mnt/etc/default/keyboard -e "/^XKBLAYOUT/s/\".*\"/\"us\"/"
#boot settings
cp -f config.txt mnt/boot/
#external OLED screen
apt-get install -y libjpeg-dev i2c-tools python-smbus python-pip python-dev python-pil python-daemon screen
#for fancontrol.py:
pip install wiringpi
cd /root
git clone https://github.com/rm-hull/ssd1306
cd ssd1306
# Force an older version of ssd1306, since recent changes have caused a lot of compatibility issues.
git reset --hard 232fc801b0b8bd551290e26a13122c42d628fd39
python setup.py install
cp /root/stratux/test/screen/screen.py /usr/bin/stratux-screen.py
mkdir -p /etc/stratux-screen/
cp -f /root/stratux/test/screen/stratux-logo-64x64.bmp /etc/stratux-screen/stratux-logo-64x64.bmp
cp -f /root/stratux/test/screen/CnC_Red_Alert.ttf /etc/stratux-screen/CnC_Red_Alert.ttf
#startup scripts
cp -f ../__lib__systemd__system__stratux.service mnt/lib/systemd/system/stratux.service
cp -f ../__root__stratux-pre-start.sh mnt/root/stratux-pre-start.sh
cp -f rc.local mnt/etc/rc.local
#dhcpcd causes first boot hanging.
chroot mnt/ systemctl disable dhcpcd
#disable hciuart - interferes with ttyAMA0 as a serial port.
chroot mnt/ systemctl disable hciuart
#clean up for release images.
rm -rf mnt/root/stratux mnt/root/go

Wyświetl plik

@ -0,0 +1,7 @@
# /etc/modules: kernel modules to load at boot time.
#
# This file contains the names of kernel modules that should be loaded
# at boot time, one per line. Lines beginning with "#" are ignored.
i2c-bcm2708
i2c-dev

20
image/motd 100644
Wyświetl plik

@ -0,0 +1,20 @@
ad88888ba 888888888888 88888888ba db 888888888888 88 88 8b d8
d8" "8b 88 88 "8b d88b 88 88 88 Y8, ,8P
Y8, 88 88 ,8P d8'`8b 88 88 88 `8b d8'
`Y8aaaaa, 88 88aaaaaa8P' d8' `8b 88 88 88 Y88P
`"""""8b, 88 88""""88' d8YaaaaY8b 88 88 88 d88b
`8b 88 88 `8b d8""""""""8b 88 88 88 ,8P Y8,
Y8a a8P 88 88 `8b d8' `8b 88 Y8a. .a8P d8' `8b
"Y88888P" 88 88 `8b d8' `8b 88 `"Y8888Y"' 8P Y8
NOTE TO DEVELOPERS: Make sure that your system has an acceptable clock source, i.e., a GPS
with sufficient signal or enable ntpd (internet connection required).
Everything here comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Type 'stratux-help' (as root) for a few debugging commands.

9
image/rc.local 100644 → 100755
Wyświetl plik

@ -17,6 +17,13 @@ if [ "$_IP" ]; then
printf "My IP address is %s\n" "$_IP"
fi
nohup /usr/sbin/wifi_watch.sh 0<&- &> /var/log/stratux/wifi_watch.log &
#
# Rotate logs on boot.
#
/usr/sbin/logrotate /etc/logrotate.conf
/usr/bin/stratux-screen.py start
exit 0

Wyświetl plik

@ -0,0 +1,2 @@
# Ignore gen_gdl90. stratux.log is written directly from the process.
if $programname == 'gen_gdl90' then ~

Wyświetl plik

@ -0,0 +1,4 @@
blacklist dvb_usb_rtl28xxu
blacklist e4000
blacklist rtl2832
blacklist dvb_usb_rtl2832u

317
image/sdr-tool.sh 100644
Wyświetl plik

@ -0,0 +1,317 @@
#!/bin/bash
######################################################################
# STRATUX SDR MANAGER #
######################################################################
#Set Script Name variable
SCRIPT=`basename ${BASH_SOURCE[0]}`
# rtl_eeprom -d 0 -s <String>:<Freq>:<PPM>
#Initialize variables to default values.
SERVICE=stratux.service
WhichSDR=1090
FallBack=true
PPMValue=0
parm="*"
err="####"
att="+++"
#Set fonts for Help.
BOLD=$(tput bold)
STOT=$(tput smso)
DIM=$(tput dim)
UNDR=$(tput smul)
REV=$(tput rev)
RED=$(tput setaf 1)
GREEN=$(tput setaf 2)
YELLOW=$(tput setaf 3)
MAGENTA=$(tput setaf 5)
WHITE=$(tput setaf 7)
NORM=$(tput sgr0)
NORMAL=$(tput sgr0)
#This is the Title
function HEAD {
clear
echo "######################################################################"
echo "# STRATUX SDR SERIAL TOOL #"
echo "######################################################################"
echo " "
}
function STOPSTRATUX {
HEAD
echo "Give me a few seconds to check if STRATUX is running..."
# The service we want to check (according to systemctl)
if [ "`systemctl is-active $SERVICE`" = "active" ]
then
echo "$SERVICE is currently running"
echo "Stopping..."
SDRs=`systemctl stop stratux.service`
fi
sleep 3
}
function STARTSTRATUX {
HEAD
echo "Give me a few seconds to get STRATUX running again..."
SDRs=`systemctl start stratux.service`
sleep 3
if [ "`systemctl is-active $SERVICE`" = "active" ]
then
echo "$SERVICE is now running"
else
echo "$SERVICE did not restart. Try 'reboot' to restart your RaspberryPI"
fi
}
#Function to set the serial function
function SETSDRSERIAL {
HEAD
echo "# Setting ${WhichSDR}mhz SDR Serial Data #"
#Build this string
# rtl_eeprom -d 0 -s <String>:<Freq>:<PPM>
echo " SETTING SERIAL: "
echo " rtl_eeprom -d 0 -s stx:${WhichSDR}:${PPMValue} "
echo " "
echo "${REV}Answer 'y' to the qustion: 'Write new configuration to device [y/n]?'${NORM}"
echo " "
SDRs=`rtl_eeprom -d 0 -s stx:${WhichSDR}:${PPMValue}`
sleep 2
echo " "
echo "Do you have another SDR to program?"
echo " 'Yes' will shutdown your STRATUX and allow you to swap SDRs."
echo " 'No' will reboot your STRATUX and return your STRATUX to normal operation."
echo " 'exit' will exit the script and return you to your shell prompt"
choices=( 'Yes' 'No' 'exit' )
# Present the choices.
# The user chooses by entering the *number* before the desired choice.
select choice in "${choices[@]}"; do
# If an invalid number was chosen, $choice will be empty.
# Report an error and prompt again.
[[ -n $choice ]] || { echo "Invalid choice." >&2; continue; }
case $choice in
'Yes')
echo "Shutting down..."
SDRs=`shutdown -h now`
;;
'No')
echo "Rebooting..."
SDRs=`reboot`
;;
exit)
STARTSTRATUX
echo "Exiting. "
exit 0
esac
break
done
}
function SDRInfo {
HEAD
echo "# Building ${WhichSDR}mhz SDR Serial #"
echo " "
echo "Do you have a PPM value to enter?"
echo "If not, its ok... Just choose 'No'"
choices=( 'Yes' 'No' 'exit' )
# Present the choices.
# The user chooses by entering the *number* before the desired choice.
select choice in "${choices[@]}"; do
# If an invalid number was chosen, $choice will be empty.
# Report an error and prompt again.
[[ -n $choice ]] || { echo "Invalid choice." >&2; continue; }
case $choice in
'Yes')
echo "Please enter your PPM value for your 978mhz SDR:"
read PPMValue
;;
'No')
echo " "
;;
exit)
STARTSTRATUX
echo "Exiting. "
exit 0
esac
break
done
SETSDRSERIAL
}
function PICKFALLBACK {
HEAD
echo "# Gathering ${WhichSDR}mhz SDR Serial #"
echo " "
echo "${RED}${BOLD}IMPORTANT INFORMATION: READ CAREFULLY${NORM}"
echo "${BOLD}DO you want to set the 1090mhz SDR to Fall Back to 978mhz in the event of the 978mhx SDR failing inflight?${NORM}"
echo "If no serials are set on any of the attached SDRs then STRATUX will assign 978mhz to the first SDR found and 1090mhz to the remaining SDR. This is a safety featre of STRATUX to always allow users to always have access to WEATHER and METAR data in the event of one SDR failing in flight. "
echo " "
echo "When a user assigns a frequency to an SDR, via setting serials, STRATUX will always assign that frequency. NO MATTER WHAT."
echo "This could cause issues if an SDR fails in flight. If the 978mhz SDR fails in flight and the other SDR is assigned the 1090 serial this SDR will never be set to 978mhz and the user will not have access to WEATHER and METAR data"
echo " "
echo "Choosing the Fall Back mode will allow the remaining SDR to be assigned to 978mhz while keeping the PPM value, allowing the user to continue to receive WEATHER and METAR data."
echo "Fall Back mode is reccomended!"
choices=( 'FallBack' '1090mhz' 'exit' )
# Present the choices.
# The user chooses by entering the *number* before the desired choice.
select choice in "${choices[@]}"; do
# If an invalid number was chosen, $choice will be empty.
# Report an error and prompt again.
[[ -n $choice ]] || { echo "Invalid choice." >&2; continue; }
case $choice in
'FallBack')
WhichSDR=0
;;
'1090mhz')
echo " "
;;
exit)
STARTSTRATUX
echo "Exiting. "
exit 0
esac
break
done
}
function PICKFREQ {
HEAD
echo "# Selecting Radio to set Serial #"
echo " "
echo "${BOLD}Which SDR are you setting up?${NORM}"
echo "${DIM}If you have tuned antennas make sure you have the correct SDR and antenna combination hooked up at this time and remember which antenna connection is for which antenna.${NORM}"
choices=( '978mhz' '1090mhz' 'exit' )
# Present the choices.
# The user chooses by entering the *number* before the desired choice.
select choice in "${choices[@]}"; do
# If an invalid number was chosen, $choice will be empty.
# Report an error and prompt again.
[[ -n $choice ]] || { echo "Invalid choice." >&2; continue; }
case $choice in
'978mhz')
WhichSDR=978
SDRInfo
;;
'1090mhz')
PICKFALLBACK
SDRInfo
;;
exit)
STARTSTRATUX
echo "Exiting. "
exit 0
esac
break
done
}
function MAINMENU {
HEAD
echo "Loading SDR info..."
sleep 2
HEAD
echo "# CONFIRM ONLY ONE SDR INSTALLED #"
echo "----------------------------------------------------------------------"
SDRs=`rtl_eeprom`
echo "----------------------------------------------------------------------"
echo " "
echo "${BOLD}${RED}Read the lines above.${NORM}"
echo "${BOLD}How many SDRs were found?${NORM}"
# Define the choices to present to the user, which will be
# presented line by line, prefixed by a sequential number
# (E.g., '1) copy', ...)
choices=( 'Only 1' '2 or more' 'exit' )
# Present the choices.
# The user chooses by entering the *number* before the desired choice.
select choice in "${choices[@]}"; do
# If an invalid number was chosen, $choice will be empty.
# Report an error and prompt again.
[[ -n $choice ]] || { echo "Invalid choice." >&2; continue; }
case $choice in
'Only 1')
PICKFREQ
;;
'2 or more')
echo "#####################################################################################"
echo "# ${RED}Too Many SDRs Plugged in. Unplug all SDRs except one and try again!!${NORM} #"
echo "#####################################################################################"
STARTSTRATUX
echo "Exiting. "
exit 0
;;
exit)
STARTSTRATUX
echo "Exiting... "
exit 0
esac
# Getting here means that a valid choice was made,
# so break out of the select statement and continue below,
# if desired.
# Note that without an explicit break (or exit) statement,
# bash will continue to prompt.
break
done
}
function START {
echo "Help documentation for ${BOLD}${SCRIPT}.${NORM}"
echo " "
echo "This script will help you in setting your SDR serials. Please read carefully before continuing. There are many options in settings the SDR serials. Programming the SDR serials does 2 things. "
echo " "
echo "${BOLD}First:${NORM}"
echo "Setting the serials will tell your STRATUX which SDR is attached to which tuned antenna."
echo " "
echo "${BOLD}Second:${NORM}"
echo "Setting the PPM value will enhance the reception of your SDR by correcting the Frequency Error in each SDR. Each PPM value is unique to each SDR. For more info on this please refer to the Settings page in the WebUI and click on the Help in the top right."
echo " "
echo "Steps we will take:"
echo "1) Make sure you have ${BOLD}${REV}ONLY ONE${NORM} SDR plugged in at a time. Plugging in one SDR at a time will ensure they are not mixed up."
echo "2) Select which SDR we are setting the serial for."
echo "3) Add a PPM value. If you do not know or do not want to set this value this will be set to 0. "
echo "4) Write the serial to the SDR."
echo " "
echo "If you are ready to begin choose ${BOLD}Continue${NORM} to begin."
echo " Continuing will stop the STRATUX service to release the SDRs for setting the serials"
choices=( 'Continue' 'Exit' )
# Present the choices.
# The user chooses by entering the *number* before the desired choice.
select choice in "${choices[@]}"; do
# If an invalid number was chosen, $choice will be empty.
# Report an error and prompt again.
[[ -n $choice ]] || { echo "Invalid choice." >&2; continue; }
case $choice in
'Continue')
STOPSTRATUX
MAINMENU
;;
exit)
STARTSTRATUX
echo "Exiting. "
exit 0
esac
break
done
}
HEAD
START

Wyświetl plik

@ -59,8 +59,6 @@ scp_in_to_qemu /root/spindle/sshd_config /tmp/sshd_config.in
scp_in_to_qemu /root/spindle/libdump978.so /tmp/libdump978.so.in
scp_in_to_qemu /root/spindle/libimu.so /tmp/libimu.so.in
scp_in_to_qemu /root/spindle/go.tgz /mnt/root/go.tgz
scp_in_to_qemu /root/spindle/rc.local /tmp/rc.local.in
scp_in_to_qemu /root/spindle/wifi_watch.sh /tmp/wifi_watch.sh.in
ssh_in_to_qemu chroot /mnt sh -l -ex - <<\EOF
@ -80,9 +78,6 @@ mv -f /tmp/dhcpd.conf.in /etc/dhcp/dhcpd.conf
mv -f /tmp/hostapd.conf.in /etc/hostapd/hostapd.conf
mv -f /tmp/isc-dhcp-server.in /etc/default/isc-dhcp-server
mv -f /tmp/sshd_config.in /etc/ssh/sshd_config
mv -f /tmp/wifi_watch.sh.in /usr/sbin/wifi_watch.sh
chmod +x /usr/sbin/wifi_watch.sh
mv -f /tmp/rc.local.in /etc/rc.local
rm -f /usr/share/dbus-1/system-services/fi.epitest.hostap.WPASupplicant.service
echo "DAEMON_CONF=\"/etc/hostapd/hostapd.conf\"" >/etc/default/hostapd

Wyświetl plik

@ -0,0 +1,106 @@
#!/bin/bash
#####
##### Wifi/AP control file
#####
##### Description: All the scripting related to the AP and wireless functions for Stratux should be placed in this file
##### This file is called when wlan0 is started i.e. "ifup wlan0"
##### This script is called from /etc/network/interfaces by the line "post-up /usr/sbin/stratux-wifi.sh" under the wlan0 configuration
#####
# common variables
DAEMON_USER_PREF=/etc/hostapd/hostapd.user
#Logging Function
SCRIPT=`basename ${BASH_SOURCE[0]}`
STX_LOG="/var/log/stratux.log"
function wLog () {
echo "$(date +"%Y/%m/%d %H:%m:%S") - $SCRIPT - $1" >> ${STX_LOG}
}
wLog "Running Stratux WiFI Script."
##### Function for setting up new file structure for hostapd settings
##### Look for hostapd.user and if found do nothing.
##### If not assume because of previous version and convert to new file structure
function hostapd-upgrade {
DAEMON_CONF=/etc/hostapd/hostapd.conf
DAEMON_CONF_EDIMAX=/etc/hostapd/hostapd-edimax.conf
HOSTAPD_VALUES=('ssid=' 'channel=' 'auth_algs=' 'wpa=' 'wpa_passphrase=' 'wpa_key_mgmt=' 'wpa_pairwise=' 'rsn_pairwise=')
wLog "Moving existing values from $DAEMON_CONF to $DAEMON_USER_PREF if found"
for i in "${HOSTAPD_VALUES[@]}"
do
if grep -q "^$i" $DAEMON_CONF
then
grep "^$i" $DAEMON_CONF >> $DAEMON_USER_PREF
sed -i '/^'"$i"'/d' $DAEMON_CONF
sed -i '/^'"$i"'/d' $DAEMON_CONF_EDIMAX
fi
done
sleep 1 #make sure there is time to get the file written before checking for it again
# If once the code above runs and there is still no hostapd.user file then something is wrong and we will just create the file with basic settings.
# Any more then this they somebody was messing with things and its not our fault things are this bad
wLog "Rechecking if $DAEMON_USER_PREF exists after moving files."
if [ ! -f $DAEMON_USER_PREF ]; then
wLog "File not found. Creating default file. "
echo "ssid=stratux" > $DAEMON_USER_PREF
echo "channel=1" >> $DAEMON_USER_PREF
fi
}
##### End hostapd settings structure function
##### Hostapd Driver check function #####
function ap-start {
# Preliminaries. Kill off old services.
wLog "Killing Hostapd services "
/usr/bin/killall -9 hostapd hostapd-edimax
wLog "Stopping DHCP services "
/usr/sbin/service isc-dhcp-server stop
#EDIMAX Mac Addresses from http://www.adminsub.net/mac-address-finder/edimax
#for logic check all addresses must be lowercase
# 74:da:38 is my MAC on my NANO
edimaxMac=(80:1f:02 74:da:38 00:50:fc 00:1f:1f 00:0e:2e 00:00:b4)
#Assume PI3 settings
DAEMON_CONF=/etc/hostapd/hostapd.conf
DAEMON_SBIN=/usr/sbin/hostapd
# Location of temporary hostapd.conf built by combining
# non-editable /etc/hostapd/hostapd.conf or hostapd-edimax.conf
# and the user configurable /etc/hostapd/hostapd.conf
DAEMON_TMP=/tmp/hostapd.conf
#get the first 3 octets of the MAC(XX:XX:XX) at wlan0
wlan0mac=$(head -c 8 /sys/class/net/wlan0/address)
# Is there an Edimax Mac Address at wlan0
if [[ ${edimaxMac[*]} =~ "$wlan0mac" ]]; then
DAEMON_CONF=/etc/hostapd/hostapd-edimax.conf
DAEMON_SBIN=/usr/sbin/hostapd-edimax
wLog "Edimax Dongle found at WLAN0. Using Edimad conf files $DAEMON_SBIN : $DAEMON_CONF"
fi
#Make a new hostapd or hostapd-edimax conf file based on logic above
cat ${DAEMON_USER_PREF} <(echo) ${DAEMON_CONF} > ${DAEMON_TMP}
${DAEMON_SBIN} -B ${DAEMON_TMP}
sleep 2
wLog "Restarting DHCP services"
/usr/sbin/service isc-dhcp-server start
}
##### End Hostapd driver check function #####
#Do we need to upgrade the hostapd configuration files
wLog "Checking if $DAEMON_USER_PREF file exists"
if [ ! -f $DAEMON_USER_PREF ]; then
wLog "File not found. Upgrading to new file structure."
hostapd-upgrade
fi
# function to build /tmp/hostapd.conf and start AP
ap-start

Wyświetl plik

@ -0,0 +1,71 @@
alias stratux-off='shutdown -P now'
alias eeprom='rtl_eeprom'
alias sa='service --status-all'
alias stxrestart='service stratux restart'
alias stxstop='service stratux stop'
alias stxstart='service stratux start'
alias sdr0='rtl_eeprom -d 0'
alias sdr1='rtl_eeprom -d 1'
alias sdrs='sdr0 || sdr1'
alias d90='dump1090'
alias d900='dump1090 --device-index 0 --interactive'
alias d901='dump1090 --device-index 1 --interactive'
alias kal0='kal -d 0 -s GSM850 -g 47'
alias kal1='kal -d 1 -s GSM850 -g 47'
alias kalChan0='function _kalChan0 () { kal -d 0 -g 47 -c $1; unset -f _kalChan0; }; _kalChan0'
alias kalChan1='function _kalChan1 () { kal -d 1 -g 47 -c $1; unset -f _kalChan1; }; _kalChan1'
alias setSerial0='function _setSerial0 () { rtl_eeprom -d 0 -s stx:0:$1; unset -f _setSerial0; }; _setSerial0'
alias setSerial1='function _setSerial1 () { rtl_eeprom -d 1 -s stx:0:$1; unset -f _setSerial1; }; _setSerial1'
alias secure='hostapd_manager.sh -e'
alias open='hostapd_manager.sh -o'
alias stratux-help='_stxhelp'
function _stxhelp() {
clear
echo ""
echo "########################################################"
echo ""
echo "These are commands avalible to you. Use at your own Risk"
echo ""
echo "########################################################"
echo ""
echo " Common tools "
echo "########################################################"
echo ""
echo "secure Turns on WiFi Security"
echo "open Turns off WiFi Security"
echo "stratux-off Shutdown Stratux"
echo "hostapd_manager.sh Sets the Change SSID, Channel, or Encryption for your Stratux"
echo "sdr-tool.sh Tool to walk you though setting your SDRs Serials"
echo ""
echo " Developer Tools "
echo "########################################################"
echo ""
echo "sa List all services running"
echo "stxrestart Restart Startux service only"
echo "stxstop Stop Stratux Service."
echo "stxstart Start Stratux Service."
echo "sdr0 Test to see if sdr0 is in use by Stratux."
echo "sdr1 Test to see if sdr1 is in use by Startux."
echo "sdrs Test to see if both SDRs are in use by Stratux."
echo "d90 Run dump1090 on SDR0"
echo "d900 Run dump1090 on SDR0 in interactive mode."
echo "d901 Run dump1090 on SDR1 in interactive mode."
echo "kal0 Find Channels for calibrating PPM of SDR0."
echo "kal1 Find Channels for calibrating PPM of SDR1."
echo "kalChan0 Use the Chan from above to get ppm pf SDR0. Example: kalChan0 151"
echo "kalChan1 Use the Chan from above to get ppm pf SDR1. Example: kalChan1 151"
echo "setSerial0 Set the PPM error to SDR0. Value from kalChan0. Example: setSerial0 -45"
echo "setSerial1 Set the PPM error to SDR1. Value from kalChan1. Example: setSerial1 23"
echo "raspi-config Open Raspberry Pi settings to expand filesystem"
}

Wyświetl plik

@ -1,12 +0,0 @@
#!/bin/bash
while true ; do
if ifconfig wlan0 | grep -q "UP BROADCAST RUNNING MULTICAST" ; then
sleep 30
else
echo "Wi-Fi connection down! Attempting reconnection."
service hostapd restart
service isc-dhcp-server restart
sleep 10
fi
done

Wyświetl plik

@ -1,78 +0,0 @@
#!/bin/sh
### BEGIN INIT INFO
# Provides: stratux
# Required-Start: $network
# Required-Stop:
# Should-Start:
# Should-Stop:
# Default-Start: 2
# Default-Stop: 6
# Short-Description: Stratux ADS-B Receiver
# Description: RTL-SDR ADS-B receiver
### END INIT INFO
PATH=/sbin:/bin:/usr/sbin:/usr/bin
DAEMON_SBIN=/usr/bin/gen_gdl90
DAEMON_DEFS=
DAEMON_CONF=
NAME=stratux
DESC="Stratux ADS-B Receiver"
PIDFILE=/var/run/stratux.pid
[ -x "$DAEMON_SBIN" ] || exit 0
DAEMON_OPTS=""
. /lib/lsb/init-functions
case "$1" in
start)
log_daemon_msg "Starting $DESC" "$NAME"
echo powersave >/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
# Check if we need to run an update.
if [ -e /root/update*stratux*v*.sh ] ; then
UPDATE_SCRIPT=`ls -1t /root/update*stratux*v*.sh | head -1`
if [ -n "$UPDATE_SCRIPT" ] ; then
# Execute the script, remove it, then reboot.
echo
echo "Running update script ${UPDATE_SCRIPT}..."
sh ${UPDATE_SCRIPT}
rm -f $UPDATE_SCRIPT
reboot
fi
fi
start-stop-daemon --start --background --oknodo --quiet --exec "$DAEMON_SBIN" \
--pidfile "$PIDFILE" --make-pidfile -- $DAEMON_OPTS >/dev/null
log_end_msg "$?"
;;
stop)
log_daemon_msg "Stopping $DESC" "$NAME"
start-stop-daemon --stop --oknodo --quiet --exec "$DAEMON_SBIN" \
--pidfile "$PIDFILE"
pkill dump1090 || true
log_end_msg "$?"
;;
reload)
log_daemon_msg "Reloading $DESC" "$NAME"
start-stop-daemon --stop --signal HUP --exec "$DAEMON_SBIN" \
--pidfile "$PIDFILE"
log_end_msg "$?"
;;
restart|force-reload)
$0 stop
sleep 8
$0 start
;;
status)
status_of_proc "$DAEMON_SBIN" "$NAME"
exit $?
;;
*)
N=/etc/init.d/$NAME
echo "Usage: $N {start|stop|restart|force-reload|reload|status}" >&2
exit 1
;;
esac
exit 0

@ -1 +0,0 @@
Subproject commit 56658ffe83c23fde04fccc8e747bf9b7c1e184ea

46
main/cputemp.go 100644
Wyświetl plik

@ -0,0 +1,46 @@
package main
import (
"io/ioutil"
"strconv"
"strings"
"time"
)
const invalidCpuTemp = float32(-99.0)
type CpuTempUpdateFunc func(cpuTemp float32)
/* cpuTempMonitor() reads the RPi board temperature every second and
calls a callback. This is broken out into its own function (run as
its own goroutine) because the RPi temperature monitor code is buggy,
and often times reading this file hangs quite some time. */
func cpuTempMonitor(updater CpuTempUpdateFunc) {
timer := time.NewTicker(1 * time.Second)
for {
// Update CPUTemp.
temp, err := ioutil.ReadFile("/sys/class/thermal/thermal_zone0/temp")
tempStr := strings.Trim(string(temp), "\n")
t := invalidCpuTemp
if err == nil {
tInt, err := strconv.Atoi(tempStr)
if err == nil {
if tInt > 1000 {
t = float32(tInt) / float32(1000.0)
} else {
t = float32(tInt) // case where Temp is returned as simple integer
}
}
}
if t >= invalidCpuTemp { // Only update if valid value was obtained.
updater(t)
}
<-timer.C
}
}
// Check if CPU temperature is valid. Assume <= 0 is invalid.
func isCPUTempValid(cpuTemp float32) bool {
return cpuTemp > 0
}

642
main/datalog.go 100644
Wyświetl plik

@ -0,0 +1,642 @@
/*
Copyright (c) 2015-2016 Christopher Young
Distributable under the terms of The "BSD New" License
that can be found in the LICENSE file, herein included
as part of this header.
datalog.go: Log stratux data as it is received. Bucket data into timestamp time slots.
*/
package main
import (
"database/sql"
"errors"
"fmt"
_ "github.com/mattn/go-sqlite3"
"log"
"os"
"reflect"
"strconv"
"strings"
"time"
)
const (
LOG_TIMESTAMP_RESOLUTION = 250 * time.Millisecond
)
type StratuxTimestamp struct {
id int64
Time_type_preference int // 0 = stratuxClock, 1 = gpsClock, 2 = gpsClock extrapolated via stratuxClock.
StratuxClock_value time.Time
GPSClock_value time.Time // The value of this is either from the GPS or extrapolated from the GPS via stratuxClock if pref is 1 or 2. It is time.Time{} if 0.
PreferredTime_value time.Time
StartupID int64
}
// 'startup' table creates a new entry each time the daemon is started. This keeps track of sequential starts, even if the
// timestamp is ambiguous (units with no GPS). This struct is just a placeholder for an empty table (other than primary key).
type StratuxStartup struct {
id int64
Fill string
}
var dataLogStarted bool
var dataLogReadyToWrite bool
var stratuxStartupID int64
var dataLogTimestamps []StratuxTimestamp
var dataLogCurTimestamp int64 // Current timestamp bucket. This is an index on dataLogTimestamps which is not necessarily the db id.
/*
checkTimestamp().
Verify that our current timestamp is within the LOG_TIMESTAMP_RESOLUTION bucket.
Returns false if the timestamp was changed, true if it is still valid.
This is where GPS timestamps are extrapolated, if the GPS data is currently valid.
*/
func checkTimestamp() bool {
thisCurTimestamp := dataLogCurTimestamp
if stratuxClock.Since(dataLogTimestamps[thisCurTimestamp].StratuxClock_value) >= LOG_TIMESTAMP_RESOLUTION {
var ts StratuxTimestamp
ts.id = 0
ts.Time_type_preference = 0 // stratuxClock.
ts.StratuxClock_value = stratuxClock.Time
ts.GPSClock_value = time.Time{}
ts.PreferredTime_value = stratuxClock.Time
// Extrapolate from GPS timestamp, if possible.
if isGPSClockValid() && thisCurTimestamp > 0 {
// Was the last timestamp either extrapolated or GPS time?
last_ts := dataLogTimestamps[thisCurTimestamp]
if last_ts.Time_type_preference == 1 || last_ts.Time_type_preference == 2 {
// Extrapolate via stratuxClock.
timeSinceLastTS := ts.StratuxClock_value.Sub(last_ts.StratuxClock_value) // stratuxClock ticks since last timestamp.
extrapolatedGPSTimestamp := last_ts.PreferredTime_value.Add(timeSinceLastTS)
// Re-set the preferred timestamp type to '2' (extrapolated time).
ts.Time_type_preference = 2
ts.PreferredTime_value = extrapolatedGPSTimestamp
ts.GPSClock_value = extrapolatedGPSTimestamp
}
}
dataLogTimestamps = append(dataLogTimestamps, ts)
dataLogCurTimestamp = int64(len(dataLogTimestamps) - 1)
return false
}
return true
}
type SQLiteMarshal struct {
FieldType string
Marshal func(v reflect.Value) string
}
func boolMarshal(v reflect.Value) string {
b := v.Bool()
if b {
return "1"
}
return "0"
}
func intMarshal(v reflect.Value) string {
return strconv.FormatInt(v.Int(), 10)
}
func uintMarshal(v reflect.Value) string {
return strconv.FormatUint(v.Uint(), 10)
}
func floatMarshal(v reflect.Value) string {
return strconv.FormatFloat(v.Float(), 'f', 10, 64)
}
func stringMarshal(v reflect.Value) string {
return v.String()
}
func notsupportedMarshal(v reflect.Value) string {
return ""
}
func structCanBeMarshalled(v reflect.Value) bool {
m := v.MethodByName("String")
if m.IsValid() && !m.IsNil() {
return true
}
return false
}
func structMarshal(v reflect.Value) string {
if structCanBeMarshalled(v) {
m := v.MethodByName("String")
in := make([]reflect.Value, 0)
ret := m.Call(in)
if len(ret) > 0 {
return ret[0].String()
}
}
return ""
}
var sqliteMarshalFunctions = map[string]SQLiteMarshal{
"bool": {FieldType: "INTEGER", Marshal: boolMarshal},
"int": {FieldType: "INTEGER", Marshal: intMarshal},
"uint": {FieldType: "INTEGER", Marshal: uintMarshal},
"float": {FieldType: "REAL", Marshal: floatMarshal},
"string": {FieldType: "TEXT", Marshal: stringMarshal},
"struct": {FieldType: "STRING", Marshal: structMarshal},
"notsupported": {FieldType: "notsupported", Marshal: notsupportedMarshal},
}
var sqlTypeMap = map[reflect.Kind]string{
reflect.Bool: "bool",
reflect.Int: "int",
reflect.Int8: "int",
reflect.Int16: "int",
reflect.Int32: "int",
reflect.Int64: "int",
reflect.Uint: "uint",
reflect.Uint8: "uint",
reflect.Uint16: "uint",
reflect.Uint32: "uint",
reflect.Uint64: "uint",
reflect.Uintptr: "notsupported",
reflect.Float32: "float",
reflect.Float64: "float",
reflect.Complex64: "notsupported",
reflect.Complex128: "notsupported",
reflect.Array: "notsupported",
reflect.Chan: "notsupported",
reflect.Func: "notsupported",
reflect.Interface: "notsupported",
reflect.Map: "notsupported",
reflect.Ptr: "notsupported",
reflect.Slice: "notsupported",
reflect.String: "string",
reflect.Struct: "struct",
reflect.UnsafePointer: "notsupported",
}
func makeTable(i interface{}, tbl string, db *sql.DB) {
val := reflect.ValueOf(i)
fields := make([]string, 0)
for i := 0; i < val.NumField(); i++ {
kind := val.Field(i).Kind()
fieldName := val.Type().Field(i).Name
sqlTypeAlias := sqlTypeMap[kind]
// Check that if the field is a struct that it can be marshalled.
if sqlTypeAlias == "struct" && !structCanBeMarshalled(val.Field(i)) {
continue
}
if sqlTypeAlias == "notsupported" || fieldName == "id" {
continue
}
sqlType := sqliteMarshalFunctions[sqlTypeAlias].FieldType
s := fieldName + " " + sqlType
fields = append(fields, s)
}
// Add the timestamp_id field to link up with the timestamp table.
if tbl != "timestamp" && tbl != "startup" {
fields = append(fields, "timestamp_id INTEGER")
}
tblCreate := fmt.Sprintf("CREATE TABLE %s (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, %s)", tbl, strings.Join(fields, ", "))
_, err := db.Exec(tblCreate)
if err != nil {
fmt.Printf("ERROR: %s\n", err.Error())
}
}
/*
bulkInsert().
Reads insertBatch and insertBatchIfs. This is called after a group of insertData() calls.
*/
func bulkInsert(tbl string, db *sql.DB) (res sql.Result, err error) {
if _, ok := insertString[tbl]; !ok {
return nil, errors.New("no insert statement")
}
batchVals := insertBatchIfs[tbl]
numColsPerRow := len(batchVals[0])
maxRowBatch := int(999 / numColsPerRow) // SQLITE_MAX_VARIABLE_NUMBER = 999.
// log.Printf("table %s. %d cols per row. max batch %d\n", tbl, numColsPerRow, maxRowBatch)
for len(batchVals) > 0 {
// timeInit := time.Now()
i := int(0) // Variable number of rows per INSERT statement.
stmt := ""
vals := make([]interface{}, 0)
querySize := uint64(0) // Size of the query in bytes.
for len(batchVals) > 0 && i < maxRowBatch && querySize < 750000 { // Maximum of 1,000,000 bytes per query.
if len(stmt) == 0 { // The first set will be covered by insertString.
stmt = insertString[tbl]
querySize += uint64(len(insertString[tbl]))
} else {
addStr := ", (" + strings.Join(strings.Split(strings.Repeat("?", len(batchVals[0])), ""), ",") + ")"
stmt += addStr
querySize += uint64(len(addStr))
}
for _, val := range batchVals[0] {
querySize += uint64(len(val.(string)))
}
vals = append(vals, batchVals[0]...)
batchVals = batchVals[1:]
i++
}
// log.Printf("inserting %d rows to %s. querySize=%d\n", i, tbl, querySize)
res, err = db.Exec(stmt, vals...)
// timeBatch := time.Since(timeInit) // debug
// log.Printf("SQLite: bulkInserted %d rows to %s. Took %f msec to build and insert query. querySize=%d\n", i, tbl, 1000*timeBatch.Seconds(), querySize) // debug
if err != nil {
log.Printf("sqlite INSERT error: '%s'\n", err.Error())
return
}
}
// Clear the buffers.
delete(insertString, tbl)
delete(insertBatchIfs, tbl)
return
}
/*
insertData().
Inserts an arbitrary struct into an SQLite table.
Inserts the timestamp first, if its 'id' is 0.
*/
// Cached 'VALUES' statements. Indexed by table name.
var insertString map[string]string // INSERT INTO tbl (col1, col2, ...) VALUES(?, ?, ...). Only for one value.
var insertBatchIfs map[string][][]interface{}
func insertData(i interface{}, tbl string, db *sql.DB, ts_num int64) int64 {
val := reflect.ValueOf(i)
keys := make([]string, 0)
values := make([]string, 0)
for i := 0; i < val.NumField(); i++ {
kind := val.Field(i).Kind()
fieldName := val.Type().Field(i).Name
sqlTypeAlias := sqlTypeMap[kind]
if sqlTypeAlias == "notsupported" || fieldName == "id" {
continue
}
v := sqliteMarshalFunctions[sqlTypeAlias].Marshal(val.Field(i))
keys = append(keys, fieldName)
values = append(values, v)
}
// Add the timestamp_id field to link up with the timestamp table.
if tbl != "timestamp" && tbl != "startup" {
keys = append(keys, "timestamp_id")
if dataLogTimestamps[ts_num].id == 0 {
//FIXME: This is somewhat convoluted. When insertData() is called for a ts_num that corresponds to a timestamp with no database id,
// then it inserts that timestamp via the same interface and the id is updated in the structure via the below lines
// (dataLogTimestamps[ts_num].id = id).
dataLogTimestamps[ts_num].StartupID = stratuxStartupID
insertData(dataLogTimestamps[ts_num], "timestamp", db, ts_num) // Updates dataLogTimestamps[ts_num].id.
}
values = append(values, strconv.FormatInt(dataLogTimestamps[ts_num].id, 10))
}
if _, ok := insertString[tbl]; !ok {
// Prepare the statement.
tblInsert := fmt.Sprintf("INSERT INTO %s (%s) VALUES(%s)", tbl, strings.Join(keys, ","),
strings.Join(strings.Split(strings.Repeat("?", len(keys)), ""), ","))
insertString[tbl] = tblInsert
}
// Make the values slice into a slice of interface{}.
ifs := make([]interface{}, len(values))
for i := 0; i < len(values); i++ {
ifs[i] = values[i]
}
insertBatchIfs[tbl] = append(insertBatchIfs[tbl], ifs)
if tbl == "timestamp" || tbl == "startup" { // Immediate insert always for "timestamp" and "startup" table.
res, err := bulkInsert(tbl, db) // Bulk insert of 1, always.
if err == nil {
id, err := res.LastInsertId()
if err == nil && tbl == "timestamp" { // Special handling for timestamps. Update the timestamp ID.
ts := dataLogTimestamps[ts_num]
ts.id = id
dataLogTimestamps[ts_num] = ts
}
return id
}
}
return 0
}
type DataLogRow struct {
tbl string
data interface{}
ts_num int64
}
var dataLogChan chan DataLogRow
var shutdownDataLog chan bool
var shutdownDataLogWriter chan bool
var dataLogWriteChan chan DataLogRow
func dataLogWriter(db *sql.DB) {
dataLogWriteChan = make(chan DataLogRow, 10240)
shutdownDataLogWriter = make(chan bool)
// The write queue. As data comes in via dataLogChan, it is timestamped and stored.
// When writeTicker comes up, the queue is emptied.
writeTicker := time.NewTicker(10 * time.Second)
rowsQueuedForWrite := make([]DataLogRow, 0)
for {
select {
case r := <-dataLogWriteChan:
// Accept timestamped row.
rowsQueuedForWrite = append(rowsQueuedForWrite, r)
case <-writeTicker.C:
// for i := 0; i < 1000; i++ {
// logSituation()
// }
timeStart := stratuxClock.Time
nRows := len(rowsQueuedForWrite)
if globalSettings.DEBUG {
log.Printf("Writing %d rows\n", nRows)
}
// Write the buffered rows. This will block while it is writing.
// Save the names of the tables affected so that we can run bulkInsert() on after the insertData() calls.
tblsAffected := make(map[string]bool)
// Start transaction.
tx, err := db.Begin()
if err != nil {
log.Printf("db.Begin() error: %s\n", err.Error())
break // from select {}
}
for _, r := range rowsQueuedForWrite {
tblsAffected[r.tbl] = true
insertData(r.data, r.tbl, db, r.ts_num)
}
// Do the bulk inserts.
for tbl, _ := range tblsAffected {
bulkInsert(tbl, db)
}
// Close the transaction.
tx.Commit()
rowsQueuedForWrite = make([]DataLogRow, 0) // Zero the queue.
timeElapsed := stratuxClock.Since(timeStart)
if globalSettings.DEBUG {
rowsPerSecond := float64(nRows) / float64(timeElapsed.Seconds())
log.Printf("Writing finished. %d rows in %.2f seconds (%.1f rows per second).\n", nRows, float64(timeElapsed.Seconds()), rowsPerSecond)
}
if timeElapsed.Seconds() > 10.0 {
log.Printf("WARNING! SQLite logging is behind. Last write took %.1f seconds.\n", float64(timeElapsed.Seconds()))
dataLogCriticalErr := fmt.Errorf("WARNING! SQLite logging is behind. Last write took %.1f seconds.\n", float64(timeElapsed.Seconds()))
addSystemError(dataLogCriticalErr)
}
case <-shutdownDataLogWriter: // Received a message on the channel to initiate a graceful shutdown, and to command dataLog() to shut down
log.Printf("datalog.go: dataLogWriter() received shutdown message with rowsQueuedForWrite = %d\n", len(rowsQueuedForWrite))
shutdownDataLog <- true
return
}
}
log.Printf("datalog.go: dataLogWriter() shutting down\n")
}
func dataLog() {
dataLogStarted = true
log.Printf("datalog.go: dataLog() started\n")
dataLogChan = make(chan DataLogRow, 10240)
shutdownDataLog = make(chan bool)
dataLogTimestamps = make([]StratuxTimestamp, 0)
var ts StratuxTimestamp
ts.id = 0
ts.Time_type_preference = 0 // stratuxClock.
ts.StratuxClock_value = stratuxClock.Time
ts.GPSClock_value = time.Time{}
ts.PreferredTime_value = stratuxClock.Time
dataLogTimestamps = append(dataLogTimestamps, ts)
dataLogCurTimestamp = 0
// Check if we need to create a new database.
createDatabase := false
if _, err := os.Stat(dataLogFilef); os.IsNotExist(err) {
createDatabase = true
log.Printf("creating new database '%s'.\n", dataLogFilef)
}
db, err := sql.Open("sqlite3", dataLogFilef)
if err != nil {
log.Printf("sql.Open(): %s\n", err.Error())
}
defer func() {
db.Close()
dataLogStarted = false
//close(dataLogChan)
log.Printf("datalog.go: dataLog() has closed DB in %s\n", dataLogFilef)
}()
_, err = db.Exec("PRAGMA journal_mode=WAL")
if err != nil {
log.Printf("db.Exec('PRAGMA journal_mode=WAL') err: %s\n", err.Error())
}
_, err = db.Exec("PRAGMA synchronous=OFF")
if err != nil {
log.Printf("db.Exec('PRAGMA journal_mode=WAL') err: %s\n", err.Error())
}
//log.Printf("Starting dataLogWriter\n") // REMOVE -- DEBUG
go dataLogWriter(db)
// Do we need to create the database?
if createDatabase {
makeTable(StratuxTimestamp{}, "timestamp", db)
makeTable(mySituation, "mySituation", db)
makeTable(globalStatus, "status", db)
makeTable(globalSettings, "settings", db)
makeTable(TrafficInfo{}, "traffic", db)
makeTable(msg{}, "messages", db)
makeTable(esmsg{}, "es_messages", db)
makeTable(Dump1090TermMessage{}, "dump1090_terminal", db)
makeTable(gpsPerfStats{}, "gps_attitude", db)
makeTable(StratuxStartup{}, "startup", db)
}
// The first entry to be created is the "startup" entry.
stratuxStartupID = insertData(StratuxStartup{}, "startup", db, 0)
dataLogReadyToWrite = true
//log.Printf("Entering dataLog read loop\n") //REMOVE -- DEBUG
for {
select {
case r := <-dataLogChan:
// When data is input, the first step is to timestamp it.
// Check if our time bucket has expired or has never been entered.
checkTimestamp()
// Mark the row with the current timestamp ID, in case it gets entered later.
r.ts_num = dataLogCurTimestamp
// Queue it for the scheduled write.
dataLogWriteChan <- r
case <-shutdownDataLog: // Received a message on the channel to complete a graceful shutdown (see the 'defer func()...' statement above).
log.Printf("datalog.go: dataLog() received shutdown message\n")
return
}
}
log.Printf("datalog.go: dataLog() shutting down\n")
close(shutdownDataLog)
}
/*
setDataLogTimeWithGPS().
Create a timestamp entry using GPS time.
*/
func setDataLogTimeWithGPS(sit SituationData) {
if isGPSClockValid() {
var ts StratuxTimestamp
// Piggyback a GPS time update from this update.
ts.id = 0
ts.Time_type_preference = 1 // gpsClock.
ts.StratuxClock_value = stratuxClock.Time
ts.GPSClock_value = sit.GPSTime
ts.PreferredTime_value = sit.GPSTime
dataLogTimestamps = append(dataLogTimestamps, ts)
dataLogCurTimestamp = int64(len(dataLogTimestamps) - 1)
}
}
/*
logSituation(), logStatus(), ... pass messages from other functions to the logging
engine. These are only read into `dataLogChan` if the Replay Log is toggled on,
and if the log system is ready to accept writes.
*/
func isDataLogReady() bool {
return dataLogReadyToWrite
}
func logSituation() {
if globalSettings.ReplayLog && isDataLogReady() {
dataLogChan <- DataLogRow{tbl: "mySituation", data: mySituation}
}
}
func logStatus() {
if globalSettings.ReplayLog && isDataLogReady() {
dataLogChan <- DataLogRow{tbl: "status", data: globalStatus}
}
}
func logSettings() {
if globalSettings.ReplayLog && isDataLogReady() {
dataLogChan <- DataLogRow{tbl: "settings", data: globalSettings}
}
}
func logTraffic(ti TrafficInfo) {
if globalSettings.ReplayLog && isDataLogReady() {
dataLogChan <- DataLogRow{tbl: "traffic", data: ti}
}
}
func logMsg(m msg) {
if globalSettings.ReplayLog && isDataLogReady() {
dataLogChan <- DataLogRow{tbl: "messages", data: m}
}
}
func logESMsg(m esmsg) {
if globalSettings.ReplayLog && isDataLogReady() {
dataLogChan <- DataLogRow{tbl: "es_messages", data: m}
}
}
func logGPSAttitude(gpsPerf gpsPerfStats) {
if globalSettings.ReplayLog && isDataLogReady() {
dataLogChan <- DataLogRow{tbl: "gps_attitude", data: gpsPerf}
}
}
func logDump1090TermMessage(m Dump1090TermMessage) {
if globalSettings.DEBUG && globalSettings.ReplayLog && isDataLogReady() {
dataLogChan <- DataLogRow{tbl: "dump1090_terminal", data: m}
}
}
func initDataLog() {
//log.Printf("dataLogStarted = %t. dataLogReadyToWrite = %t\n", dataLogStarted, dataLogReadyToWrite) //REMOVE -- DEBUG
insertString = make(map[string]string)
insertBatchIfs = make(map[string][][]interface{})
go dataLogWatchdog()
//log.Printf("datalog.go: initDataLog() complete.\n") //REMOVE -- DEBUG
}
/*
dataLogWatchdog(): Watchdog function to control startup / shutdown of data logging subsystem.
Called by initDataLog as a goroutine. It iterates once per second to determine if
globalSettings.ReplayLog has toggled. If logging was switched from off to on, it starts
datalog() as a goroutine. If the log is running and we want it to stop, it calls
closeDataLog() to turn off the input channels, close the log, and tear down the dataLog
and dataLogWriter goroutines.
*/
func dataLogWatchdog() {
for {
if !dataLogStarted && globalSettings.ReplayLog { // case 1: sqlite logging isn't running, and we want to start it
log.Printf("datalog.go: Watchdog wants to START logging.\n")
go dataLog()
} else if dataLogStarted && !globalSettings.ReplayLog { // case 2: sqlite logging is running, and we want to shut it down
log.Printf("datalog.go: Watchdog wants to STOP logging.\n")
closeDataLog()
}
//log.Printf("Watchdog iterated.\n") //REMOVE -- DEBUG
time.Sleep(1 * time.Second)
//log.Printf("Watchdog sleep over.\n") //REMOVE -- DEBUG
}
}
/*
closeDataLog(): Handler for graceful shutdown of data logging goroutines. It is called by
by dataLogWatchdog(), gracefulShutdown(), and by any other function (disk space monitor?)
that needs to be able to shut down sqlite logging without corrupting data or blocking
execution.
This function turns off log message reads into the dataLogChan receiver, and sends a
message to a quit channel ('shutdownDataLogWriter`) in dataLogWriter(). dataLogWriter()
then sends a message to a quit channel to 'shutdownDataLog` in dataLog() to close *that*
goroutine. That function sets dataLogStarted=false once the logfile is closed. By waiting
for that signal, closeDataLog() won't exit until the log is safely written. This prevents
data loss on shutdown.
*/
func closeDataLog() {
//log.Printf("closeDataLog(): dataLogStarted = %t\n", dataLogStarted) //REMOVE -- DEBUG
dataLogReadyToWrite = false // prevent any new messages from being sent down the channels
log.Printf("datalog.go: Starting data log shutdown\n")
shutdownDataLogWriter <- true //
defer close(shutdownDataLogWriter) // ... and close the channel so subsequent accidental writes don't stall execution
log.Printf("datalog.go: Waiting for shutdown signal from dataLog()")
for dataLogStarted {
//log.Printf("closeDataLog(): dataLogStarted = %t\n", dataLogStarted) //REMOVE -- DEBUG
time.Sleep(50 * time.Millisecond)
}
log.Printf("datalog.go: Data log shutdown successful.\n")
}

355
main/equations.go 100644
Wyświetl plik

@ -0,0 +1,355 @@
/*
Copyright (c) 2016 AvSquirrel (https://github.com/AvSquirrel)
Distributable under the terms of the "BSD New" License
that can be found in the LICENSE file, herein included
as part of this header.
equations.go: Math and statistics library used to support AHRS
and other fuctions of Stratux package
*/
package main
import (
"fmt"
"math"
)
// linReg calculates slope and intercept for a least squares linear regression of y[] vs x[]
// Returns error if fewer than two data points in each series, or if series lengths are different
func linReg(x, y []float64) (slope, intercept float64, valid bool) {
n := len(x)
nf := float64(n)
if n != len(y) {
fmt.Printf("linReg: Lengths not equal\n")
return math.NaN(), math.NaN(), false
}
if n < 2 {
fmt.Printf("linReg: Lengths too short\n")
return math.NaN(), math.NaN(), false
}
var Sx, Sy, Sxx, Sxy, Syy float64
for i := range x {
Sx += x[i]
Sy += y[i]
Sxx += x[i] * x[i]
Sxy += x[i] * y[i]
Syy += y[i] * y[i]
}
if nf*Sxx == Sx*Sx {
fmt.Printf("linReg: Infinite slope\n")
return math.NaN(), math.NaN(), false
}
// Calculate slope and intercept
slope = (nf*Sxy - Sx*Sy) / (nf*Sxx - Sx*Sx)
intercept = Sy/nf - slope*Sx/nf
valid = true
return
}
// linRegWeighted calculates slope and intercept for a weighted least squares
// linear regression of y[] vs x[], given weights w[] for each point.
// Returns error if fewer than two data points in each series, if series lengths are different,
// if weights sum to zero, or if slope is infinite
func linRegWeighted(x, y, w []float64) (slope, intercept float64, valid bool) {
n := len(x)
if n != len(y) || n != len(w) {
fmt.Printf("linRegWeighted: Lengths not equal\n")
return math.NaN(), math.NaN(), false
}
if n < 2 {
fmt.Printf("linRegWeighted: Lengths too short\n")
return math.NaN(), math.NaN(), false
}
//var Sx, Sy, Sxx, Sxy, Syy float64
var Sw, Swx, Swy, Swxx, Swxy, Swyy float64
for i := range x {
Sw += w[i]
Swxy += w[i] * x[i] * y[i]
Swx += w[i] * x[i]
Swy += w[i] * y[i]
Swxx += w[i] * x[i] * x[i]
Swyy += w[i] * y[i] * y[i]
/*
Sx += x[i]
Sy += y[i]
Sxx += x[i]*x[i]
Sxy += x[i]*y[i]
Syy += y[i]*y[i]
*/
}
if Sw == 0 {
fmt.Printf("linRegWeighted: Sum of weights is zero\n")
return math.NaN(), math.NaN(), false
}
if Sw*Swxx == Swx*Swx {
fmt.Printf("linRegWeighted: Infinite slope\n")
return math.NaN(), math.NaN(), false
}
// Calculate slope and intercept
slope = (Sw*Swxy - Swx*Swy) / (Sw*Swxx - Swx*Swx)
intercept = Swy/Sw - slope*Swx/Sw
valid = true
return
}
// triCubeWeight returns the value of the tricube weight function
// at point x, for the given center and halfwidth.
func triCubeWeight(center, halfwidth, x float64) float64 {
var weight, x_t float64
x_t = math.Abs((x - center) / halfwidth)
if x_t < 1 {
weight = math.Pow((1 - math.Pow(x_t, 3)), 3)
} else {
weight = 0
}
return weight
}
// arrayMin calculates the minimum value in array x
func arrayMin(x []float64) (float64, bool) {
if len(x) < 1 {
fmt.Printf("arrayMin: Length too short\n")
return math.NaN(), false
}
min := x[0]
for i := range x {
if x[i] < min {
min = x[i]
}
}
return min, true
}
// arrayMax calculates the maximum value in array x
func arrayMax(x []float64) (float64, bool) {
if len(x) < 1 {
fmt.Printf("arrayMax: Length too short\n")
return math.NaN(), false
}
max := x[0]
for i := range x {
if x[i] > max {
max = x[i]
}
}
return max, true
}
// arrayRange calculates the range of values in array x
func arrayRange(x []float64) (float64, bool) {
max, err1 := arrayMax(x)
min, err2 := arrayMin(x)
if !err1 || !err2 {
fmt.Printf("Error calculating range\n")
return math.NaN(), false
}
return (max - min), true
}
// mean returns the arithmetic mean of array x
func mean(x []float64) (float64, bool) {
if len(x) < 1 {
fmt.Printf("mean: Length too short\n")
return math.NaN(), false
}
sum := 0.0
nf := float64(len(x))
for i := range x {
sum += x[i]
}
return sum / nf, true
}
// stdev estimates the sample standard deviation of array x
func stdev(x []float64) (float64, bool) {
if len(x) < 2 {
fmt.Printf("stdev: Length too short\n")
return math.NaN(), false
}
nf := float64(len(x))
xbar, xbarValid := mean(x)
if !xbarValid {
fmt.Printf("stdev: Error calculating xbar\n")
return math.NaN(), false
}
sumsq := 0.0
for i := range x {
sumsq += (x[i] - xbar) * (x[i] - xbar)
}
return math.Pow(sumsq/(nf-1), 0.5), true
}
// radians converts angle from degrees, and returns its value in radians
func radians(angle float64) float64 {
return angle * math.Pi / 180.0
}
// degrees converts angle from radians, and returns its value in degrees
func degrees(angle float64) float64 {
return angle * 180.0 / math.Pi
}
// radiansRel converts angle from degrees, and returns its value in radians in the range -Pi to + Pi
func radiansRel(angle float64) float64 {
for angle > 180 {
angle -= 360
}
for angle < -180 {
angle += 360
}
return angle * math.Pi / 180.0
}
// degreesRel converts angle from radians, and returns its value in the range of -180 to +180 degrees
func degreesRel(angle float64) float64 {
for angle > math.Pi {
angle -= 2 * math.Pi
}
for angle < -math.Pi {
angle += 2 * math.Pi
}
return angle * 180.0 / math.Pi
}
// degreesHdg converts angle from radians, and returns its value in the range of 0+ to 360 degrees
func degreesHdg(angle float64) float64 {
for angle < 0 {
angle += 2 * math.Pi
}
return angle * 180.0 / math.Pi
}
// roundToInt16 cheaply rounds a float64 to an int16, rather than truncating
func roundToInt16(in float64) (out int16) {
if in >= 0 {
out = int16(in + 0.5)
} else {
out = int16(in - 0.5)
}
return
}
/*
Distance functions based on rectangular coordinate systems
Simple calculations and "good enough" on small scale (± 1° of lat / lon)
suitable for relative distance to nearby traffic
*/
// distRect returns distance and bearing to target #2 (e.g. traffic) from target #1 (e.g. ownship)
// Inputs are lat / lon of both points in decimal degrees
// Outputs are distance in meters and bearing in degrees (0° = north, 90° = east)
// Secondary outputs are north and east components of distance in meters (north, east positive)
func distRect(lat1, lon1, lat2, lon2 float64) (dist, bearing, distN, distE float64) {
radius_earth := 6371008.8 // meters; mean radius
dLat := radiansRel(lat2 - lat1)
avgLat := radiansRel((lat2 + lat1) / 2)
dLon := radiansRel(lon2 - lon1)
distN = dLat * radius_earth
distE = dLon * radius_earth * math.Abs(math.Cos(avgLat))
dist = math.Pow(distN*distN+distE*distE, 0.5)
bearing = math.Atan2(distE, distN)
bearing = degreesHdg(bearing)
return
}
// distRectNorth returns north-south distance from point 1 to point 2.
// Inputs are lat in decimal degrees. Output is distance in meters (east positive)
func distRectNorth(lat1, lat2 float64) float64 {
var dist float64
radius_earth := 6371008.8 // meters; mean radius
dLat := radiansRel(lat2 - lat1)
dist = dLat * radius_earth
return dist
}
// distRectEast returns east-west distance from point 1 to point 2.
// Inputs are lat/lon in decimal degrees. Output is distance in meters (north positive)
func distRectEast(lat1, lon1, lat2, lon2 float64) float64 {
var dist float64
radius_earth := 6371008.8 // meters; mean radius
//dLat := radiansRel(lat2 - lat1) // unused
avgLat := radiansRel((lat2 + lat1) / 2)
dLon := radiansRel(lon2 - lon1)
dist = dLon * radius_earth * math.Abs(math.Cos(avgLat))
return dist
}
/*
Distance functions: Polar coordinate systems
More accurate over longer distances
*/
// distance calculates distance between two points using the law of cosines.
// Inputs are lat / lon of both points in decimal degrees
// Outputs are distance in meters and bearing to the target from origin in degrees (0° = north, 90° = east)
func distance(lat1, lon1, lat2, lon2 float64) (dist, bearing float64) {
radius_earth := 6371008.8 // meters; mean radius
lat1 = radians(lat1)
lon1 = radians(lon1)
lat2 = radians(lat2)
lon2 = radians(lon2)
dist = math.Acos(math.Sin(lat1)*math.Sin(lat2)+math.Cos(lat1)*math.Cos(lat2)*math.Cos(lon2-lon1)) * radius_earth
var x, y float64
x = math.Cos(lat1)*math.Sin(lat2) - math.Sin(lat1)*math.Cos(lat2)*math.Cos(lon2-lon1)
y = math.Sin(lon2-lon1) * math.Cos(lat2)
bearing = degreesHdg(math.Atan2(y, x))
return
}
// CalcAltitude determines the pressure altitude (feet) from the atmospheric pressure (hPa)
func CalcAltitude(press float64) (altitude float64) {
altitude = 145366.45 * (1.0 - math.Pow(press/1013.25, 0.190284))
return
}
// golang only defines min/max for float64. Really.
func iMin(x, y int) int {
if x < y {
return x
}
return y
}
func iMax(x, y int) int {
if x > y {
return x
}
return y
}

241
main/fancontrol.go 100644
Wyświetl plik

@ -0,0 +1,241 @@
package main
import (
"encoding/json"
"flag"
"fmt"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/takama/daemon"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"
)
// #include <wiringPi.h>
// #cgo LDFLAGS: -lwiringPi
import "C"
// Initialize Prometheus metrics.
var (
currentTemp = prometheus.NewGauge(prometheus.GaugeOpts{
Name: "current_temp",
Help: "Current CPU temp.",
})
totalFanOnTime = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "total_fan_on_time",
Help: "Total fan run time.",
},
[]string{"all"},
)
totalUptime = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "total_uptime",
Help: "Total uptime.",
},
[]string{"all"},
)
)
const (
// CPU temperature target, degrees C
defaultTempTarget = 50.
hysteresis = float32(1.)
pwmClockDivisor = 100
/* Minimum duty cycle is the point below which the fan does
/* not spin. This depends on both your fan and the switching
/* transistor used. */
defaultPwmDutyMin = 1
pwmDutyMax = 10
// Temperature at which we give up attempting active fan speed control and set it to full speed.
failsafeTemp = 65
// how often to update
delaySeconds = 30
// GPIO-1/BCM "18"/Pin 12 on a Raspberry Pi 3
defaultPin = 1
// name of the service
name = "fancontrol"
description = "cooling fan speed control based on CPU temperature"
// Address on which daemon should be listen.
addr = ":9977"
)
type FanControl struct {
TempTarget float32
TempCurrent float32
PWMDutyMin int
PWMDutyMax int
PWMDutyCurrent int
PWMPin int
}
var myFanControl FanControl
var stdlog, errlog *log.Logger
func updateStats() {
updateTicker := time.NewTicker(1 * time.Second)
for {
<-updateTicker.C
totalUptime.With(prometheus.Labels{"all": "all"}).Inc()
currentTemp.Set(float64(myFanControl.TempCurrent))
if myFanControl.PWMDutyCurrent > 0 {
totalFanOnTime.With(prometheus.Labels{"all": "all"}).Inc()
}
}
}
func fanControl() {
prometheus.MustRegister(currentTemp)
prometheus.MustRegister(totalFanOnTime)
prometheus.MustRegister(totalUptime)
go updateStats()
cPin := C.int(myFanControl.PWMPin)
C.wiringPiSetup()
// Power on "test". Allows the user to verify that their fan is working.
C.pinMode(cPin, C.OUTPUT)
C.digitalWrite(cPin, C.HIGH)
time.Sleep(5 * time.Second)
C.digitalWrite(cPin, C.LOW)
C.pwmSetMode(C.PWM_MODE_MS)
C.pinMode(cPin, C.PWM_OUTPUT)
C.pwmSetRange(C.uint(myFanControl.PWMDutyMax))
C.pwmSetClock(pwmClockDivisor)
C.pwmWrite(cPin, C.int(myFanControl.PWMDutyMin))
myFanControl.TempCurrent = 0
go cpuTempMonitor(func(cpuTemp float32) {
if isCPUTempValid(cpuTemp) {
myFanControl.TempCurrent = cpuTemp
}
})
myFanControl.PWMDutyCurrent = 0
delay := time.NewTicker(delaySeconds * time.Second)
for {
if myFanControl.TempCurrent > (myFanControl.TempTarget + hysteresis) {
myFanControl.PWMDutyCurrent = iMax(iMin(myFanControl.PWMDutyMax, myFanControl.PWMDutyCurrent+1), myFanControl.PWMDutyMin)
} else if myFanControl.TempCurrent < (myFanControl.TempTarget - hysteresis) {
myFanControl.PWMDutyCurrent = iMax(myFanControl.PWMDutyCurrent-1, 0)
if myFanControl.PWMDutyCurrent < myFanControl.PWMDutyMin {
myFanControl.PWMDutyCurrent = 0
}
}
//log.Println(myFanControl.TempCurrent, " ", myFanControl.PWMDutyCurrent)
C.pwmWrite(cPin, C.int(myFanControl.PWMDutyCurrent))
<-delay.C
if myFanControl.PWMDutyCurrent == myFanControl.PWMDutyMax && myFanControl.TempCurrent >= failsafeTemp {
// Reached the maximum temperature. We stop using PWM control and set the fan to "on" permanently.
break
}
}
// Default to "ON".
C.pinMode(cPin, C.OUTPUT)
C.digitalWrite(cPin, C.HIGH)
}
// Service has embedded daemon
type Service struct {
daemon.Daemon
}
// Manage by daemon commands or run the daemon
func (service *Service) Manage() (string, error) {
tempTarget := flag.Float64("temp", defaultTempTarget, "Target CPU Temperature, degrees C")
pwmDutyMin := flag.Int("minduty", defaultPwmDutyMin, "Minimum PWM duty cycle")
pin := flag.Int("pin", defaultPin, "PWM pin (wiringPi numbering)")
flag.Parse()
usage := "Usage: " + name + " install | remove | start | stop | status"
// if received any kind of command, do it
if flag.NArg() > 0 {
command := os.Args[flag.NFlag()+1]
switch command {
case "install":
return service.Install()
case "remove":
return service.Remove()
case "start":
return service.Start()
case "stop":
return service.Stop()
case "status":
return service.Status()
default:
return usage, nil
}
}
myFanControl.TempTarget = float32(*tempTarget)
myFanControl.PWMDutyMin = *pwmDutyMin
myFanControl.PWMDutyMax = pwmDutyMax
myFanControl.PWMPin = *pin
go fanControl()
// Set up channel on which to send signal notifications.
// We must use a buffered channel or risk missing the signal
// if we're not ready to receive when the signal is sent.
interrupt := make(chan os.Signal, 1)
signal.Notify(interrupt, os.Interrupt, os.Kill, syscall.SIGTERM)
http.HandleFunc("/", handleStatusRequest)
http.Handle("/metrics", promhttp.Handler())
http.ListenAndServe(addr, nil)
// interrupt by system signal
for {
killSignal := <-interrupt
stdlog.Println("Got signal:", killSignal)
if killSignal == os.Interrupt {
return "Daemon was interrupted by system signal", nil
}
return "Daemon was killed", nil
}
}
func handleStatusRequest(w http.ResponseWriter, r *http.Request) {
statusJSON, _ := json.Marshal(&myFanControl)
w.Write(statusJSON)
}
func init() {
stdlog = log.New(os.Stdout, "", 0)
errlog = log.New(os.Stderr, "", 0)
}
func main() {
srv, err := daemon.New(name, description, []string{}...)
if err != nil {
errlog.Println("Error: ", err)
os.Exit(1)
}
service := &Service{srv}
status, err := service.Manage()
if err != nil {
errlog.Println(status, "\nError: ", err)
os.Exit(1)
}
fmt.Println(status)
}

Plik diff jest za duży Load Diff

2140
main/gps.go 100644

Plik diff jest za duży Load Diff

Wyświetl plik

@ -0,0 +1,155 @@
package main
import (
"encoding/hex"
"fmt"
"github.com/stratux/serial"
"log"
"os"
"time"
"unsafe"
)
/*
#cgo LDFLAGS: -ldump978 -lm
#include <stdint.h>
#include "../dump978/fec.h"
*/
import "C"
var radioSerialConfig *serial.Config
var radioSerialPort *serial.Port
func initUATRadioSerial() error {
// Init for FEC routines.
C.init_fec()
go func() {
watchTicker := time.NewTicker(1 * time.Second)
for {
<-watchTicker.C
// Watch for the radio or change in settings.
if !globalSettings.UAT_Enabled || globalStatus.UATRadio_connected {
// UAT not enabled or radio already set up. Continue.
continue
}
if _, err := os.Stat("/dev/uatradio"); err != nil {
// Device not connected.
continue
}
log.Printf("===== UAT Device Name : UATRadio v1.0 =====\n")
// Initialize port at 2Mbaud.
radioSerialConfig = &serial.Config{Name: "/dev/uatradio", Baud: 2000000}
p, err := serial.OpenPort(radioSerialConfig)
if err != nil {
log.Printf("\tUAT Open Failed: %s\n", err.Error())
continue
}
log.Printf("\tUATRadio init success.\n")
radioSerialPort = p
globalStatus.UATRadio_connected = true
// Start a goroutine to watch the serial port.
go radioSerialPortReader(radioSerialPort)
}
}()
return nil
}
/*
radioSerialPortReader().
Loop to read data from the radio serial port.
*/
var radioMagic = []byte{0x0a, 0xb0, 0xcd, 0xe0}
func radioSerialPortReader(serialPort *serial.Port) {
defer func() {
globalStatus.UATRadio_connected = false
serialPort.Close()
}()
tmpBuf := make([]byte, 1024) // Read buffer.
var buf []byte // Message buffer.
for {
n, err := serialPort.Read(tmpBuf)
if err != nil {
log.Printf("serial port err, shutting down radio: %s\n", err.Error())
return
}
buf = append(buf, tmpBuf[:n]...)
bufLen := len(buf)
var finBuf []byte // Truncated buffer, with processed messages extracted.
var numMessages int // Number of messages extracted.
// Search for a suitable message to extract.
for i := 0; i < bufLen-6; i++ {
if (buf[i] == radioMagic[0]) && (buf[i+1] == radioMagic[1]) && (buf[i+2] == radioMagic[2]) && (buf[i+3] == radioMagic[3]) {
// Found the magic sequence. Get the length.
msgLen := int(uint16(buf[i+4])+(uint16(buf[i+5])<<8)) + 5 // 5 bytes for RSSI and TS.
// Check if we've read enough to finish this message.
if bufLen < i+6+msgLen {
break // Wait for more of the message to come in.
}
// Message is long enough.
processRadioMessage(buf[i+6 : i+6+msgLen])
// Remove everything in the buffer before this message.
finBuf = buf[i+6+msgLen:]
numMessages++
}
}
if numMessages > 0 {
buf = finBuf
}
}
}
/*
processRadioMessage().
Processes a single message from the radio. De-interleaves (when necessary), checks Reed-Solomon, passes to main process.
*/
func processRadioMessage(msg []byte) {
// RSSI and message timestamp are prepended to the actual packet.
// RSSI
rssiRaw := int8(msg[0])
//rssiAdjusted := int16(rssiRaw) - 132 // -132 dBm, calculated minimum RSSI.
//rssiDump978 := int16(1000 * (10 ^ (float64(rssiAdjusted) / 20)))
rssiDump978 := rssiRaw
//_ := uint32(msg[1]) + (uint32(msg[2]) << 8) + (uint32(msg[3]) << 16) + (uint32(msg[4]) << 24) // Timestamp. Currently unused.
msg = msg[5:]
var toRelay string
var rs_errors int
switch len(msg) {
case 552:
to := make([]byte, 552)
C.correct_uplink_frame((*C.uint8_t)(unsafe.Pointer(&msg[0])), (*C.uint8_t)(unsafe.Pointer(&to[0])), (*C.int)(unsafe.Pointer(&rs_errors)))
toRelay = fmt.Sprintf("+%s;ss=%d;", hex.EncodeToString(to[:432]), rssiDump978)
case 48:
to := make([]byte, 48)
copy(to, msg)
i := int(C.correct_adsb_frame((*C.uint8_t)(unsafe.Pointer(&to[0])), (*C.int)(unsafe.Pointer(&rs_errors))))
if i == 1 {
// Short ADS-B frame.
toRelay = fmt.Sprintf("-%s;ss=%d;", hex.EncodeToString(to[:18]), rssiDump978)
} else if i == 2 {
// Long ADS-B frame.
toRelay = fmt.Sprintf("-%s;ss=%d;", hex.EncodeToString(to[:34]), rssiDump978)
}
default:
log.Printf("processRadioMessage(): unhandled message size %d\n", len(msg))
}
if len(toRelay) > 0 && rs_errors != 9999 {
o, msgtype := parseInput(toRelay)
if o != nil && msgtype != 0 {
relayMessage(msgtype, o)
}
}
}

Wyświetl plik

@ -1,6 +1,6 @@
/*
Copyright (c) 2015-2016 Christopher Young
Distributable under the terms of The "BSD New"" License
Distributable under the terms of The "BSD New" License
that can be found in the LICENSE file, herein included
as part of this header.
@ -10,6 +10,7 @@
package main
import (
"archive/zip"
"encoding/hex"
"encoding/json"
"fmt"
@ -20,6 +21,9 @@ import (
"log"
"net/http"
"os"
"os/exec"
"path/filepath"
"regexp"
"strings"
"syscall"
"text/template"
@ -34,6 +38,31 @@ type SettingMessage struct {
// Weather updates channel.
var weatherUpdate *uibroadcaster
var trafficUpdate *uibroadcaster
var gdl90Update *uibroadcaster
func handleGDL90WS(conn *websocket.Conn) {
// Subscribe the socket to receive updates.
gdl90Update.AddSocket(conn)
// Connection closes when function returns. Since uibroadcast is writing and we don't need to read anything (for now), just keep it busy.
for {
buf := make([]byte, 1024)
_, err := conn.Read(buf)
if err != nil {
break
}
if buf[0] != 0 { // Dummy.
continue
}
time.Sleep(1 * time.Second)
}
}
// Situation updates channel.
var situationUpdate *uibroadcaster
// Raw weather (UATFrame packet stream) update channel.
var weatherRawUpdate *uibroadcaster
/*
The /weather websocket starts off by sending the current buffer of weather messages, then sends updates as they are received.
@ -56,6 +85,36 @@ func handleWeatherWS(conn *websocket.Conn) {
}
}
func handleJsonIo(conn *websocket.Conn) {
trafficMutex.Lock()
for _, traf := range traffic {
if !traf.Position_valid { // Don't send unless a valid position exists.
continue
}
trafficJSON, _ := json.Marshal(&traf)
conn.Write(trafficJSON)
}
// Subscribe the socket to receive updates.
trafficUpdate.AddSocket(conn)
weatherRawUpdate.AddSocket(conn)
situationUpdate.AddSocket(conn)
trafficMutex.Unlock()
// Connection closes when function returns. Since uibroadcast is writing and we don't need to read anything (for now), just keep it busy.
for {
buf := make([]byte, 1024)
_, err := conn.Read(buf)
if err != nil {
break
}
if buf[0] != 0 { // Dummy.
continue
}
time.Sleep(1 * time.Second)
}
}
// Works just as weather updates do.
func handleTrafficWS(conn *websocket.Conn) {
@ -103,7 +162,6 @@ func handleStatusWS(conn *websocket.Conn) {
*/
// Send status.
<-timer.C
update, _ := json.Marshal(&globalStatus)
_, err := conn.Write(update)
@ -111,19 +169,20 @@ func handleStatusWS(conn *websocket.Conn) {
// log.Printf("Web client disconnected.\n")
break
}
<-timer.C
}
}
func handleSituationWS(conn *websocket.Conn) {
timer := time.NewTicker(100 * time.Millisecond)
for {
<-timer.C
situationJSON, _ := json.Marshal(&mySituation)
_, err := conn.Write(situationJSON)
if err != nil {
break
}
<-timer.C
}
@ -150,6 +209,8 @@ func handleSituationRequest(w http.ResponseWriter, r *http.Request) {
func handleTowersRequest(w http.ResponseWriter, r *http.Request) {
setNoCache(w)
setJSONHeaders(w)
ADSBTowerMutex.Lock()
towersJSON, err := json.Marshal(&ADSBTowers)
if err != nil {
log.Printf("Error sending tower JSON data: %s\n", err.Error())
@ -157,12 +218,27 @@ func handleTowersRequest(w http.ResponseWriter, r *http.Request) {
// for testing purposes, we can return a fixed reply
// towersJSON = []byte(`{"(38.490880,-76.135554)":{"Lat":38.49087953567505,"Lng":-76.13555431365967,"Signal_strength_last_minute":100,"Signal_strength_max":67,"Messages_last_minute":1,"Messages_total":1059},"(38.978698,-76.309276)":{"Lat":38.97869825363159,"Lng":-76.30927562713623,"Signal_strength_last_minute":495,"Signal_strength_max":32,"Messages_last_minute":45,"Messages_total":83},"(39.179285,-76.668413)":{"Lat":39.17928457260132,"Lng":-76.66841268539429,"Signal_strength_last_minute":50,"Signal_strength_max":24,"Messages_last_minute":1,"Messages_total":16},"(39.666309,-74.315300)":{"Lat":39.66630935668945,"Lng":-74.31529998779297,"Signal_strength_last_minute":9884,"Signal_strength_max":35,"Messages_last_minute":4,"Messages_total":134}}`)
fmt.Fprintf(w, "%s\n", towersJSON)
ADSBTowerMutex.Unlock()
}
// AJAX call - /getSatellites. Responds with all GNSS satellites that are being tracked, along with status information.
func handleSatellitesRequest(w http.ResponseWriter, r *http.Request) {
setNoCache(w)
setJSONHeaders(w)
mySituation.muSatellite.Lock()
satellitesJSON, err := json.Marshal(&Satellites)
if err != nil {
log.Printf("Error sending GNSS satellite JSON data: %s\n", err.Error())
}
fmt.Fprintf(w, "%s\n", satellitesJSON)
mySituation.muSatellite.Unlock()
}
// AJAX call - /getSettings. Responds with all stratux.conf data.
func handleSettingsGetRequest(w http.ResponseWriter, r *http.Request) {
setNoCache(w)
setJSONHeaders(w)
readWiFiUserSettings()
settingsJSON, _ := json.Marshal(&globalSettings)
fmt.Fprintf(w, "%s\n", settingsJSON)
}
@ -181,6 +257,7 @@ func handleSettingsSetRequest(w http.ResponseWriter, r *http.Request) {
// raw, _ := httputil.DumpRequest(r, true)
// log.Printf("handleSettingsSetRequest:raw: %s\n", raw)
var resetWiFi bool
decoder := json.NewDecoder(r.Body)
for {
var msg map[string]interface{} // support arbitrary JSON
@ -194,26 +271,67 @@ func handleSettingsSetRequest(w http.ResponseWriter, r *http.Request) {
for key, val := range msg {
// log.Printf("handleSettingsSetRequest:json: testing for key:%s of type %s\n", key, reflect.TypeOf(val))
switch key {
case "DarkMode":
globalSettings.DarkMode = val.(bool)
case "UAT_Enabled":
globalSettings.UAT_Enabled = val.(bool)
case "ES_Enabled":
globalSettings.ES_Enabled = val.(bool)
case "Ping_Enabled":
globalSettings.Ping_Enabled = val.(bool)
case "GPS_Enabled":
globalSettings.GPS_Enabled = val.(bool)
case "AHRS_Enabled":
globalSettings.AHRS_Enabled = val.(bool)
case "IMU_Sensor_Enabled":
globalSettings.IMU_Sensor_Enabled = val.(bool)
if !globalSettings.IMU_Sensor_Enabled && globalStatus.IMUConnected {
myIMUReader.Close()
globalStatus.IMUConnected = false
}
case "BMP_Sensor_Enabled":
globalSettings.BMP_Sensor_Enabled = val.(bool)
if !globalSettings.BMP_Sensor_Enabled && globalStatus.BMPConnected {
myPressureReader.Close()
globalStatus.BMPConnected = false
}
case "DEBUG":
globalSettings.DEBUG = val.(bool)
case "DisplayTrafficSource":
globalSettings.DisplayTrafficSource = val.(bool)
case "ReplayLog":
v := val.(bool)
if v != globalSettings.ReplayLog { // Don't mark the files unless there is a change.
globalSettings.ReplayLog = v
replayMark(v)
}
case "AHRSLog":
globalSettings.AHRSLog = val.(bool)
case "IMUMapping":
if globalSettings.IMUMapping != val.([2]int) {
globalSettings.IMUMapping = val.([2]int)
myIMUReader.Close()
globalStatus.IMUConnected = false // Force a restart of the IMU reader
}
case "PPM":
globalSettings.PPM = int(val.(float64))
case "Baud":
if serialOut, ok := globalSettings.SerialOutputs["/dev/serialout0"]; ok { //FIXME: Only one device for now.
newBaud := int(val.(float64))
if newBaud == serialOut.Baud { // Same baud rate. No change.
continue
}
log.Printf("changing /dev/serialout0 baud rate from %d to %d.\n", serialOut.Baud, newBaud)
serialOut.Baud = newBaud
// Close the port if it is open.
if serialOut.serialPort != nil {
log.Printf("closing /dev/serialout0 for baud rate change.\n")
serialOut.serialPort.Close()
serialOut.serialPort = nil
}
globalSettings.SerialOutputs["/dev/serialout0"] = serialOut
}
case "WatchList":
globalSettings.WatchList = val.(string)
case "GLimits":
globalSettings.GLimits = val.(string)
case "OwnshipModeS":
// Expecting a hex string less than 6 characters (24 bits) long.
if len(val.(string)) > 6 { // Too long.
@ -230,15 +348,70 @@ func handleSettingsSetRequest(w http.ResponseWriter, r *http.Request) {
continue
}
globalSettings.OwnshipModeS = fmt.Sprintf("%02X%02X%02X", hexn[0], hexn[1], hexn[2])
case "StaticIps":
ipsStr := val.(string)
ips := strings.Split(ipsStr, " ")
if ipsStr == "" {
ips = make([]string, 0)
}
re, _ := regexp.Compile(`^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$`)
err := ""
for _, ip := range ips {
// Verify IP format
if !re.MatchString(ip) {
err = err + "Invalid IP: " + ip + ". "
}
}
if err != "" {
log.Printf("handleSettingsSetRequest:StaticIps: %s\n", err)
continue
}
globalSettings.StaticIps = ips
case "WiFiSSID":
globalSettings.WiFiSSID = val.(string)
resetWiFi = true
case "WiFiChannel":
globalSettings.WiFiChannel = int(val.(float64))
resetWiFi = true
case "WiFiSecurityEnabled":
globalSettings.WiFiSecurityEnabled = val.(bool)
resetWiFi = true
case "WiFiPassphrase":
globalSettings.WiFiPassphrase = val.(string)
resetWiFi = true
case "WiFiSmartEnabled":
globalSettings.WiFiSmartEnabled = val.(bool)
resetWiFi = true
default:
log.Printf("handleSettingsSetRequest:json: unrecognized key:%s\n", key)
}
}
saveSettings()
if resetWiFi {
saveWiFiUserSettings()
go func() {
time.Sleep(time.Second)
cmd := exec.Command("ifdown", "wlan0")
if err := cmd.Start(); err != nil {
log.Printf("Error shutting down WiFi: %s\n", err.Error())
}
if err = cmd.Wait(); err != nil {
log.Printf("Error shutting down WiFi: %s\n", err.Error())
}
cmd = exec.Command("ifup", "wlan0")
if err := cmd.Start(); err != nil {
log.Printf("Error starting WiFi: %s\n", err.Error())
}
if err = cmd.Wait(); err != nil {
log.Printf("Error starting WiFi: %s\n", err.Error())
}
}()
}
}
}
// while it may be redundent, we return the latest settings
// while it may be redundant, we return the latest settings
settingsJSON, _ := json.Marshal(&globalSettings)
fmt.Fprintf(w, "%s\n", settingsJSON)
}
@ -246,23 +419,163 @@ func handleSettingsSetRequest(w http.ResponseWriter, r *http.Request) {
func handleShutdownRequest(w http.ResponseWriter, r *http.Request) {
syscall.Sync()
gracefulShutdown()
syscall.Reboot(syscall.LINUX_REBOOT_CMD_POWER_OFF)
}
func doReboot() {
syscall.Sync()
gracefulShutdown()
syscall.Reboot(syscall.LINUX_REBOOT_CMD_RESTART)
}
func handleDeleteLogFile(w http.ResponseWriter, r *http.Request) {
log.Println("handleDeleteLogFile called!!!")
clearDebugLogFile()
}
func handleDeleteAHRSLogFiles(w http.ResponseWriter, r *http.Request) {
files, err := ioutil.ReadDir("/var/log")
if err != nil {
http.Error(w, fmt.Sprintf("error deleting AHRS logs: %s", err), http.StatusNotFound)
return
}
var fn string
for _, f := range files {
fn = f.Name()
if v, _ := filepath.Match("sensors_*.csv", fn); v {
os.Remove("/var/log/" + fn)
log.Printf("Deleting AHRS log file %s\n", fn)
}
analysisLogger = nil
}
}
func handleDevelModeToggle(w http.ResponseWriter, r *http.Request) {
log.Printf("handleDevelModeToggle called!!!\n")
globalSettings.DeveloperMode = true
saveSettings()
}
func handleRestartRequest(w http.ResponseWriter, r *http.Request) {
log.Printf("handleRestartRequest called\n")
go doRestartApp()
}
func handleRebootRequest(w http.ResponseWriter, r *http.Request) {
doReboot()
setNoCache(w)
setJSONHeaders(w)
w.Header().Set("Access-Control-Allow-Method", "GET, POST, OPTIONS")
w.Header().Set("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept")
go delayReboot()
}
func handleOrientAHRS(w http.ResponseWriter, r *http.Request) {
// define header in support of cross-domain AJAX
setNoCache(w)
w.Header().Set("Content-Type", "text/plain")
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Method", "GET, POST, OPTIONS")
w.Header().Set("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept")
// For an OPTION method request, we return header without processing.
// This ensures we are recognized as supporting cross-domain AJAX REST calls.
if r.Method == "POST" {
var (
action []byte = make([]byte, 1)
err error
)
if _, err = r.Body.Read(action); err != nil {
log.Println("AHRS Error: handleOrientAHRS received invalid request")
http.Error(w, "orientation received invalid request", http.StatusBadRequest)
}
switch action[0] {
case 'f': // Set sensor "forward" direction (toward nose of airplane).
f, err := getMinAccelDirection()
if err != nil {
log.Printf("AHRS Error: sensor orientation: couldn't read accelerometer: %s\n", err)
http.Error(w, fmt.Sprintf("couldn't read accelerometer: %s\n", err), http.StatusBadRequest)
return
}
log.Printf("AHRS Info: sensor orientation success! forward axis is %d\n", f)
globalSettings.IMUMapping = [2]int{f, 0}
case 'd': // Set sensor "up" direction (toward top of airplane).
globalSettings.SensorQuaternion = [4]float64{0, 0, 0, 0}
saveSettings()
myIMUReader.Close()
globalStatus.IMUConnected = false // restart the processes depending on the orientation
ResetAHRSGLoad()
time.Sleep(2000 * time.Millisecond)
}
}
}
func handleCageAHRS(w http.ResponseWriter, r *http.Request) {
// define header in support of cross-domain AJAX
setNoCache(w)
w.Header().Set("Content-Type", "text/plain")
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Method", "GET, POST, OPTIONS")
w.Header().Set("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept")
// For an OPTION method request, we return header without processing.
// This ensures we are recognized as supporting cross-domain AJAX REST calls.
if r.Method == "POST" {
CageAHRS()
}
}
func handleCalibrateAHRS(w http.ResponseWriter, r *http.Request) {
// define header in support of cross-domain AJAX
setNoCache(w)
w.Header().Set("Content-Type", "text/plain")
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Method", "GET, POST, OPTIONS")
w.Header().Set("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept")
// For an OPTION method request, we return header without processing.
// This ensures we are recognized as supporting cross-domain AJAX REST calls.
if r.Method == "POST" {
CalibrateAHRS()
}
}
func handleResetGMeter(w http.ResponseWriter, r *http.Request) {
// define header in support of cross-domain AJAX
setNoCache(w)
w.Header().Set("Content-Type", "text/plain")
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Method", "GET, POST, OPTIONS")
w.Header().Set("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept")
// For an OPTION method request, we return header without processing.
// This ensures we are recognized as supporting cross-domain AJAX REST calls.
if r.Method == "POST" {
ResetAHRSGLoad()
}
}
func doRestartApp() {
time.Sleep(1)
syscall.Sync()
out, err := exec.Command("/bin/systemctl", "restart", "stratux").Output()
if err != nil {
log.Printf("restart error: %s\n%s", err.Error(), out)
} else {
log.Printf("restart: %s\n", out)
}
}
// AJAX call - /getClients. Responds with all connected clients.
func handleClientsGetRequest(w http.ResponseWriter, r *http.Request) {
setNoCache(w)
setJSONHeaders(w)
netMutex.Lock()
clientsJSON, _ := json.Marshal(&outSockets)
netMutex.Unlock()
fmt.Fprintf(w, "%s\n", clientsJSON)
}
@ -271,6 +584,68 @@ func delayReboot() {
doReboot()
}
func handleDownloadLogRequest(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/zip")
w.Header().Set("Content-Disposition", "attachment; filename='stratux.log'")
http.ServeFile(w, r, "/var/log/stratux.log")
}
func handleDownloadAHRSLogsRequest(w http.ResponseWriter, r *http.Request) {
// Common error handler
httpErr := func(w http.ResponseWriter, e error) {
http.Error(w, fmt.Sprintf("error zipping AHRS logs: %s", e), http.StatusNotFound)
}
files, err := ioutil.ReadDir("/var/log")
if err != nil {
httpErr(w, err)
return
}
z := zip.NewWriter(w)
defer z.Close()
for _, f := range files {
fn := f.Name()
v1, _ := filepath.Match("sensors_*.csv", fn)
v2, _ := filepath.Match("stratux.log", fn)
if !(v1 || v2) {
continue
}
unzippedFile, err := os.Open("/var/log/" + fn)
if err != nil {
httpErr(w, err)
return
}
fh, err := zip.FileInfoHeader(f)
if err != nil {
httpErr(w, err)
return
}
zippedFile, err := z.CreateHeader(fh)
if err != nil {
httpErr(w, err)
return
}
_, err = io.Copy(zippedFile, unzippedFile)
if err != nil {
httpErr(w, err)
return
}
}
w.Header().Set("Content-Type", "application/zip")
w.Header().Set("Content-Disposition", "attachment; filename=\"ahrs_logs.zip\"")
}
func handleDownloadDBRequest(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/zip")
w.Header().Set("Content-Disposition", "attachment; filename='stratux.sqlite'")
http.ServeFile(w, r, "/var/log/stratux.sqlite")
}
// Upload an update file.
func handleUpdatePostRequest(w http.ResponseWriter, r *http.Request) {
setNoCache(w)
@ -282,7 +657,12 @@ func handleUpdatePostRequest(w http.ResponseWriter, r *http.Request) {
return
}
defer file.Close()
updateFile := fmt.Sprintf("/root/%s", handler.Filename)
// Special hardware builds. Don't allow an update unless the filename contains the hardware build name.
if (len(globalStatus.HardwareBuild) > 0) && !strings.Contains(strings.ToLower(handler.Filename), strings.ToLower(globalStatus.HardwareBuild)) {
w.WriteHeader(404)
return
}
updateFile := fmt.Sprintf("/root/update-stratux-v.sh")
f, err := os.OpenFile(updateFile, os.O_WRONLY|os.O_CREATE, 0666)
if err != nil {
log.Printf("Update failed from %s (%s).\n", r.RemoteAddr, err.Error())
@ -312,6 +692,17 @@ func defaultServer(w http.ResponseWriter, r *http.Request) {
http.FileServer(http.Dir("/var/www")).ServeHTTP(w, r)
}
func handleroPartitionRebuild(w http.ResponseWriter, r *http.Request) {
out, err := exec.Command("/usr/sbin/rebuild_ro_part.sh").Output()
if err != nil {
addSingleSystemErrorf("partition-rebuild", "Rebuild RO Partition error: %s", err.Error())
} else {
addSingleSystemErrorf("partition-rebuild", "Rebuild RO Partition success: %s", out)
}
}
// https://gist.github.com/alexisrobert/982674.
// Copyright (c) 2010-2014 Alexis ROBERT <alexis.robert@gmail.com>.
const dirlisting_tpl = `<?xml version="1.0" encoding="iso-8859-1"?>
@ -364,6 +755,7 @@ type dirlisting struct {
ServerUA string
}
//FIXME: This needs to be switched to show a "sessions log" from the sqlite database.
func viewLogs(w http.ResponseWriter, r *http.Request) {
names, err := ioutil.ReadDir("/var/log/stratux/")
@ -401,11 +793,20 @@ func viewLogs(w http.ResponseWriter, r *http.Request) {
func managementInterface() {
weatherUpdate = NewUIBroadcaster()
trafficUpdate = NewUIBroadcaster()
situationUpdate = NewUIBroadcaster()
weatherRawUpdate = NewUIBroadcaster()
gdl90Update = NewUIBroadcaster()
http.HandleFunc("/", defaultServer)
http.Handle("/logs/", http.StripPrefix("/logs/", http.FileServer(http.Dir("/var/log"))))
http.HandleFunc("/view_logs/", viewLogs)
http.HandleFunc("/gdl90",
func(w http.ResponseWriter, req *http.Request) {
s := websocket.Server{
Handler: websocket.Handler(handleGDL90WS)}
s.ServeHTTP(w, req)
})
http.HandleFunc("/status",
func(w http.ResponseWriter, req *http.Request) {
s := websocket.Server{
@ -431,15 +832,35 @@ func managementInterface() {
s.ServeHTTP(w, req)
})
http.HandleFunc("/jsonio",
func(w http.ResponseWriter, req *http.Request) {
s := websocket.Server{
Handler: websocket.Handler(handleJsonIo)}
s.ServeHTTP(w, req)
})
http.HandleFunc("/getStatus", handleStatusRequest)
http.HandleFunc("/getSituation", handleSituationRequest)
http.HandleFunc("/getTowers", handleTowersRequest)
http.HandleFunc("/getSatellites", handleSatellitesRequest)
http.HandleFunc("/getSettings", handleSettingsGetRequest)
http.HandleFunc("/setSettings", handleSettingsSetRequest)
http.HandleFunc("/restart", handleRestartRequest)
http.HandleFunc("/shutdown", handleShutdownRequest)
http.HandleFunc("/reboot", handleRebootRequest)
http.HandleFunc("/getClients", handleClientsGetRequest)
http.HandleFunc("/updateUpload", handleUpdatePostRequest)
http.HandleFunc("/roPartitionRebuild", handleroPartitionRebuild)
http.HandleFunc("/develmodetoggle", handleDevelModeToggle)
http.HandleFunc("/orientAHRS", handleOrientAHRS)
http.HandleFunc("/calibrateAHRS", handleCalibrateAHRS)
http.HandleFunc("/cageAHRS", handleCageAHRS)
http.HandleFunc("/resetGMeter", handleResetGMeter)
http.HandleFunc("/deletelogfile", handleDeleteLogFile)
http.HandleFunc("/downloadlog", handleDownloadLogRequest)
http.HandleFunc("/deleteahrslogfiles", handleDeleteAHRSLogFiles)
http.HandleFunc("/downloadahrslogs", handleDownloadAHRSLogsRequest)
http.HandleFunc("/downloaddb", handleDownloadDBRequest)
err := http.ListenAndServe(managementAddr, nil)

Wyświetl plik

@ -1,6 +1,6 @@
/*
Copyright (c) 2015-2016 Christopher Young
Distributable under the terms of The "BSD New"" License
Distributable under the terms of The "BSD New" License
that can be found in the LICENSE file, herein included
as part of this header.
@ -21,13 +21,18 @@ type monotonic struct {
Milliseconds uint64
Time time.Time
ticker *time.Ticker
realTimeSet bool
RealTime time.Time
}
func (m *monotonic) Watcher() {
for {
<-m.ticker.C
m.Milliseconds += 50
m.Time = m.Time.Add(50 * time.Millisecond)
m.Milliseconds += 10
m.Time = m.Time.Add(10 * time.Millisecond)
if m.realTimeSet {
m.RealTime = m.RealTime.Add(10 * time.Millisecond)
}
}
}
@ -43,8 +48,19 @@ func (m *monotonic) Unix() int64 {
return int64(m.Since(time.Time{}).Seconds())
}
func (m *monotonic) HasRealTimeReference() bool {
return m.realTimeSet
}
func (m *monotonic) SetRealTimeReference(t time.Time) {
if !m.realTimeSet { // Only allow the real clock to be set once.
m.RealTime = t
m.realTimeSet = true
}
}
func NewMonotonic() *monotonic {
t := &monotonic{Milliseconds: 0, Time: time.Time{}, ticker: time.NewTicker(50 * time.Millisecond)}
t := &monotonic{Milliseconds: 0, Time: time.Time{}, ticker: time.NewTicker(10 * time.Millisecond)}
go t.Watcher()
return t
}

Wyświetl plik

@ -1,6 +1,6 @@
/*
Copyright (c) 2015-2016 Christopher Young
Distributable under the terms of The "BSD New"" License
Distributable under the terms of The "BSD New" License
that can be found in the LICENSE file, herein included
as part of this header.
@ -10,6 +10,7 @@
package main
import (
"github.com/tarm/serial"
"golang.org/x/net/icmp"
"golang.org/x/net/ipv4"
"io/ioutil"
@ -32,11 +33,12 @@ type networkMessage struct {
}
type networkConnection struct {
Conn *net.UDPConn
Ip string
Port uint32
Capability uint8
messageQueue [][]byte // Device message queue.
Conn *net.UDPConn
Ip string
Port uint32
Capability uint8
messageQueue [][]byte // Device message queue.
MessageQueueLen int // Length of the message queue. For debugging.
/*
Sleep mode/throttle variables. "sleep mode" is actually now just a very reduced packet rate, since we don't know positively
when a client is ready to accept packets - we just assume so if we don't receive ICMP Unreachable packets in 5 secs.
@ -45,26 +47,46 @@ type networkConnection struct {
nextMessageTime time.Time // The next time that the device is "able" to receive a message.
numOverflows uint32 // Number of times the queue has overflowed - for calculating the amount to chop off from the queue.
SleepFlag bool // Whether or not this client has been marked as sleeping - only used for debugging (relies on messages being sent to update this flag in sendToAllConnectedClients()).
FFCrippled bool
}
type serialConnection struct {
DeviceString string
Baud int
serialPort *serial.Port
}
var messageQueue chan networkMessage
var outSockets map[string]networkConnection
var dhcpLeases map[string]string
var netMutex *sync.Mutex
var pingResponse map[string]time.Time // Last time an IP responded to an "echo" response.
var netMutex *sync.Mutex // netMutex needs to be locked before accessing dhcpLeases, pingResponse, and outSockets and calling isSleeping() and isThrottled().
var totalNetworkMessagesSent uint32
var pingResponse map[string]time.Time // Last time an IP responded to an "echo" response.
const (
NETWORK_GDL90_STANDARD = 1
NETWORK_AHRS_FFSIM = 2
NETWORK_AHRS_GDL90 = 4
dhcp_lease_file = "/var/lib/dhcp/dhcpd.leases"
dhcp_lease_dir = "/var/lib/dhcp"
extra_hosts_file = "/etc/stratux-static-hosts.conf"
)
var dhcpLeaseDirectoryLastTest time.Time // Last time fsWriteTest() was run on the DHCP lease directory.
// Read the "dhcpd.leases" file and parse out IP/hostname.
func getDHCPLeases() (map[string]string, error) {
// Do a write test. Even if we are able to read the file, it may be out of date because there's a fs write issue.
// Only perform the test once every 5 minutes to minimize writes.
if stratuxClock.Since(dhcpLeaseDirectoryLastTest) >= 5*time.Minute {
err := fsWriteTest(dhcp_lease_dir)
if err != nil {
addSingleSystemErrorf("fs-write", "Write error on '%s', your EFB may have issues receiving weather and traffic.", dhcp_lease_dir)
}
dhcpLeaseDirectoryLastTest = stratuxClock.Time
}
dat, err := ioutil.ReadFile(dhcp_lease_file)
ret := make(map[string]string)
if err != nil {
@ -82,30 +104,53 @@ func getDHCPLeases() (map[string]string, error) {
hostname := strings.TrimRight(strings.TrimLeft(strings.Join(spaced[3:], " "), "\""), "\";")
ret[block_ip] = hostname
open_block = false
} else if open_block && len(spaced) >= 4 && spaced[2] == "ends" {
end_time := spaced[4] + " " + strings.TrimRight(spaced[5], ";")
// Mon Jan 2 15:04:05 -0700 MST 2006.
// 2016/02/02 00:39:59.
t, err := time.Parse("2006/01/02 15:04:05", end_time) // "In the absence of a time zone indicator, Parse returns a time in UTC."
if err == nil && t.Before(time.Now()) {
log.Printf("lease expired for %s (%s) - skipping.\n", block_ip, end_time)
open_block = false
delete(ret, block_ip)
block_ip = ""
}
} else if open_block && strings.HasPrefix(spaced[0], "}") { // No hostname.
open_block = false
ret[block_ip] = ""
}
}
// Add IP's set through the settings page
if globalSettings.StaticIps != nil {
for _, ip := range globalSettings.StaticIps {
ret[ip] = ""
}
}
// Added the ability to have static IP hosts stored in /etc/stratux-static-hosts.conf
dat2, err := ioutil.ReadFile(extra_hosts_file)
if err != nil {
return ret, nil
}
iplines := strings.Split(string(dat2), "\n")
block_ip2 := ""
for _, ipline := range iplines {
spacedip := strings.Split(ipline, " ")
if len(spacedip) == 2 {
// The ip is in block_ip2
block_ip2 = spacedip[0]
// the hostname is here
ret[block_ip2] = spacedip[1]
}
}
return ret, nil
}
/*
isSleeping().
Check if a client identifier 'ip:port' is in either a sleep or active state.
***WARNING***: netMutex must be locked before calling this function.
*/
func isSleeping(k string) bool {
if globalSettings.NoSleep == true {
return false
}
ipAndPort := strings.Split(k, ":")
lastPing, ok := pingResponse[ipAndPort[0]]
// No ping response. Assume disconnected/sleeping device.
if !ok || stratuxClock.Since(lastPing) > (10*time.Second) {
if lastPing, ok := pingResponse[ipAndPort[0]]; !ok || stratuxClock.Since(lastPing) > (10*time.Second) {
return true
}
if stratuxClock.Since(outSockets[k].LastUnreachable) < (5 * time.Second) {
@ -114,13 +159,24 @@ func isSleeping(k string) bool {
return false
}
// Throttle mode for testing port open and giving some start-up time to the app.
// Throttling is 0.1% data rate for first 15 seconds.
/*
isThrottled().
Checks if a client identifier 'ip:port' is throttled.
Throttle mode is for testing port open and giving some start-up time to the app.
Throttling is 0.1% data rate for first 15 seconds.
***WARNING***: netMutex must be locked before calling this function.
*/
func isThrottled(k string) bool {
return (rand.Int()%1000 != 0) && stratuxClock.Since(outSockets[k].LastUnreachable) < (15*time.Second)
}
func sendToAllConnectedClients(msg networkMessage) {
if (msg.msgType & NETWORK_GDL90_STANDARD) != 0 {
// It's a GDL90 message. Send to serial output channel (which may or may not cause something to happen).
serialOutputChan <- msg.msg
networkGDL90Chan <- msg.msg
}
netMutex.Lock()
defer netMutex.Unlock()
for k, netconn := range outSockets {
@ -167,9 +223,82 @@ func sendToAllConnectedClients(msg networkMessage) {
}
}
// Returns the number of DHCP leases and prints queue lengths
func getNetworkStats() uint {
for _, netconn := range outSockets {
var serialOutputChan chan []byte
var networkGDL90Chan chan []byte
func networkOutWatcher() {
for {
ch := <-networkGDL90Chan
gdl90Update.SendJSON(ch)
}
}
// Monitor serial output channel, send to serial port.
func serialOutWatcher() {
// Check every 30 seconds for a serial output device.
serialTicker := time.NewTicker(30 * time.Second)
serialDev := "/dev/serialout0" //FIXME: This is temporary. Only one serial output device for now.
for {
select {
case <-serialTicker.C:
if _, err := os.Stat(serialDev); !os.IsNotExist(err) { // Check if the device file exists.
var thisSerialConn serialConnection
// Check if we need to start handling a new device.
if val, ok := globalSettings.SerialOutputs[serialDev]; !ok {
newSerialOut := serialConnection{DeviceString: serialDev, Baud: 38400}
log.Printf("detected new serial output, setting up now: %s. Default baudrate 38400.\n", serialDev)
if globalSettings.SerialOutputs == nil {
globalSettings.SerialOutputs = make(map[string]serialConnection)
}
globalSettings.SerialOutputs[serialDev] = newSerialOut
saveSettings()
thisSerialConn = newSerialOut
} else {
thisSerialConn = val
}
// Check if we need to open the connection now.
if thisSerialConn.serialPort == nil {
cfg := &serial.Config{Name: thisSerialConn.DeviceString, Baud: thisSerialConn.Baud}
p, err := serial.OpenPort(cfg)
if err != nil {
log.Printf("serialout port (%s) err: %s\n", thisSerialConn.DeviceString, err.Error())
break // We'll attempt again in 30 seconds.
} else {
log.Printf("opened serialout: Name: %s, Baud: %d\n", thisSerialConn.DeviceString, thisSerialConn.Baud)
}
// Save the serial port connection.
thisSerialConn.serialPort = p
globalSettings.SerialOutputs[serialDev] = thisSerialConn
}
}
case b := <-serialOutputChan:
if val, ok := globalSettings.SerialOutputs[serialDev]; ok {
if val.serialPort != nil {
_, err := val.serialPort.Write(b)
if err != nil { // Encountered an error in writing to the serial port. Close it and set Serial_out_enabled.
log.Printf("serialout (%s) port err: %s. Closing port.\n", val.DeviceString, err.Error())
val.serialPort.Close()
val.serialPort = nil
globalSettings.SerialOutputs[serialDev] = val
}
}
}
}
}
}
// Returns the number of DHCP leases and prints queue lengths.
func getNetworkStats() {
netMutex.Lock()
defer netMutex.Unlock()
var numNonSleepingClients uint
for k, netconn := range outSockets {
queueBytes := 0
for _, msg := range netconn.messageQueue {
queueBytes += len(msg)
@ -177,11 +306,21 @@ func getNetworkStats() uint {
if globalSettings.DEBUG {
log.Printf("On %s:%d, Queue length = %d messages / %d bytes\n", netconn.Ip, netconn.Port, len(netconn.messageQueue), queueBytes)
}
ipAndPort := strings.Split(k, ":")
if len(ipAndPort) != 2 {
continue
}
ip := ipAndPort[0]
if pingRespTime, ok := pingResponse[ip]; ok {
// Don't count the ping time if it is the same as stratuxClock epoch.
// If the client has responded to a ping in the last 15 minutes, count it as "connected" or "recent".
if !pingRespTime.Equal(time.Time{}) && stratuxClock.Since(pingRespTime) < 15*time.Minute {
numNonSleepingClients++
}
}
}
ret := uint(len(dhcpLeases))
globalStatus.Connected_Users = ret
return ret
globalStatus.Connected_Users = numNonSleepingClients
}
// See who has a DHCP lease and make a UDP connection to each of them.
@ -228,7 +367,7 @@ func refreshConnectedClients() {
}
func messageQueueSender() {
secondTimer := time.NewTicker(15 * time.Second)
secondTimer := time.NewTicker(15 * time.Second) // getNetworkStats().
queueTimer := time.NewTicker(100 * time.Millisecond)
var lastQueueTimeChange time.Time // Reevaluate send frequency every 5 seconds.
@ -288,6 +427,8 @@ func messageQueueSender() {
outSockets[k] = tmpConn
*/
}
netconn.MessageQueueLen = len(netconn.messageQueue)
outSockets[k] = netconn
}
if stratuxClock.Since(lastQueueTimeChange) >= 5*time.Second {
@ -298,7 +439,10 @@ func messageQueueSender() {
} else {
pd = float64(0.1) // 100ms.
}
log.Printf("Average sendable queue is %v messages. Changing queue timer to %f seconds\n", averageSendableQueueSize, pd)
if globalSettings.DEBUG {
log.Printf("Average sendable queue is %v messages. Changing queue timer to %f seconds\n", averageSendableQueueSize, pd)
}
queueTimer.Stop()
queueTimer = time.NewTicker(time.Duration(pd*1000000000.0) * time.Nanosecond)
@ -333,6 +477,7 @@ func icmpEchoSender(c *icmp.PacketConn) {
timer := time.NewTicker(5 * time.Second)
for {
<-timer.C
netMutex.Lock()
// Collect IPs.
ips := make(map[string]bool)
for k, _ := range outSockets {
@ -359,6 +504,7 @@ func icmpEchoSender(c *icmp.PacketConn) {
}
totalNetworkMessagesSent++
}
netMutex.Unlock()
}
}
@ -387,7 +533,9 @@ func sleepMonitor() {
// Look for echo replies, mark it as received.
if msg.Type == ipv4.ICMPTypeEchoReply {
netMutex.Lock()
pingResponse[ip] = stratuxClock.Time
netMutex.Unlock()
continue // No further processing needed.
}
@ -444,8 +592,58 @@ func networkStatsCounter() {
}
/*
ffMonitor().
Watches for "i-want-to-play-ffm-udp", "i-can-play-ffm-udp", and "i-cannot-play-ffm-udp" UDP messages broadcasted on
port 50113. Tags the client, issues a warning, and disables AHRS GDL90 output.
*/
func ffMonitor() {
addr := net.UDPAddr{Port: 50113, IP: net.ParseIP("0.0.0.0")}
conn, err := net.ListenUDP("udp", &addr)
if err != nil {
log.Printf("ffMonitor(): error listening on port 50113: %s\n", err.Error())
return
}
defer conn.Close()
for {
buf := make([]byte, 1024)
n, addr, err := conn.ReadFrom(buf)
ipAndPort := strings.Split(addr.String(), ":")
ip := ipAndPort[0]
if err != nil {
log.Printf("err: %s\n", err.Error())
return
}
// Got message, check if it's in the correct format.
if n < 3 || buf[0] != 0xFF || buf[1] != 0xFE {
continue
}
s := string(buf[2:n])
s = strings.Replace(s, "\x00", "", -1)
ffIpAndPort := ip + ":4000"
netMutex.Lock()
p, ok := outSockets[ffIpAndPort]
if !ok {
// Can't do anything, the client isn't even technically connected.
netMutex.Unlock()
continue
}
if strings.HasPrefix(s, "i-want-to-play-ffm-udp") || strings.HasPrefix(s, "i-can-play-ffm-udp") || strings.HasPrefix(s, "i-cannot-play-ffm-udp") {
p.FFCrippled = true
//FIXME: AHRS output doesn't need to be disabled globally, just on the ForeFlight client IPs.
addSingleSystemErrorf("ff-warn", "Stratux is not supported by your EFB app. Your EFB app is known to regularly make changes that cause compatibility issues with Stratux. See the README for a list of apps that officially support Stratux.")
}
outSockets[ffIpAndPort] = p
netMutex.Unlock()
}
}
func initNetwork() {
messageQueue = make(chan networkMessage, 1024) // Buffered channel, 1024 messages.
serialOutputChan = make(chan []byte, 1024) // Buffered channel, 1024 GDL90 messages.
networkGDL90Chan = make(chan []byte, 1024)
outSockets = make(map[string]networkConnection)
pingResponse = make(map[string]time.Time)
netMutex = &sync.Mutex{}
@ -454,4 +652,6 @@ func initNetwork() {
go messageQueueSender()
go sleepMonitor()
go networkStatsCounter()
go serialOutWatcher()
go networkOutWatcher()
}

271
main/ping.go 100644
Wyświetl plik

@ -0,0 +1,271 @@
/*
Copyright (c) 2016 uAvionix
Distributable under the terms of The "BSD New" License
that can be found in the LICENSE file, herein included
as part of this header.
ping.go: uAvionix Ping ADS-B monitoring and management.
*/
package main
import (
"bufio"
//"fmt"
"log"
"os"
"strings"
"sync"
//"sync/atomic"
"net"
"os/exec"
"time"
// Using forked version of tarm/serial to force Linux
// instead of posix code, allowing for higher baud rates
"github.com/uavionix/serial"
)
// Ping device data
var pingSerialConfig *serial.Config
var pingSerialPort *serial.Port
var pingWG *sync.WaitGroup
var closeCh chan int
func initPingSerial() bool {
var device string
baudrate := int(2000000)
log.Printf("Configuring Ping ADS-B\n")
if _, err := os.Stat("/dev/ping"); err == nil {
device = "/dev/ping"
} else if _, err := os.Stat("/dev/softrf"); err == nil {
device = "/dev/softrf"
baudrate = int(38400)
} else {
log.Printf("No suitable Ping device found.\n")
return false
}
log.Printf("Using %s for Ping\n", device)
// Open port
// No timeout specified as Ping does not heartbeat
pingSerialConfig = &serial.Config{Name: device, Baud: baudrate}
p, err := serial.OpenPort(pingSerialConfig)
if err != nil {
log.Printf("Error opening serial port: %s\n", err.Error())
return false
}
log.Printf("Ping opened serial port")
// No device configuration is needed, we should be ready
pingSerialPort = p
return true
}
func pingNetworkRepeater() {
defer pingWG.Done()
log.Println("Entered Ping network repeater ...")
cmd := exec.Command("/usr/bin/dump1090", "--net-only")
stdout, _ := cmd.StdoutPipe()
stderr, _ := cmd.StderrPipe()
err := cmd.Start()
if err != nil {
log.Printf("Error executing /usr/bin/dump1090: %s\n", err)
// don't return immediately, use the proper shutdown procedure
shutdownPing = true
for {
select {
case <-closeCh:
return
default:
time.Sleep(1 * time.Second)
}
}
}
log.Println("Executed /usr/bin/dump1090 successfully...")
scanStdout := bufio.NewScanner(stdout)
scanStderr := bufio.NewScanner(stderr)
for {
select {
case <-closeCh:
log.Println("Ping network repeater: shutdown msg received, calling cmd.Process.Kill() ...")
err := cmd.Process.Kill()
if err != nil {
log.Printf("\t couldn't kill dump1090: %s\n", err)
} else {
cmd.Wait()
log.Println("\t kill successful...")
}
return
default:
for scanStdout.Scan() {
m := Dump1090TermMessage{Text: scanStdout.Text(), Source: "stdout"}
logDump1090TermMessage(m)
}
if err := scanStdout.Err(); err != nil {
log.Printf("scanStdout error: %s\n", err)
}
for scanStderr.Scan() {
m := Dump1090TermMessage{Text: scanStderr.Text(), Source: "stderr"}
logDump1090TermMessage(m)
if shutdownES != true {
shutdownES = true
}
}
if err := scanStderr.Err(); err != nil {
log.Printf("scanStderr error: %s\n", err)
}
time.Sleep(1 * time.Second)
}
}
}
var dump1090Connection net.Conn = nil
var connectionError error
func pingNetworkConnection() {
// Send to dump1090 on port 30001
dump1090Addr := "127.0.0.1:30001"
dump1090Connection, connectionError = net.Dial("tcp", dump1090Addr)
// RCB monitor for connection failure and redial
}
func pingSerialReader() {
//defer pingWG.Done()
defer pingSerialPort.Close()
// RCB TODO channel control for terminate
log.Printf("Starting Ping serial reader")
scanner := bufio.NewScanner(pingSerialPort)
for scanner.Scan() && globalStatus.Ping_connected && globalSettings.Ping_Enabled {
s := scanner.Text()
// Trimspace removes newlines as well as whitespace
s = strings.TrimSpace(s)
//logString := fmt.Sprintf("Ping received: %s", s)
//log.Println(logString)
if s[0] == '*' {
// 1090ES report
// Ping appends a signal strength at the end of the message
// e.g. *8DC01C2860C37797E9732E555B23;ss=049D;
// Remove this before forwarding to dump1090
// We currently aren't doing anything with this information
// and need to develop a scaling equation - we're using a
// log detector for power so it should have a logarithmic
// relationship. In one example, at -25dBm input (upper limit
// of RX) we saw ~0x500. At -95dBm input (lower limit of RX)
// we saw 0x370
report := strings.Split(s, ";")
//replayLog(s, MSGCLASS_DUMP1090);
if dump1090Connection == nil {
log.Println("Starting dump1090 network connection")
pingNetworkConnection()
}
if len(report[0]) != 0 && dump1090Connection != nil {
dump1090Connection.Write([]byte(report[0] + ";\r\n"))
//log.Println("Relaying 1090ES message")
//logString := fmt.Sprintf("Relaying 1090ES: %s;", report[0]);
//log.Println(logString)
}
} else if s[0] == '+' || s[0] == '-' {
// UAT report
// Ping appends a signal strength and RS bit errors corrected
// at the end of the message
// e.g. -08A5DFDF3907E982585F029B00040080105C3AB4BC5C240700A206000000000000003A13C82F96C80A63191F05FCB231;rs=1;ss=A2;
// We need to rescale the signal strength for interpretation by dump978,
// which expects a 0-1000 base 10 (linear?) scale
// RSSI is in hex and represents an int8 with -128 (0x80) representing an
// errored measurement. There will be some offset from actual due to loss
// in the path. In one example we measured 0x93 (-98) when injecting a
// -102dBm signal
o, msgtype := parseInput(s)
if o != nil && msgtype != 0 {
//logString = fmt.Sprintf("Relaying message, type=%d", msgtype)
//log.Println(logString)
relayMessage(msgtype, o)
} else if o == nil {
//log.Println("Not relaying message, o == nil")
} else {
//log.Println("Not relaying message, msgtype == 0")
}
}
}
globalStatus.Ping_connected = false
log.Printf("Exiting Ping serial reader")
return
}
func pingShutdown() {
log.Println("Entered Ping shutdown() ...")
//close(closeCh)
//log.Println("Ping shutdown(): calling pingWG.Wait() ...")
//pingWG.Wait() // Wait for the goroutine to shutdown
//log.Println("Ping shutdown(): pingWG.Wait() returned...")
// RCB TODO FINISH
globalStatus.Ping_connected = false
}
func pingKill() {
// Send signal to shutdown to pingWatcher().
shutdownPing = true
// Spin until device has been de-initialized.
for globalStatus.Ping_connected != false {
time.Sleep(1 * time.Second)
}
}
// to keep our sync primitives synchronized, only exit a read
// method's goroutine via the close flag channel check, to
// include catastrophic dongle failures
var shutdownPing bool
// Watch for config/device changes.
func pingWatcher() {
prevPingEnabled := false
for {
time.Sleep(1 * time.Second)
// true when a serial call fails
if shutdownPing {
pingShutdown()
shutdownPing = false
}
if prevPingEnabled == globalSettings.Ping_Enabled {
continue
}
// Global settings have changed, reconfig
if globalSettings.Ping_Enabled && !globalStatus.Ping_connected {
globalStatus.Ping_connected = initPingSerial()
//count := 0
if globalStatus.Ping_connected {
//pingWG.Add(1)
go pingNetworkRepeater()
//pingNetworkConnection()
go pingSerialReader()
// Emulate SDR count
//count = 2
}
//atomic.StoreUint32(&globalStatus.Devices, uint32(count))
} else if !globalSettings.Ping_Enabled {
pingShutdown()
}
prevPingEnabled = globalSettings.Ping_Enabled
}
}
func pingInit() {
go pingWatcher()
}

13
main/plugin.go 100644
Wyświetl plik

@ -0,0 +1,13 @@
package main
import (
"time"
)
type StratuxPlugin struct {
InitFunc func() bool
ShutdownFunc func() bool
Name string
Clock time.Time
Input chan string
}

Plik diff jest za duży Load Diff

Wyświetl plik

@ -1,6 +1,6 @@
/*
Copyright (c) 2015-2016 Christopher Young
Distributable under the terms of The "BSD New"" License
Distributable under the terms of The "BSD New" License
that can be found in the LICENSE file, herein included
as part of this header.
@ -10,7 +10,6 @@
package main
import (
"bufio"
"log"
"os/exec"
"regexp"
@ -18,6 +17,7 @@ import (
"strings"
"sync"
"sync/atomic"
"syscall"
"time"
"../godump978"
@ -47,6 +47,11 @@ var UATDev *UAT
// ESDev holds a 1090 MHz dongle object
var ESDev *ES
type Dump1090TermMessage struct {
Text string
Source string
}
func (e *ES) read() {
defer e.wg.Done()
log.Println("Entered ES read() ...")
@ -71,42 +76,66 @@ func (e *ES) read() {
log.Println("Executed /usr/bin/dump1090 successfully...")
scanStdout := bufio.NewScanner(stdout)
scanStderr := bufio.NewScanner(stderr)
done := make(chan bool)
for {
select {
case <-e.closeCh:
log.Println("ES read(): shutdown msg received, calling cmd.Process.Kill() ...")
err := cmd.Process.Kill()
if err != nil {
log.Printf("\t couldn't kill dump1090: %s\n", err)
} else {
cmd.Wait()
log.Println("\t kill successful...")
}
return
default:
for scanStdout.Scan() {
replayLog(scanStdout.Text(), MSGCLASS_DUMP1090)
}
if err := scanStdout.Err(); err != nil {
log.Printf("scanStdout error: %s\n", err)
go func() {
for {
select {
case <-done:
return
case <-e.closeCh:
log.Println("ES read(): shutdown msg received, calling cmd.Process.Kill() ...")
err := cmd.Process.Kill()
if err == nil {
log.Println("\t kill successful...")
}
return
default:
time.Sleep(1 * time.Second)
}
}
}()
for scanStderr.Scan() {
replayLog(scanStderr.Text(), MSGCLASS_DUMP1090)
if shutdownES != true {
shutdownES = true
stdoutBuf := make([]byte, 1024)
stderrBuf := make([]byte, 1024)
go func() {
for {
select {
case <-done:
return
default:
n, err := stdout.Read(stdoutBuf)
if err == nil && n > 0 {
m := Dump1090TermMessage{Text: string(stdoutBuf[:n]), Source: "stdout"}
logDump1090TermMessage(m)
}
}
if err := scanStderr.Err(); err != nil {
log.Printf("scanStderr error: %s\n", err)
}
time.Sleep(1 * time.Second)
}
}
}()
go func() {
for {
select {
case <-done:
return
default:
n, err := stderr.Read(stderrBuf)
if err == nil && n > 0 {
m := Dump1090TermMessage{Text: string(stderrBuf[:n]), Source: "stderr"}
logDump1090TermMessage(m)
}
}
}
}()
cmd.Wait()
// we get here if A) the dump1090 process died
// on its own or B) cmd.Process.Kill() was called
// from within the goroutine, either way close
// the "done" channel, which ensures we don't leak
// goroutines...
close(done)
}
func (u *UAT) read() {
@ -201,6 +230,9 @@ func (u *UAT) sdrConfig() (err error) {
}
log.Printf("\tSetTunerGain Successful\n")
tgain := u.dev.GetTunerGain()
log.Printf("\tGetTunerGain: %d\n", tgain)
//---------- Get/Set Sample Rate ----------
err = u.dev.SetSampleRate(SampleRate)
if err != nil {
@ -311,6 +343,7 @@ func (u *UAT) shutdown() {
log.Println("UAT shutdown(): u.wg.Wait() returned...")
log.Println("UAT shutdown(): closing device ...")
u.dev.Close() // preempt the blocking ReadSync call
log.Println("UAT shutdown() complete ...")
}
func (e *ES) shutdown() {
@ -318,7 +351,7 @@ func (e *ES) shutdown() {
close(e.closeCh) // signal to shutdown
log.Println("ES shutdown(): calling e.wg.Wait() ...")
e.wg.Wait() // Wait for the goroutine to shutdown
log.Println("ES shutdown(): e.wg.Wait() returned...")
log.Println("ES shutdown() complete ...")
}
var sdrShutdown bool
@ -397,6 +430,8 @@ func configDevices(count int, esEnabled, uatEnabled bool) {
for i := 0; i < count; i++ {
_, _, s, err := rtl.GetDeviceUsbStrings(i)
if err == nil {
//FIXME: Trim NULL from the serial. Best done in gortlsdr, but putting this here for now.
s = strings.Trim(s, "\x00")
// no need to check if createXDev returned an error; if it
// failed to config the error is logged and we can ignore
// it here so it doesn't get queued up again
@ -417,7 +452,7 @@ func configDevices(count int, esEnabled, uatEnabled bool) {
// dongles are set to the same stratux id and the unconsumed,
// non-anonymous, dongle makes it to this loop.
for i, s := range unusedIDs {
if uatEnabled && UATDev == nil && !rES.hasID(s) {
if uatEnabled && !globalStatus.UATRadio_connected && UATDev == nil && !rES.hasID(s) {
createUATDev(i, s, false)
} else if esEnabled && ESDev == nil && !rUAT.hasID(s) {
createESDev(i, s, false)
@ -437,6 +472,21 @@ func sdrWatcher() {
prevUATEnabled := false
prevESEnabled := false
// Get the system (RPi) uptime.
info := syscall.Sysinfo_t{}
err := syscall.Sysinfo(&info)
if err == nil {
// Got system uptime. Delay if and only if the system uptime is less than 120 seconds. This should be plenty of time
// for the RPi to come up and start Stratux. Keeps the delay from happening if the daemon is auto-restarted from systemd.
if info.Uptime < 120 {
time.Sleep(90 * time.Second)
} else if globalSettings.DeveloperMode {
// Throw a "critical error" if developer mode is enabled. Alerts the developer that the daemon was restarted (possibly)
// unexpectedly.
addSingleSystemErrorf("restart-warn", "System uptime %d seconds. Daemon was restarted.\n", info.Uptime)
}
}
for {
time.Sleep(1 * time.Second)
if sdrShutdown {
@ -453,27 +503,37 @@ func sdrWatcher() {
// true when a ReadSync call fails
if shutdownUAT {
UATDev.shutdown()
UATDev = nil
if UATDev != nil {
UATDev.shutdown()
UATDev = nil
}
shutdownUAT = false
}
// true when we get stderr output
if shutdownES {
ESDev.shutdown()
ESDev = nil
if ESDev != nil {
ESDev.shutdown()
ESDev = nil
}
shutdownES = false
}
// capture current state
esEnabled := globalSettings.ES_Enabled
uatEnabled := globalSettings.UAT_Enabled
count := rtl.GetDeviceCount()
atomic.StoreUint32(&globalStatus.Devices, uint32(count))
interfaceCount := count
if globalStatus.UATRadio_connected {
interfaceCount++
}
atomic.StoreUint32(&globalStatus.Devices, uint32(interfaceCount))
// support two and only two dongles
// support up to two dongles
if count > 2 {
count = 2
}
if count == prevCount && prevESEnabled == globalSettings.ES_Enabled &&
prevUATEnabled == globalSettings.UAT_Enabled {
if count == prevCount && prevESEnabled == esEnabled && prevUATEnabled == uatEnabled {
continue
}
@ -486,17 +546,16 @@ func sdrWatcher() {
ESDev.shutdown()
ESDev = nil
}
configDevices(count, globalSettings.ES_Enabled, globalSettings.UAT_Enabled)
configDevices(count, esEnabled, uatEnabled)
prevCount = count
prevUATEnabled = globalSettings.UAT_Enabled
prevESEnabled = globalSettings.ES_Enabled
prevUATEnabled = uatEnabled
prevESEnabled = esEnabled
}
}
func sdrInit() {
go sdrWatcher()
go uatReader()
godump978.Dump978Init()
go godump978.ProcessDataFromChannel()
}

494
main/sensors.go 100644
Wyświetl plik

@ -0,0 +1,494 @@
package main
import (
"fmt"
"log"
"math"
"path/filepath"
"strings"
"time"
"../goflying/ahrs"
"../goflying/ahrsweb"
"../sensors"
"github.com/kidoman/embd"
_ "github.com/kidoman/embd/host/all"
)
const (
numRetries uint8 = 5
calCLimit = 0.15
calDLimit = 10.0
// WHO_AM_I values to differentiate between the different IMUs.
MPUREG_WHO_AM_I = 0x75
MPUREG_WHO_AM_I_VAL = 0x71 // Expected value.
ICMREG_WHO_AM_I = 0x00
ICMREG_WHO_AM_I_VAL = 0xEA // Expected value.
)
var (
i2cbus embd.I2CBus
myPressureReader sensors.PressureReader
myIMUReader sensors.IMUReader
cal chan (string)
analysisLogger *ahrs.AHRSLogger
ahrsCalibrating bool
logMap map[string]interface{}
)
func initI2CSensors() {
i2cbus = embd.NewI2CBus(1)
go pollSensors()
go sensorAttitudeSender()
go updateAHRSStatus()
}
func pollSensors() {
timer := time.NewTicker(4 * time.Second)
for {
<-timer.C
// If it's not currently connected, try connecting to pressure sensor
if globalSettings.BMP_Sensor_Enabled && !globalStatus.BMPConnected {
globalStatus.BMPConnected = initPressureSensor() // I2C temperature and pressure altitude.
go tempAndPressureSender()
}
// If it's not currently connected, try connecting to IMU
if globalSettings.IMU_Sensor_Enabled && !globalStatus.IMUConnected {
globalStatus.IMUConnected = initIMU() // I2C accel/gyro/mag.
}
}
}
func initPressureSensor() (ok bool) {
bmp, err := sensors.NewBMP280(&i2cbus, 100*time.Millisecond)
if err == nil {
myPressureReader = bmp
return true
}
//TODO westphae: make bmp180.go to fit bmp interface
return false
}
func tempAndPressureSender() {
var (
temp float64
press float64
altLast = -9999.9
altitude float64
err error
dt = 0.1
failNum uint8
)
// Initialize variables for rate of climb calc
u := 5 / (5 + float32(dt)) // Use 5 sec decay time for rate of climb, slightly faster than typical VSI
timer := time.NewTicker(time.Duration(1000*dt) * time.Millisecond)
for globalSettings.BMP_Sensor_Enabled && globalStatus.BMPConnected {
<-timer.C
// Read temperature and pressure altitude.
temp, err = myPressureReader.Temperature()
if err != nil {
addSingleSystemErrorf("pressure-sensor-temp-read", "AHRS Error: Couldn't read temperature from sensor: %s", err)
}
press, err = myPressureReader.Pressure()
if err != nil {
addSingleSystemErrorf("pressure-sensor-pressure-read", "AHRS Error: Couldn't read pressure from sensor: %s", err)
failNum++
if failNum > numRetries {
// log.Printf("AHRS Error: Couldn't read pressure from sensor %d times, closing BMP: %s", failNum, err)
myPressureReader.Close()
globalStatus.BMPConnected = false // Try reconnecting a little later
break
}
}
// Update the Situation data.
mySituation.muBaro.Lock()
mySituation.BaroLastMeasurementTime = stratuxClock.Time
mySituation.BaroTemperature = float32(temp)
altitude = CalcAltitude(press)
mySituation.BaroPressureAltitude = float32(altitude)
if altLast < -2000 {
altLast = altitude // Initialize
}
// Assuming timer is reasonably accurate, use a regular ewma
mySituation.BaroVerticalSpeed = u*mySituation.BaroVerticalSpeed + (1-u)*float32(altitude-altLast)/(float32(dt)/60)
mySituation.muBaro.Unlock()
altLast = altitude
}
mySituation.BaroPressureAltitude = 99999
mySituation.BaroVerticalSpeed = 99999
}
func initIMU() (ok bool) {
// Check if the chip is the ICM-20948 or MPU-9250.
v, err := i2cbus.ReadByteFromReg(0x68, ICMREG_WHO_AM_I)
if err != nil {
log.Printf("Error identifying IMU: %s\n", err.Error())
return false
}
v2, err := i2cbus.ReadByteFromReg(0x68, MPUREG_WHO_AM_I)
if err != nil {
log.Printf("Error identifying IMU: %s\n", err.Error())
return false
}
if v == ICMREG_WHO_AM_I_VAL {
log.Println("ICM-20948 detected.")
imu, err := sensors.NewICM20948(&i2cbus)
if err == nil {
myIMUReader = imu
return true
}
} else if v2 == MPUREG_WHO_AM_I_VAL {
log.Println("MPU-9250 detected.")
imu, err := sensors.NewMPU9250(&i2cbus)
if err == nil {
myIMUReader = imu
return true
}
} else {
log.Printf("Could not identify MPU. v=%02x, v2=%02x.\n", v, v2)
return false
}
return false
}
//FIXME: Shoud be moved to managementinterface.go and standardized on management interface port.
func sensorAttitudeSender() {
var (
t time.Time
roll, pitch, heading float64
mpuError, magError error
failNum uint8
)
s := ahrs.NewSimpleAHRS()
m := ahrs.NewMeasurement()
cal = make(chan (string), 1)
// Set up loggers for analysis
ahrswebListener, err := ahrsweb.NewKalmanListener()
if err != nil {
// addSingleSystemErrorf("ahrs-web-start", "AHRS Info: couldn't start ahrswebListener: %s\n", err.Error())
} else {
defer ahrswebListener.Close()
}
// Need a sampling freq faster than 10Hz
timer := time.NewTicker(50 * time.Millisecond) // ~20Hz update.
for {
// Set sensor gyro calibrations
if c, d := &globalSettings.C, &globalSettings.D; d[0]*d[0]+d[1]*d[1]+d[2]*d[2] > 0 {
s.SetCalibrations(c, d)
log.Printf("AHRS Info: IMU Calibrations read from settings: accel %6f %6f %6f; gyro %6f %6f %6f\n",
c[0], c[1], c[2], d[0], d[1], d[2])
} else {
// Do an initial calibration
select { // Don't block if cal isn't receiving: only need one calibration in the queue at a time.
case cal <- "cal":
default:
}
}
// Set sensor quaternion
if f := &globalSettings.SensorQuaternion; f[0]*f[0]+f[1]*f[1]+f[2]*f[2]+f[3]*f[3] > 0 {
s.SetSensorQuaternion(f)
} else {
select { // Don't block if cal isn't receiving: only need one calibration in the queue at a time.
case cal <- "level":
default:
}
}
failNum = 0
<-timer.C
time.Sleep(950 * time.Millisecond)
for globalSettings.IMU_Sensor_Enabled && globalStatus.IMUConnected {
<-timer.C
// Process calibration and level requests
select {
case action := <-cal:
log.Printf("AHRS Info: cal received action %s\n", action)
ahrsCalibrating = true
myIMUReader.Read() // Clear out the averages
var (
nTries uint8
cc, dd float64
)
for (math.Abs(cc-1) > calCLimit || dd > calDLimit) && nTries < numRetries {
time.Sleep(1 * time.Second)
_, d1, d2, d3, c1, c2, c3, _, _, _, mpuError, _ := myIMUReader.Read()
cc = math.Sqrt(c1*c1 + c2*c2 + c3*c3)
dd = math.Sqrt(d1*d1 + d2*d2 + d3*d3)
nTries++
log.Printf("AHRS Info: IMU calibration attempt #%d\n", nTries)
if mpuError != nil {
log.Printf("AHRS Info: Error reading IMU while calibrating: %s\n", mpuError)
} else {
if strings.Contains(action, "cal") { // Calibrate gyros
globalSettings.D = [3]float64{d1, d2, d3}
s.SetCalibrations(nil, &globalSettings.D)
log.Printf("AHRS Info: IMU gyro calibration: %3f %3f %3f\n", d1, d2, d3)
}
if strings.Contains(action, "level") { // Calibrate accel / level
globalSettings.C = [3]float64{c1, c2, c3}
s.SetCalibrations(&globalSettings.C, nil)
globalSettings.SensorQuaternion = *makeOrientationQuaternion(globalSettings.C)
s.SetSensorQuaternion(&globalSettings.SensorQuaternion)
s.Reset()
log.Printf("AHRS Info: IMU accel calibration: %3f %3f %3f\n", c1, c2, c3)
log.Printf("AHRS Info: Caged to quaternion %v\n", globalSettings.SensorQuaternion)
}
saveSettings()
}
}
ahrsCalibrating = false
<-timer.C // Make sure we get data for the actual algorithm
default:
}
// Make the IMU sensor measurements.
t = stratuxClock.Time
m.T = float64(t.UnixNano()/1000) / 1e6
_, m.B1, m.B2, m.B3, m.A1, m.A2, m.A3, m.M1, m.M2, m.M3, mpuError, magError = myIMUReader.Read()
m.SValid = mpuError == nil
m.MValid = magError == nil
if mpuError != nil {
log.Printf("AHRS Gyro/Accel Error: %s\n", mpuError)
failNum++
if failNum > numRetries {
log.Printf("AHRS Gyro/Accel Error: failed to read %d times, restarting: %s\n",
failNum-1, mpuError)
myIMUReader.Close()
globalStatus.IMUConnected = false
}
continue
}
failNum = 0
if magError != nil {
if globalSettings.DEBUG {
log.Printf("AHRS Magnetometer Error, not using for this run: %s\n", magError)
}
m.MValid = false
}
// Make the GPS measurements.
m.TW = float64(mySituation.GPSLastGroundTrackTime.UnixNano()/1000) / 1e6
m.WValid = isGPSGroundTrackValid()
if m.WValid {
m.W1 = mySituation.GPSGroundSpeed * math.Sin(float64(mySituation.GPSTrueCourse)*ahrs.Deg)
m.W2 = mySituation.GPSGroundSpeed * math.Cos(float64(mySituation.GPSTrueCourse)*ahrs.Deg)
if globalSettings.BMP_Sensor_Enabled && globalStatus.BMPConnected {
m.W3 = float64(mySituation.BaroVerticalSpeed * 60 / 6076.12)
} else {
m.W3 = float64(mySituation.GPSVerticalSpeed) * 3600 / 6076.12
}
}
// Run the AHRS calculations.
s.Compute(m)
// If we have valid AHRS info, then update mySituation.
mySituation.muAttitude.Lock()
if s.Valid() {
roll, pitch, heading = s.RollPitchHeading()
mySituation.AHRSRoll = roll / ahrs.Deg
mySituation.AHRSPitch = pitch / ahrs.Deg
mySituation.AHRSGyroHeading = heading
if !isAHRSInvalidValue(heading) {
mySituation.AHRSGyroHeading /= ahrs.Deg
}
//TODO westphae: until magnetometer calibration is performed, no mag heading
mySituation.AHRSMagHeading = ahrs.Invalid
mySituation.AHRSSlipSkid = s.SlipSkid()
mySituation.AHRSTurnRate = s.RateOfTurn()
mySituation.AHRSGLoad = s.GLoad()
if mySituation.AHRSGLoad < mySituation.AHRSGLoadMin || mySituation.AHRSGLoadMin == 0 {
mySituation.AHRSGLoadMin = mySituation.AHRSGLoad
}
if mySituation.AHRSGLoad > mySituation.AHRSGLoadMax {
mySituation.AHRSGLoadMax = mySituation.AHRSGLoad
}
mySituation.AHRSLastAttitudeTime = t
} else {
mySituation.AHRSRoll = ahrs.Invalid
mySituation.AHRSPitch = ahrs.Invalid
mySituation.AHRSGyroHeading = ahrs.Invalid
mySituation.AHRSMagHeading = ahrs.Invalid
mySituation.AHRSSlipSkid = ahrs.Invalid
mySituation.AHRSTurnRate = ahrs.Invalid
mySituation.AHRSGLoad = ahrs.Invalid
mySituation.AHRSGLoadMin = ahrs.Invalid
mySituation.AHRSGLoadMax = 0
mySituation.AHRSLastAttitudeTime = time.Time{}
s.Reset()
}
mySituation.muAttitude.Unlock()
makeAHRSGDL90Report() // Send whether or not valid - the function will invalidate the values as appropriate
// Send to AHRS debugging server.
if ahrswebListener != nil {
if err = ahrswebListener.Send(s.GetState(), m); err != nil {
log.Printf("AHRS Error: couldn't write to ahrsweb: %s\n", err)
ahrswebListener = nil
}
}
// Log it to csv for later analysis.
if globalSettings.AHRSLog && usage.Usage() < 0.95 {
if analysisLogger == nil {
analysisFilename := fmt.Sprintf("sensors_%s.csv", time.Now().Format("20060102_150405"))
logMap = s.GetLogMap()
updateExtraLogging()
analysisLogger = ahrs.NewAHRSLogger(filepath.Join(logDirf, analysisFilename), logMap)
}
if analysisLogger != nil {
updateExtraLogging()
analysisLogger.Log()
}
} else {
analysisLogger = nil
}
}
}
}
func updateExtraLogging() {
logMap["GPSNACp"] = float64(mySituation.GPSNACp)
logMap["GPSTrueCourse"] = mySituation.GPSTrueCourse
logMap["GPSVerticalAccuracy"] = mySituation.GPSVerticalAccuracy
logMap["GPSHorizontalAccuracy"] = mySituation.GPSHorizontalAccuracy
logMap["GPSAltitudeMSL"] = mySituation.GPSAltitudeMSL
logMap["GPSFixQuality"] = float64(mySituation.GPSFixQuality)
logMap["BaroPressureAltitude"] = float64(mySituation.BaroPressureAltitude)
logMap["BaroVerticalSpeed"] = float64(mySituation.BaroVerticalSpeed)
}
func makeOrientationQuaternion(g [3]float64) (f *[4]float64) {
if globalSettings.IMUMapping[0] == 0 { // if unset, default to some standard orientation
globalSettings.IMUMapping[0] = -1 // +2 for RY836AI
}
// This is the "forward direction" chosen during the orientation process.
var x *[3]float64 = new([3]float64)
if globalSettings.IMUMapping[0] < 0 {
x[-globalSettings.IMUMapping[0]-1] = -1
} else {
x[+globalSettings.IMUMapping[0]-1] = +1
}
// Normalize the gravity vector to be 1 G.
z, _ := ahrs.MakeUnitVector(g)
rotmat, _ := ahrs.MakeHardSoftRotationMatrix(*z, *x, [3]float64{0, 0, 1}, [3]float64{1, 0, 0})
f = new([4]float64)
f[0], f[1], f[2], f[3] = ahrs.RotationMatrixToQuaternion(*rotmat)
return
}
// This is used in the orientation process where the user specifies the forward and up directions.
func getMinAccelDirection() (i int, err error) {
_, _, _, _, a1, a2, a3, _, _, _, err, _ := myIMUReader.ReadOne()
if err != nil {
return
}
log.Printf("AHRS Info: sensor orientation accels %1.3f %1.3f %1.3f\n", a1, a2, a3)
switch {
case math.Abs(a1) > math.Abs(a2) && math.Abs(a1) > math.Abs(a3):
if a1 > 0 {
i = 1
} else {
i = -1
}
case math.Abs(a2) > math.Abs(a3) && math.Abs(a2) > math.Abs(a1):
if a2 > 0 {
i = 2
} else {
i = -2
}
case math.Abs(a3) > math.Abs(a1) && math.Abs(a3) > math.Abs(a2):
if a3 > 0 {
i = 3
} else {
i = -3
}
default:
err = fmt.Errorf("couldn't determine biggest accel from %1.3f %1.3f %1.3f", a1, a2, a3)
}
return
}
// CageAHRS sends a signal to the AHRSProvider that it should recalibrate and reset its level orientation.
func CageAHRS() {
cal <- "level"
}
// CageAHRS sends a signal to the AHRSProvider that it should recalibrate and reset its level orientation.
func CalibrateAHRS() {
cal <- "cal"
}
// ResetAHRSGLoad resets the min and max to the current G load value.
func ResetAHRSGLoad() {
mySituation.AHRSGLoadMax = mySituation.AHRSGLoad
mySituation.AHRSGLoadMin = mySituation.AHRSGLoad
}
func updateAHRSStatus() {
var (
msg uint8
imu bool
ticker *time.Ticker
)
ticker = time.NewTicker(250 * time.Millisecond)
for {
<-ticker.C
msg = 0
// GPS ground track valid?
if isGPSGroundTrackValid() {
msg++
}
// IMU is being used
imu = globalSettings.IMU_Sensor_Enabled && globalStatus.IMUConnected
if imu {
msg += 1 << 1
}
// BMP is being used
if globalSettings.BMP_Sensor_Enabled && globalStatus.BMPConnected {
msg += 1 << 2
}
// IMU is doing a calibration
if ahrsCalibrating {
msg += 1 << 3
}
// Logging to csv
if imu && analysisLogger != nil {
msg += 1 << 4
}
mySituation.AHRSStatus = msg
}
}
func isAHRSInvalidValue(val float64) bool {
return math.Abs(val-ahrs.Invalid) < 0.01
}

Wyświetl plik

@ -1,6 +1,6 @@
/*
Copyright (c) 2015-2016 Christopher Young
Distributable under the terms of The "BSD New"" License
Distributable under the terms of The "BSD New" License
that can be found in the LICENSE file, herein included
as part of this header.
@ -13,10 +13,11 @@ import (
"bufio"
"encoding/hex"
"encoding/json"
"fmt"
"log"
"math"
"net"
//"strconv"
"strconv"
"strings"
"sync"
"time"
@ -75,13 +76,15 @@ const (
type TrafficInfo struct {
Icao_addr uint32
Tail string
Reg string // Registration. Calculated from Icao_addr for civil aircraft of US registry.
Tail string // Callsign. Transmitted by aircraft.
Emitter_category uint8 // Formatted using GDL90 standard, e.g. in a Mode ES report, A7 becomes 0x07, B0 becomes 0x08, etc.
OnGround bool // Air-ground status. On-ground is "true".
Addr_type uint8 // UAT address qualifier. Used by GDL90 format, so translations for ES TIS-B/ADS-R are needed.
TargetType uint8 // types decribed in const above
SignalLevel float64 // Signal level, dB RSSI.
Position_valid bool // set when position report received. Unset after n seconds? (To-do)
Squawk int // Squawk code
Position_valid bool //TODO: set when position report received. Unset after n seconds?
Lat float32 // decimal degrees, north positive
Lng float32 // decimal degrees, east positive
Alt int32 // Pressure altitude, feet
@ -94,20 +97,24 @@ type TrafficInfo struct {
Speed_valid bool // set when speed report received.
Vvel int16 // feet per minute
Timestamp time.Time // timestamp of traffic message, UTC
PriorityStatus uint8 // Emergency or priority code as defined in GDL90 spec, DO-260B (Type 28 msg) and DO-282B
// Parameters starting at 'Age' are calculated after message receipt.
// Parameters starting at 'Age' are calculated from last message receipt on each call of sendTrafficUpdates().
// Mode S transmits position and track in separate messages, and altitude can also be
// received from interrogations.
Age float64 // seconds ago traffic last seen
Last_seen time.Time // time of last position update, relative to Stratux startup. Used for timing out expired data.
Last_alt time.Time // time of last altitude update, relative to Stratux startup
Last_GnssDiff time.Time // time of last GnssDiffFromBaroAlt update, relative to Stratux startup
Last_GnssDiffAlt int32 // altitude at last GnssDiffFromBaroAlt update
Last_speed time.Time // time of last velocity / track update, relative to Stratux startup
Last_source uint8 // last SDR on which this target was observed
ExtrapolatedPosition bool // TO-DO: True if Stratux is "coasting" the target from last known position.
Bearing float64 // TO-DO: Bearing in degrees true to traffic from ownship
Distance float64 // TO-DO: Distance to traffic from ownship
Age float64 // Age of last valid position fix, seconds ago.
AgeLastAlt float64 // Age of last altitude message, seconds ago.
Last_seen time.Time // Time of last position update (stratuxClock). Used for timing out expired data.
Last_alt time.Time // Time of last altitude update (stratuxClock).
Last_GnssDiff time.Time // Time of last GnssDiffFromBaroAlt update (stratuxClock).
Last_GnssDiffAlt int32 // Altitude at last GnssDiffFromBaroAlt update.
Last_speed time.Time // Time of last velocity and track update (stratuxClock).
Last_source uint8 // Last frequency on which this target was received.
ExtrapolatedPosition bool //TODO: True if Stratux is "coasting" the target from last known position.
BearingDist_valid bool // set when bearing and distance information is valid
Bearing float64 // Bearing in degrees true to traffic from ownship, if it can be calculated. Units: degrees.
Distance float64 // Distance to traffic from ownship, if it can be calculated. Units: meters.
//FIXME: Rename variables for consistency, especially "Last_".
}
type dump1090Data struct {
@ -136,10 +143,17 @@ type dump1090Data struct {
Timestamp time.Time // time traffic last seen, UTC
}
type esmsg struct {
TimeReceived time.Time
Data string
}
var traffic map[uint32]TrafficInfo
var trafficMutex *sync.Mutex
var seenTraffic map[uint32]bool // Historical list of all ICAO addresses seen.
var OwnshipTrafficInfo TrafficInfo
func cleanupOldEntries() {
for icao_addr, ti := range traffic {
if stratuxClock.Since(ti.Last_seen) > 60*time.Second { // keep it in the database for up to 60 seconds, so we don't lose tail number, etc...
@ -152,12 +166,39 @@ func sendTrafficUpdates() {
trafficMutex.Lock()
defer trafficMutex.Unlock()
cleanupOldEntries()
var msg []byte
// Summarize number of UAT and 1090ES traffic targets for reports that follow.
globalStatus.UAT_traffic_targets_tracking = 0
globalStatus.ES_traffic_targets_tracking = 0
for _, traf := range traffic {
switch traf.Last_source {
case TRAFFIC_SOURCE_1090ES:
globalStatus.ES_traffic_targets_tracking++
case TRAFFIC_SOURCE_UAT:
globalStatus.UAT_traffic_targets_tracking++
}
}
msgs := make([][]byte, 1)
if globalSettings.DEBUG && (stratuxClock.Time.Second()%15) == 0 {
log.Printf("List of all aircraft being tracked:\n")
log.Printf("==================================================================\n")
}
for icao, ti := range traffic { // TO-DO: Limit number of aircraft in traffic message. ForeFlight 7.5 chokes at ~1000-2000 messages depending on iDevice RAM. Practical limit likely around ~500 aircraft without filtering.
code, _ := strconv.ParseInt(globalSettings.OwnshipModeS, 16, 32)
for icao, ti := range traffic { // ForeFlight 7.5 chokes at ~1000-2000 messages depending on iDevice RAM. Practical limit likely around ~500 aircraft without filtering.
if isGPSValid() {
// func distRect(lat1, lon1, lat2, lon2 float64) (dist, bearing, distN, distE float64) {
dist, bearing := distance(float64(mySituation.GPSLatitude), float64(mySituation.GPSLongitude), float64(ti.Lat), float64(ti.Lng))
ti.Distance = dist
ti.Bearing = bearing
ti.BearingDist_valid = true
} else {
ti.Distance = 0
ti.Bearing = 0
ti.BearingDist_valid = false
}
ti.Age = stratuxClock.Since(ti.Last_seen).Seconds()
ti.AgeLastAlt = stratuxClock.Since(ti.Last_alt).Seconds()
// DEBUG: Print the list of all tracked targets (with data) to the log every 15 seconds if "DEBUG" option is enabled
if globalSettings.DEBUG && (stratuxClock.Time.Second()%15) == 0 {
@ -169,31 +210,65 @@ func sendTrafficUpdates() {
}
// end of debug block
}
ti.Age = stratuxClock.Since(ti.Last_seen).Seconds()
traffic[icao] = ti
traffic[icao] = ti // write the updated ti back to the map
//log.Printf("Traffic age of %X is %f seconds\n",icao,ti.Age)
if ti.Age > 2 { // if nothing polls an inactive ti, it won't push to the webUI, and its Age won't update.
tiJSON, _ := json.Marshal(&ti)
trafficUpdate.Send(tiJSON)
trafficUpdate.SendJSON(ti)
}
if ti.Position_valid && ti.Age < 6 { // ... but don't pass stale data to the EFB. TO-DO: Coast old traffic? Need to determine how FF, WingX, etc deal with stale targets.
msg = append(msg, makeTrafficReportMsg(ti)...)
if ti.Position_valid && ti.Age < 6 { // ... but don't pass stale data to the EFB.
//TODO: Coast old traffic? Need to determine how FF, WingX, etc deal with stale targets.
logTraffic(ti) // only add to the SQLite log if it's not stale
if ti.Icao_addr == uint32(code) {
if globalSettings.DEBUG {
log.Printf("Ownship target detected for code %X\n", code)
}
OwnshipTrafficInfo = ti
} else {
cur_n := len(msgs) - 1
if len(msgs[cur_n]) >= 35 {
// Batch messages into packets with at most 35 traffic reports
// to keep each packet under 1KB.
cur_n++
msgs = append(msgs, make([]byte, 0))
}
msgs[cur_n] = append(msgs[cur_n], makeTrafficReportMsg(ti)...)
}
}
}
if len(msg) > 0 {
sendGDL90(msg, false)
for i := 0; i < len(msgs); i++ {
msg := msgs[i]
if len(msg) > 0 {
sendGDL90(msg, false)
}
}
}
// Send update to attached JSON client.
func registerTrafficUpdate(ti TrafficInfo) {
if !ti.Position_valid { // Don't send unless a valid position exists.
return
//logTraffic(ti) // moved to sendTrafficUpdates() to reduce SQLite log size
/*
if !ti.Position_valid { // Don't send unless a valid position exists.
return
}
*/ // Send all traffic to the websocket and let JS sort it out. This will provide user indication of why they see 1000 ES messages and no traffic.
trafficUpdate.SendJSON(ti)
}
func isTrafficAlertable(ti TrafficInfo) bool {
// Set alert bit if possible and traffic is within some threshold
// TODO: Could be more intelligent, taking into account headings etc.
if !ti.BearingDist_valid {
// If not able to calculate the distance to the target, let the alert bit be set always.
return true
}
if ti.BearingDist_valid &&
ti.Distance < 3704 { // 3704 meters, 2 nm.
return true
}
tiJSON, _ := json.Marshal(&ti)
trafficUpdate.Send(tiJSON)
return false
}
func makeTrafficReportMsg(ti TrafficInfo) []byte {
@ -201,7 +276,14 @@ func makeTrafficReportMsg(ti TrafficInfo) []byte {
// See p.16.
msg[0] = 0x14 // Message type "Traffic Report".
msg[1] = 0x10 | ti.Addr_type // Alert status, address type.
// Address type
msg[1] = ti.Addr_type
// Set alert if needed
if isTrafficAlertable(ti) {
// Set the alert bit. See pg. 18 of GDL90 ICD
msg[1] |= 0x10
}
// ICAO Address.
msg[2] = byte((ti.Icao_addr & 0x00FF0000) >> 16)
@ -288,15 +370,23 @@ func makeTrafficReportMsg(ti TrafficInfo) []byte {
// msg[19] to msg[26] are "call sign" (tail).
for i := 0; i < len(ti.Tail) && i < 8; i++ {
c := byte(ti.Tail[i])
if c != 20 && !((c >= 48) && (c <= 57)) && !((c >= 65) && (c <= 90)) && c != 'e' && c != 'u' { // See p.24, FAA ref.
if c != 20 && !((c >= 48) && (c <= 57)) && !((c >= 65) && (c <= 90)) && c != 'e' && c != 'u' && c != 'a' && c != 'r' && c != 't' { // See p.24, FAA ref.
c = byte(20)
}
msg[19+i] = c
}
//msg[27] is priority / emergency status per GDL90 spec (DO260B and DO282B are same codes)
msg[27] = ti.PriorityStatus << 4
return prepareMessage(msg)
}
// parseDownlinkReport decodes a UAT downlink message to extract identity, state vector, and mode status data.
// Decoded data is used to update a TrafficInfo object, keyed to the 24-bit ICAO code contained in the
// downlink message.
// Inputs are a checksum-verified hex string corresponding to the 18 or 34-byte UAT
// message, and an int representing UAT signal amplitude (0-1000).
func parseDownlinkReport(s string, signalLevel int) {
var ti TrafficInfo
@ -321,55 +411,127 @@ func parseDownlinkReport(s string, signalLevel int) {
ti.Last_seen = stratuxClock.Time // need to initialize to current stratuxClock so it doesn't get cut before we have a chance to populate a position message
ti.Icao_addr = icao_addr
ti.ExtrapolatedPosition = false
thisReg, validReg := icao2reg(icao_addr)
if validReg {
ti.Reg = thisReg
ti.Tail = thisReg
}
}
ti.Addr_type = addr_type
// Parse tail number, if available.
if msg_type == 1 || msg_type == 3 { // Need "MS" portion of message.
base40_alphabet := string("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ ..")
tail := ""
var uat_version byte // sent as part of MS element, byte 24
v := (uint16(frame[17]) << 8) | uint16(frame[18])
tail += string(base40_alphabet[(v/40)%40])
tail += string(base40_alphabet[v%40])
v = (uint16(frame[19]) << 8) | uint16(frame[20])
tail += string(base40_alphabet[(v/1600)%40])
tail += string(base40_alphabet[(v/40)%40])
tail += string(base40_alphabet[v%40])
v = (uint16(frame[21]) << 8) | uint16(frame[22])
tail += string(base40_alphabet[(v/1600)%40])
tail += string(base40_alphabet[(v/40)%40])
tail += string(base40_alphabet[v%40])
// Extract parameters from Mode Status elements, if available.
if msg_type == 1 || msg_type == 3 {
tail = strings.Trim(tail, " ")
ti.Tail = tail
}
// Determine UAT message version. This is needed for some capability decoding and is useful for debugging.
uat_version = (frame[23] >> 2) & 0x07
if globalSettings.DEBUG {
// This is a hack to show the source of the traffic in ForeFlight.
if len(ti.Tail) == 0 || (len(ti.Tail) != 0 && len(ti.Tail) < 8 && ti.Tail[0] != 'U') {
ti.Tail = "u" + ti.Tail
// Extract emitter category.
v := (uint16(frame[17]) << 8) | (uint16(frame[18]))
ti.Emitter_category = uint8((v / 1600) % 40)
// Decode callsign or Flight Plan ID (i.e. squawk code)
// If the CSID bit (byte 27, bit 7) is set to 1, all eight characters
// encoded in bytes 18-23 represent callsign.
// If the CSID bit is set to 0, the first four characters encoded in bytes 18-23
// represent the Mode A squawk code.
csid := (frame[26] >> 1) & 0x01
if csid == 1 { // decode as callsign
base40_alphabet := string("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ ..")
tail := ""
v := (uint16(frame[17]) << 8) | uint16(frame[18])
tail += string(base40_alphabet[(v/40)%40])
tail += string(base40_alphabet[v%40])
v = (uint16(frame[19]) << 8) | uint16(frame[20])
tail += string(base40_alphabet[(v/1600)%40])
tail += string(base40_alphabet[(v/40)%40])
tail += string(base40_alphabet[v%40])
v = (uint16(frame[21]) << 8) | uint16(frame[22])
tail += string(base40_alphabet[(v/1600)%40])
tail += string(base40_alphabet[(v/40)%40])
tail += string(base40_alphabet[v%40])
tail = strings.Trim(tail, " ")
ti.Tail = tail
} else if uat_version >= 2 { // decode as Mode 3/A code, if UAT version is at least 2
v := (uint16(frame[17]) << 8) | uint16(frame[18])
squawk_a := (v / 40) % 40
squawk_b := v % 40
v = (uint16(frame[19]) << 8) | uint16(frame[20])
squawk_c := (v / 1600) % 40
squawk_d := (v / 40) % 40
squawk := 1000*squawk_a + 100*squawk_b + 10*squawk_c + squawk_d
ti.Squawk = int(squawk)
}
ti.NACp = int((frame[25] >> 4) & 0x0F)
ti.PriorityStatus = (frame[23] >> 5) & 0x07
// Following section is future-use for debugging and / or additional status info on UAT traffic. Message parsing needs testing.
if globalSettings.DEBUG {
//declaration for mode status flags -- parse for debug logging
var status_sil byte
//var status_transmit_mso byte
var status_sda byte
var status_nacv byte
//var status_nicbaro byte
//var status_sil_supp byte
//var status_geom_vert_acc byte
//var status_sa_flag byte
var capability_uat_in bool
var capability_1090_in bool
//var capability_tcas bool
//var capability_cdti bool
//var opmode_tcas_active bool
//var opmode_ident_active bool
//var opmode_rec_atc_serv bool
// these are present in v1 and v2 messages
status_sil = frame[23] & 0x03
//status_transmit_mso = frame[24] >> 2
status_nacv = (frame[25] >> 1) & 0x07
//status_nicbaro = frame[25] & 0x01
// other status and capability bits are different between v1 and v2
if uat_version == 2 {
status_sda = frame[24] & 0x03
capability_uat_in = (frame[26] >> 7) != 0
capability_1090_in = ((frame[26] >> 6) & 0x01) != 0
//capability_tcas = ((frame[26] >> 5) & 0x01) != 0
//opmode_tcas_active = ((frame[26] >> 4) & 0x01) != 0
//opmode_ident_active = ((frame[26] >> 3) & 0x01) != 0
//opmode_rec_atc_serv = ((frame[26] >> 2) & 0x01) != 0
//status_sil_supp = frame[26] & 0x01
//status_geom_vert_acc = (frame[27] >> 6) & 0x03
//status_sa_flag = (frame[27] >> 5) & 0x01
} else if uat_version == 1 {
//capability_cdti = (frame[26] >> 7) != 0
//capability_tcas = ((frame[26] >> 6) & 0x01) != 0
//opmode_tcas_active = ((frame[26] >> 5) & 0x01) != 0
//opmode_ident_active = ((frame[26] >> 4) & 0x01) != 0
//opmode_rec_atc_serv = ((frame[26] >> 3) & 0x01) != 0
}
log.Printf("Supplemental UAT Mode Status for %06X: Version = %d; SIL = %d; SDA = %d; NACv = %d; 978 In = %v; 1090 In = %v\n", icao_addr, uat_version, status_sil, status_sda, status_nacv, capability_uat_in, capability_1090_in)
}
}
// Extract emitter category.
if msg_type == 1 || msg_type == 3 {
v := (uint16(frame[17]) << 8) | (uint16(frame[18]))
ti.Emitter_category = uint8((v / 1600) % 40)
}
// OK.
// fmt.Printf("%d, %d, %06X\n", msg_type, ti.Addr_type, ti.Icao_addr)
ti.NIC = int(frame[11] & 0x0F)
if (msg_type == 1) || (msg_type == 3) { // Since NACp is passed with normal UATreports, no need to use our ES hack.
ti.NACp = int((frame[25] >> 4) & 0x0F)
var power float64
if signalLevel > 0 {
power = 20 * (math.Log10(float64(signalLevel) / 1000)) // reported amplitude is 0-1000. Normalize to max = 1 and do amplitude dB calculation (20 dB per decade)
} else {
power = -999
}
power := 20 * (math.Log10(float64(signalLevel) / 1000)) // reported amplitude is 0-1000. Normalize to max = 1 and do amplitude dB calculation (20 dB per decade)
//log.Printf("%s (%X) seen with amplitude of %d, corresponding to normalized power of %f.2 dB\n",ti.Tail,ti.Icao_addr,signalLevel,power)
ti.SignalLevel = power
@ -387,6 +549,28 @@ func parseDownlinkReport(s string, signalLevel int) {
}
}
// This is a hack to show the source of the traffic on moving maps.
if globalSettings.DisplayTrafficSource {
type_code := " "
switch ti.TargetType {
case TARGET_TYPE_ADSB:
type_code = "a"
case TARGET_TYPE_ADSR, TARGET_TYPE_TISB_S:
type_code = "r"
case TARGET_TYPE_TISB:
type_code = "t"
}
if len(ti.Tail) == 0 {
ti.Tail = "u" + type_code
} else if len(ti.Tail) < 7 && ti.Tail[0] != 'e' && ti.Tail[0] != 'u' {
ti.Tail = "u" + type_code + ti.Tail
} else if len(ti.Tail) == 7 && ti.Tail[0] != 'e' && ti.Tail[0] != 'u' {
ti.Tail = "u" + type_code + ti.Tail[1:]
} else if len(ti.Tail) > 1 { // bounds checking
ti.Tail = "u" + type_code + ti.Tail[2:]
}
}
raw_lat := (uint32(frame[4]) << 15) | (uint32(frame[5]) << 7) | (uint32(frame[6]) >> 1)
raw_lon := ((uint32(frame[6]) & 0x01) << 23) | (uint32(frame[7]) << 15) | (uint32(frame[8]) << 7) | (uint32(frame[9]) >> 1)
@ -405,10 +589,13 @@ func parseDownlinkReport(s string, signalLevel int) {
lng = lng - 360
}
}
ti.Lat = lat
ti.Lng = lng
ti.Position_valid = position_valid
if ti.Position_valid {
ti.Lat = lat
ti.Lng = lng
if isGPSValid() {
ti.Distance, ti.Bearing = distance(float64(mySituation.GPSLatitude), float64(mySituation.GPSLongitude), float64(ti.Lat), float64(ti.Lng))
}
ti.Last_seen = stratuxClock.Time
ti.ExtrapolatedPosition = false
}
@ -467,7 +654,7 @@ func parseDownlinkReport(s string, signalLevel int) {
}
}
if ns_vel_valid && ew_vel_valid {
if ns_vel != 0 && ew_vel != 0 {
if ns_vel != 0 || ew_vel != 0 {
//TODO: Track type
track = uint16((360 + 90 - (int16(math.Atan2(float64(ns_vel), float64(ew_vel)) * 180 / math.Pi))) % 360)
}
@ -500,6 +687,26 @@ func parseDownlinkReport(s string, signalLevel int) {
// Dimensions of vehicle - skip.
}
if msg_type == 1 || msg_type == 2 || msg_type == 5 || msg_type == 6 {
// Read AUXSV.
raw_alt := (int32(frame[29]) << 4) | ((int32(frame[30]) & 0xf0) >> 4)
if raw_alt != 0 {
alt := ((raw_alt - 1) * 25) - 1000
if ti.AltIsGNSS {
// Current ti.Alt is GNSS. Swap it for the AUXSV alt, which is baro.
baro_alt := ti.Alt
ti.Alt = alt
alt = baro_alt
ti.AltIsGNSS = false
}
ti.GnssDiffFromBaroAlt = alt - ti.Alt
ti.Last_GnssDiff = stratuxClock.Time
ti.Last_GnssDiffAlt = ti.Alt
}
}
ti.Track = track
ti.Speed = speed
ti.Vvel = vvel
@ -508,7 +715,6 @@ func parseDownlinkReport(s string, signalLevel int) {
ti.Last_speed = stratuxClock.Time
}
//OK.
// fmt.Printf("ns_vel %d, ew_vel %d, track %d, speed_valid %t, speed %d, vvel_geo %t, vvel %d\n", ns_vel, ew_vel, track, speed_valid, speed, vvel_geo, vvel)
/*
@ -522,7 +728,6 @@ func parseDownlinkReport(s string, signalLevel int) {
}
*/
//OK.
// fmt.Printf("tisb_site_id %d, utc_coupled %t\n", tisb_site_id, utc_coupled)
ti.Timestamp = time.Now()
@ -536,7 +741,7 @@ func parseDownlinkReport(s string, signalLevel int) {
func esListen() {
for {
if !globalSettings.ES_Enabled {
if !globalSettings.ES_Enabled && !globalSettings.Ping_Enabled {
time.Sleep(1 * time.Second) // Don't do much unless ES is actually enabled.
continue
}
@ -547,7 +752,7 @@ func esListen() {
continue
}
rdr := bufio.NewReader(inConn)
for globalSettings.ES_Enabled {
for globalSettings.ES_Enabled || globalSettings.Ping_Enabled {
//log.Printf("ES enabled. Ready to read next message from dump1090\n")
buf, err := rdr.ReadString('\n')
//log.Printf("String read from dump1090\n")
@ -555,8 +760,18 @@ func esListen() {
break
}
buf = strings.Trim(buf, "\r\n")
//log.Printf("%s\n", buf)
replayLog(buf, MSGCLASS_ES) // Log the raw message to nnnn-ES.log
// Log the message to the message counter in any case.
var thisMsg msg
thisMsg.MessageClass = MSGCLASS_ES
thisMsg.TimeReceived = stratuxClock.Time
thisMsg.Data = buf
MsgLog = append(MsgLog, thisMsg)
var eslog esmsg
eslog.TimeReceived = stratuxClock.Time
eslog.Data = buf
logESMsg(eslog) // log raw dump1090:30006 output to SQLite log
var newTi *dump1090Data
err = json.Unmarshal([]byte(buf), &newTi)
@ -565,18 +780,19 @@ func esListen() {
continue
}
if (newTi.Icao_addr & 0xFF000000) != 0 { //24-bit overflow is used to signal heartbeat
log.Printf("No traffic last 60 seconds. Heartbeat message from dump1090: %s\n", buf)
continue
if newTi.Icao_addr == 0x07FFFFFF { // used to signal heartbeat
if globalSettings.DEBUG {
log.Printf("No traffic last 60 seconds. Heartbeat message from dump1090: %s\n", buf)
}
continue // don't process heartbeat messages
}
// Log the message to the message counter as a valid ES if it unmarshalles.
var thisMsg msg
thisMsg.MessageClass = MSGCLASS_ES
thisMsg.TimeReceived = stratuxClock.Time
thisMsg.Data = []byte(buf)
MsgLog = append(MsgLog, thisMsg)
if (newTi.Icao_addr & 0x01000000) != 0 { // bit 25 used by dump1090 to signal non-ICAO address
newTi.Icao_addr = newTi.Icao_addr & 0x00FFFFFF
if globalSettings.DEBUG {
log.Printf("Non-ICAO address %X sent by dump1090. This is typical for TIS-B.\n", newTi.Icao_addr)
}
}
icao := uint32(newTi.Icao_addr)
var ti TrafficInfo
@ -589,14 +805,26 @@ func esListen() {
} else {
//log.Printf("New target %X created for ES update\n",newTi.Icao_addr)
ti.Last_seen = stratuxClock.Time // need to initialize to current stratuxClock so it doesn't get cut before we have a chance to populate a position message
ti.Last_alt = stratuxClock.Time // ditto.
ti.Icao_addr = icao
ti.ExtrapolatedPosition = false
ti.Last_source = TRAFFIC_SOURCE_1090ES
thisReg, validReg := icao2reg(icao)
if validReg {
ti.Reg = thisReg
ti.Tail = thisReg
}
}
ti.SignalLevel = 10 * math.Log10(newTi.SignalLevel)
if newTi.SignalLevel > 0 {
ti.SignalLevel = 10 * math.Log10(newTi.SignalLevel)
} else {
ti.SignalLevel = -999
}
// generate human readable summary of message types for debug
// TO-DO: Use for ES message statistics?
//TODO: Use for ES message statistics?
/*
var s1 string
if newTi.DF == 17 {
@ -666,6 +894,10 @@ func esListen() {
if valid_position {
ti.Lat = lat
ti.Lng = lng
if isGPSValid() {
ti.Distance, ti.Bearing = distance(float64(mySituation.GPSLatitude), float64(mySituation.GPSLongitude), float64(ti.Lat), float64(ti.Lng))
ti.BearingDist_valid = true
}
ti.Position_valid = true
ti.ExtrapolatedPosition = false
ti.Last_seen = stratuxClock.Time // only update "last seen" data on position updates
@ -754,6 +986,9 @@ func esListen() {
ti.Emitter_category = uint8(*newTi.Emitter_category) // validate dump1090 on live traffic
}
if newTi.Squawk != nil {
ti.Squawk = int(*newTi.Squawk) // only provided by Mode S messages, so we don't do this in parseUAT.
}
// Set the target type. DF=18 messages are sent by ground station, so we look at CA
// (repurposed to Control Field in DF18) to determine if it's ADS-R or TIS-B.
if newTi.DF == 17 {
@ -776,19 +1011,41 @@ func esListen() {
ti.OnGround = bool(*newTi.OnGround)
}
if newTi.Tail != nil { // DF=17 or DF=18, Type Code 1-4
if (newTi.Tail != nil) && ((newTi.DF == 17) || (newTi.DF == 18)) { // DF=17 or DF=18, Type Code 1-4
ti.Tail = *newTi.Tail
// This is a hack to show the source of the traffic in ForeFlight.
ti.Tail = strings.Trim(ti.Tail, " ")
if globalSettings.DEBUG {
if len(ti.Tail) == 0 || (len(ti.Tail) != 0 && len(ti.Tail) < 8 && ti.Tail[0] != 'E') {
ti.Tail = "e" + ti.Tail
}
ti.Tail = strings.Trim(ti.Tail, " ") // remove extraneous spaces
}
// This is a hack to show the source of the traffic on moving maps.
if globalSettings.DisplayTrafficSource {
type_code := " "
switch ti.TargetType {
case TARGET_TYPE_ADSB:
type_code = "a"
case TARGET_TYPE_ADSR:
type_code = "r"
case TARGET_TYPE_TISB:
type_code = "t"
}
if len(ti.Tail) == 0 {
ti.Tail = "e" + type_code
} else if len(ti.Tail) < 7 && ti.Tail[0] != 'e' && ti.Tail[0] != 'u' {
ti.Tail = "e" + type_code + ti.Tail
} else if len(ti.Tail) == 7 && ti.Tail[0] != 'e' && ti.Tail[0] != 'u' {
ti.Tail = "e" + type_code + ti.Tail[1:]
} else if len(ti.Tail) > 1 { // bounds checking
ti.Tail = "e" + type_code + ti.Tail[2:]
}
}
if newTi.DF == 17 || newTi.DF == 18 {
ti.Last_source = TRAFFIC_SOURCE_1090ES // only update traffic source on ADS-B messages. Prevents source on UAT ADS-B targets with Mode S transponders from "flickering" every time we get an altitude or DF11 update.
}
ti.Timestamp = newTi.Timestamp // only update "last seen" data on position updates
ti.Last_source = TRAFFIC_SOURCE_1090ES
/*
s_out, err := json.Marshal(ti)
if err != nil {
@ -824,6 +1081,16 @@ and speed invalid flag is set for headings 135-150 to allow testing of response
func updateDemoTraffic(icao uint32, tail string, relAlt float32, gs float64, offset int32) {
var ti TrafficInfo
// Retrieve previous information on this ICAO code.
if val, ok := traffic[icao]; ok { // if we've already seen it, copy it in to do updates
ti = val
//log.Printf("Existing target %X imported for ES update\n", icao)
} else {
//log.Printf("New target %X created for ES update\n",newTi.Icao_addr)
ti.Last_seen = stratuxClock.Time // need to initialize to current stratuxClock so it doesn't get cut before we have a chance to populate a position message
ti.Icao_addr = icao
ti.ExtrapolatedPosition = false
}
hdg := float64((int32(stratuxClock.Milliseconds/1000)+offset)%720) / 2
// gs := float64(220) // knots
radius := gs * 0.2 / (2 * math.Pi)
@ -833,8 +1100,8 @@ func updateDemoTraffic(icao uint32, tail string, relAlt float32, gs float64, off
lat := 43.99
lng := -88.56
if isGPSValid() {
lat = float64(mySituation.Lat)
lng = float64(mySituation.Lng)
lat = float64(mySituation.GPSLatitude)
lng = float64(mySituation.GPSLongitude)
}
traffRelLat := y / 60
traffRelLng := -x / (60 * math.Cos(lat*math.Pi/180.0))
@ -862,9 +1129,13 @@ func updateDemoTraffic(icao uint32, tail string, relAlt float32, gs float64, off
ti.Emitter_category = 1
ti.Lat = float32(lat + traffRelLat)
ti.Lng = float32(lng + traffRelLng)
ti.Distance, ti.Bearing = distance(float64(lat), float64(lng), float64(ti.Lat), float64(ti.Lng))
ti.BearingDist_valid = true
ti.Position_valid = true
ti.ExtrapolatedPosition = false
ti.Alt = int32(mySituation.Alt + relAlt)
ti.Alt = int32(mySituation.GPSAltitudeMSL + relAlt)
ti.Track = uint16(hdg)
ti.Speed = uint16(gs)
if hdg >= 240 && hdg < 270 {
@ -900,6 +1171,174 @@ func updateDemoTraffic(icao uint32, tail string, relAlt float32, gs float64, off
}
}
/*
icao2reg() : Converts 24-bit Mode S addresses to N-numbers and C-numbers.
Input: uint32 representing the Mode S address. Valid range for
translation is 0xA00001 - 0xADF7C7, inclusive.
Values outside the range A000001-AFFFFFF or C00001-C3FFFF
are flagged as foreign.
Values between ADF7C8 - AFFFFF are allocated to the United States,
but are not used for aicraft on the civil registry. These could be
military, other public aircraft, or future use.
Values between C0CDF9 - C3FFFF are allocated to Canada,
but are not used for aicraft on the civil registry. These could be
military, other public aircraft, or future use.
Values between 7C0000 - 7FFFFF are allocated to Australia.
Output:
string: String containing the decoded tail number (if decoding succeeded),
"NON-NA" (for non-US / non Canada allocation), and "US-MIL" or "CA-MIL" for non-civil US / Canada allocation.
bool: True if the Mode S address successfully translated to an
N number. False for all other conditions.
*/
func icao2reg(icao_addr uint32) (string, bool) {
// Initialize local variables
base34alphabet := string("ABCDEFGHJKLMNPQRSTUVWXYZ0123456789")
nationalOffset := uint32(0xA00001) // default is US
tail := ""
nation := ""
// Determine nationality
if (icao_addr >= 0xA00001) && (icao_addr <= 0xAFFFFF) {
nation = "US"
} else if (icao_addr >= 0xC00001) && (icao_addr <= 0xC3FFFF) {
nation = "CA"
} else if (icao_addr >= 0x7C0000) && (icao_addr <= 0x7FFFFF) {
nation = "AU"
} else {
//TODO: future national decoding.
return "OTHER", false
}
if nation == "CA" { // Canada decoding
// First, discard addresses that are not assigned to aircraft on the civil registry
if icao_addr > 0xC0CDF8 {
//fmt.Printf("%X is a Canada aircraft, but not a CF-, CG-, or CI- registration.\n", icao_addr)
return "CA-MIL", false
}
nationalOffset := uint32(0xC00001)
serial := int32(icao_addr - nationalOffset)
// Fifth letter
e := serial % 26
// Fourth letter
d := (serial / 26) % 26
// Third letter
c := (serial / 676) % 26 // 676 == 26*26
// Second letter
b := (serial / 17576) % 26 // 17576 == 26*26*26
b_str := "FGI"
//fmt.Printf("B = %d, C = %d, D = %d, E = %d\n",b,c,d,e)
tail = fmt.Sprintf("C-%c%c%c%c", b_str[b], c+65, d+65, e+65)
}
if nation == "AU" { // Australia decoding
nationalOffset := uint32(0x7C0000)
offset := (icao_addr - nationalOffset)
i1 := offset / 1296
offset2 := offset % 1296
i2 := offset2 / 36
offset3 := offset2 % 36
i3 := offset3
var a_char, b_char, c_char string
a_char = fmt.Sprintf("%c", i1+65)
b_char = fmt.Sprintf("%c", i2+65)
c_char = fmt.Sprintf("%c", i3+65)
if i1 < 0 || i1 > 25 || i2 < 0 || i2 > 25 || i3 < 0 || i3 > 25 {
return "OTHER", false
}
tail = "VH-" + a_char + b_char + c_char
}
if nation == "US" { // FAA decoding
// First, discard addresses that are not assigned to aircraft on the civil registry
if icao_addr > 0xADF7C7 {
//fmt.Printf("%X is a US aircraft, but not on the civil registry.\n", icao_addr)
return "US-MIL", false
}
serial := int32(icao_addr - nationalOffset)
// First digit
a := (serial / 101711) + 1
// Second digit
a_remainder := serial % 101711
b := ((a_remainder + 9510) / 10111) - 1
// Third digit
b_remainder := (a_remainder + 9510) % 10111
c := ((b_remainder + 350) / 951) - 1
// This next bit is more convoluted. First, figure out if we're using the "short" method of
// decoding the last two digits (two letters, one letter and one blank, or two blanks).
// This will be the case if digit "B" or "C" are calculated as negative, or if c_remainder
// is less than 601.
c_remainder := (b_remainder + 350) % 951
var d, e int32
if (b >= 0) && (c >= 0) && (c_remainder > 600) { // alphanumeric decoding method
d = 24 + (c_remainder-601)/35
e = (c_remainder - 601) % 35
} else { // two-letter decoding method
if (b < 0) || (c < 0) {
c_remainder -= 350 // otherwise " " == 350, "A " == 351, "AA" == 352, etc.
}
d = (c_remainder - 1) / 25
e = (c_remainder - 1) % 25
if e < 0 {
d -= 1
e += 25
}
}
a_char := fmt.Sprintf("%d", a)
var b_char, c_char, d_char, e_char string
if b >= 0 {
b_char = fmt.Sprintf("%d", b)
}
if b >= 0 && c >= 0 {
c_char = fmt.Sprintf("%d", c)
}
if d > -1 {
d_char = string(base34alphabet[d])
if e > 0 {
e_char = string(base34alphabet[e-1])
}
}
tail = "N" + a_char + b_char + c_char + d_char + e_char
}
return tail, true
}
func initTraffic() {
traffic = make(map[uint32]TrafficInfo)
seenTraffic = make(map[uint32]bool)

Wyświetl plik

@ -1,6 +1,6 @@
/*
Copyright (c) 2015-2016 Christopher Young
Distributable under the terms of The "BSD New"" License
Distributable under the terms of The "BSD New" License
that can be found in the LICENSE file, herein included
as part of this header.
@ -11,6 +11,7 @@
package main
import (
"encoding/json"
"golang.org/x/net/websocket"
"sync"
"time"
@ -36,6 +37,11 @@ func (u *uibroadcaster) Send(msg []byte) {
u.messages <- msg
}
func (u *uibroadcaster) SendJSON(i interface{}) {
j, _ := json.Marshal(&i)
u.Send(j)
}
func (u *uibroadcaster) AddSocket(sock *websocket.Conn) {
u.sockets_mu.Lock()
u.sockets = append(u.sockets, sock)

Wyświetl plik

@ -1,183 +0,0 @@
// Package mpu6050 allows interfacing with InvenSense mpu6050 barometric pressure sensor. This sensor
// has the ability to provided compensated temperature and pressure readings.
package mpu6050
import (
"../linux-mpu9150/mpu"
"log"
"math"
"time"
)
//https://www.olimex.com/Products/Modules/Sensors/MOD-MPU6050/resources/RM-MPU-60xxA_rev_4.pdf
const (
pollDelay = 98 * time.Millisecond // ~10Hz
)
// MPU6050 represents a InvenSense MPU6050 sensor.
type MPU6050 struct {
Poll time.Duration
started bool
pitch float64
roll float64
// Calibration variables.
calibrated bool
pitch_history []float64
roll_history []float64
pitch_resting float64
roll_resting float64
// For tracking heading (mixing GPS track and the gyro output).
heading float64 // Current heading.
gps_track float64 // Last reading directly from the gyro for comparison with current heading.
gps_track_valid bool
heading_correction float64
quit chan struct{}
}
// New returns a handle to a MPU6050 sensor.
func New() *MPU6050 {
n := &MPU6050{Poll: pollDelay}
n.StartUp()
return n
}
func (d *MPU6050) StartUp() error {
mpu_sample_rate := 10 // 10 Hz read rate of hardware IMU
yaw_mix_factor := 0 // must be zero if no magnetometer
mpu.InitMPU(mpu_sample_rate, yaw_mix_factor)
d.pitch_history = make([]float64, 0)
d.roll_history = make([]float64, 0)
d.started = true
d.Run()
return nil
}
/*
func (d *MPU6050) calibrate() {
//TODO: Error checking to make sure that the histories are extensive enough to be significant.
//TODO: Error checking to do continuous calibrations.
pitch_adjust := float64(0)
for _, v := range d.pitch_history {
pitch_adjust = pitch_adjust + v
}
pitch_adjust = pitch_adjust / float64(len(d.pitch_history))
d.pitch_resting = pitch_adjust
roll_adjust := float64(0)
for _, v := range d.roll_history {
roll_adjust = roll_adjust + v
}
roll_adjust = roll_adjust / float64(len(d.roll_history))
d.roll_resting = roll_adjust
log.Printf("calibrate: pitch %f, roll %f\n", pitch_adjust, roll_adjust)
d.calibrated = true
}
*/
func normalizeHeading(h float64) float64 {
for h < float64(0.0) {
h = h + float64(360.0)
}
for h >= float64(360.0) {
h = h - float64(360.0)
}
return h
}
func (d *MPU6050) getMPUData() {
pr, rr, hr, err := mpu.ReadMPU()
// Convert from radians to degrees.
pitch := float64(pr) * (float64(180.0) / math.Pi)
roll := float64(-rr) * (float64(180.0) / math.Pi)
heading := float64(hr) * (float64(180.0) / math.Pi)
if heading < float64(0.0) {
heading = float64(360.0) + heading
}
if err == nil {
d.pitch = pitch
d.roll = roll
// Heading is raw value off the IMU. Without mag compass fusion, need to apply correction bias.
// Amount of correction is set by ResetHeading() -- doesn't necessarily have to be based off GPS.
d.heading = normalizeHeading((heading - d.heading_correction))
} else {
// log.Printf("mpu6050.calculatePitchAndRoll(): mpu.ReadMPU() err: %s\n", err.Error())
}
}
// Temperature returns the current temperature reading.
func (d *MPU6050) PitchAndRoll() (float64, float64) {
return (d.pitch - d.pitch_resting), (d.roll - d.roll_resting)
}
func (d *MPU6050) Heading() float64 {
return d.heading
}
func (d *MPU6050) Run() {
time.Sleep(d.Poll)
go func() {
d.quit = make(chan struct{})
timer := time.NewTicker(d.Poll)
// calibrateTimer := time.NewTicker(1 * time.Minute)
for {
select {
case <-timer.C:
d.getMPUData()
// case <-calibrateTimer.C:
// d.calibrate()
// calibrateTimer.Stop()
case <-d.quit:
mpu.CloseMPU()
return
}
}
}()
return
}
// Set heading from a known value (usually GPS true heading).
func (d *MPU6050) ResetHeading(newHeading float64, gain float64) {
if gain < 0.001 { // sanitize our inputs!
gain = 0.001
} else if gain > 1 {
gain = 1
}
old_hdg := d.heading // only used for debug log report
//newHeading = float64(30*time.Now().Minute()) // demo input for testing
newHeading = normalizeHeading(newHeading) // sanitize the inputs
// By applying gain factor, this becomes a 1st order function that slowly converges on solution.
// Time constant is poll rate over gain. With gain of 0.1, convergence to +/-2 deg on a 180 correction difference is about 4 sec; 0.01 converges in 45 sec.
hdg_corr_bias := float64(d.heading - newHeading) // desired adjustment to heading_correction
if hdg_corr_bias > 180 {
hdg_corr_bias = hdg_corr_bias - 360
} else if hdg_corr_bias < -180 {
hdg_corr_bias = hdg_corr_bias + 360
}
hdg_corr_bias = hdg_corr_bias * gain
d.heading_correction = normalizeHeading(d.heading_correction + hdg_corr_bias)
log.Printf("Adjusted heading. Old: %f Desired: %f Adjustment: %f New: %f\n", old_hdg, newHeading, hdg_corr_bias, d.heading-hdg_corr_bias)
}
// Close.
func (d *MPU6050) Close() {
if d.quit != nil {
d.quit <- struct{}{}
}
}

Plik binarny nie jest wyświetlany.

Wyświetl plik

@ -15,8 +15,9 @@ In order of preference:
1. Look for `0xCC` (or `0x5358`) GDL90 heartbeat message. This is sent at the same time as the GDL90 heartbeat (0x00) message.
2. Look for Wi-Fi network that **starts with** "stratux".
3. Detect 192.168.10.0/24 Wi-Fi connection, verify stratux status with JSON response from ws://192.168.10.1/status.
4. Use the the second [stratux status](http://hiltonsoftware.com/stratux/StratuxStatusMessage-V104.pdf) message.
See main/gen_gdl90.go:makeStratuxHeartbeat() for heartbeat format.
See main/gen_gdl90.go:makeStratuxHeartbeat() for heartbeat (#1) format.
### Sleep mode
@ -26,17 +27,25 @@ Stratux makes use of of ICMP Echo/Echo Reply and ICMP Destination Unreachable pa
the typical "sleep mode" period, whose content remains accurate despite said delay, and whose content is sufficiently redundant such
that if the typical delay period is exceeded then it can be discarded.
When a client enters sleep mode, queueable messages are entered into a FIFO queue of fixed size which should be sufficient to hold 10-25 minutes of
data per client.
When a client enters sleep mode, queueable messages are entered into a FIFO queue of fixed size which should be sufficient to hold 10-25 minutes of data per client. Non-queueable messages that are directed
towards a client while in sleep mode are discarded. When in sleep mode, therefore, no GDL90 messages are received by the client.
There are three cases that are used to detect the state of a client:
There are three cases that are used to determine the state of a client:
1. Responding to ICMP Echo AND no ICMP Destination Unreachable received for destination port => not sleeping.
2. Not responding to ICMP Echo => sleeping.
3. Responding to ICMP Echo AND ICMP Destination Unreachable received for destination port => sleeping.
It is important to note that NEXRAD frames, METARs, and Winds Aloft may be delayed in reception. The timestamp in the GDL90 message should always
be used to for the observation time, and not the time the message was received.
The sleep mode detection routine has two parts:
1. ICMP Echo packets are sent every 5 seconds. If a response is not received in the last 10 seconds, the client is in sleep mode.
2. If an ICMP Destination Unreachable is received in the last 5 seconds, the client is in sleep mode.
3. If an ICMP Destination Unreachable has been received in the last 15 seconds, but not in the last 5 seconds, the client is in *throttle mode*. In throttle mode, messages are sent at 0.1% of the normal rate. This gives the client a chance to recover or to respond that the port is closed.
__Note__: NEXRAD frames, METARs, and Winds Aloft, and other weather data may be delayed in reception to
the receiving application. The timestamp in the GDL90 message should always be used to for the observation
time, and **not the time the message was received**.
### Traffic handling
@ -54,7 +63,7 @@ Some 1090ES transponders will send the actual registration number of the aircraf
a squawk code.
### Additional data available to EFBs
### Additional data/control available to EFBs
Stratux makes available a webserver to retrieve statistics which may be useful to EFBs:
@ -91,21 +100,53 @@ Stratux makes available a webserver to retrieve statistics which may be useful t
* `http://192.168.10.1/getStatus` - device status and statistics. Example output (commented JSON):
```json
```javascript
{
"Version": "v0.5b1", // Software version.
"Devices": 0, // Number of radios connected.
"Connected_Users": 1, // Number of WiFi devices connected.
"UAT_messages_last_minute": 0, // UAT messages received in last minute.
"UAT_messages_max": 17949, // Max UAT messages received in a minute (since last reboot).
"ES_messages_last_minute": 0, // 1090ES messages received in last minute.
"ES_messages_max": 0, // Max 1090ES messages received in a minute (since last reboot).
"GPS_satellites_locked": 0, // Number of GPS satellites used in last GPS lock.
"GPS_connected": true, // GPS unit connected and functioning.
"GPS_solution": "", // "DGPS (WAAS)", "3D GPS", "N/A", or "" when GPS not connected/enabled.
"RY835AI_connected": false, // GPS/AHRS unit - use only for debugging (this will be removed).
"Uptime": 227068, // Device uptime (in milliseconds).
"CPUTemp": 42.236 // CPU temperature (in ºC).
"Version": "v1.4r2",
"Build": "ebd6b9bf5049aa5bb31c345c1eaa39648bc219a2",
"HardwareBuild": "",
"Devices": 1,
"Connected_Users": 0,
"DiskBytesFree": 60625375232,
"UAT_messages_last_minute": 0,
"UAT_messages_max": 0,
"ES_messages_last_minute": 0,
"ES_messages_max": 0,
"UAT_traffic_targets_tracking": 0,
"ES_traffic_targets_tracking": 0,
"Ping_connected": false,
"GPS_satellites_locked": 5,
"GPS_satellites_seen": 7,
"GPS_satellites_tracked": 9,
"GPS_position_accuracy": 10.2,
"GPS_connected": true,
"GPS_solution": "GPS + SBAS (WAAS)",
"GPS_detected_type": 55,
"Uptime": 323020,
"UptimeClock": "0001-01-01T00:05:23.02Z",
"CPUTemp": 47.774,
"NetworkDataMessagesSent": 0,
"NetworkDataMessagesSentNonqueueable": 0,
"NetworkDataBytesSent": 0,
"NetworkDataBytesSentNonqueueable": 0,
"NetworkDataMessagesSentLastSec": 0,
"NetworkDataMessagesSentNonqueueableLastSec": 0,
"NetworkDataBytesSentLastSec": 0,
"NetworkDataBytesSentNonqueueableLastSec": 0,
"UAT_METAR_total": 0,
"UAT_TAF_total": 0,
"UAT_NEXRAD_total": 0,
"UAT_SIGMET_total": 0,
"UAT_PIREP_total": 0,
"UAT_NOTAM_total": 0,
"UAT_OTHER_total": 0,
"Errors": [
],
"Logfile_Size": 34487043,
"AHRS_LogFiles_Size": 0,
"BMPConnected": true,
"IMUConnected": true
}
```
@ -115,27 +156,55 @@ Stratux makes available a webserver to retrieve statistics which may be useful t
{
"UAT_Enabled": true,
"ES_Enabled": false,
"Ping_Enabled": false,
"GPS_Enabled": true,
"BMP_Sensor_Enabled": true,
"IMU_Sensor_Enabled": true,
"NetworkOutputs": [
{
"Conn": null,
"Ip": "",
"Port": 4000,
"Capability": 5
},
{
"Conn": null,
"Ip": "",
"Port": 49002,
"Capability": 2
"Capability": 5,
"MessageQueueLen": 0,
"LastUnreachable": "0001-01-01T00:00:00Z",
"SleepFlag": false,
"FFCrippled": false
}
],
"AHRS_Enabled": false,
"SerialOutputs": null,
"DisplayTrafficSource": false,
"DEBUG": false,
"ReplayLog": true,
"ReplayLog": false,
"AHRSLog": false,
"IMUMapping": [
-1,
0
],
"SensorQuaternion": [
0.0068582877312501,
0.0067230280142738,
0.7140806859355,
-0.69999752767998
],
"C": [
-0.019065523239845,
-0.99225684377575,
-0.019766228217414
],
"D": [
-2.7707754753258,
5.544145023957,
-1.890621662038
],
"PPM": 0,
"OwnshipModeS": "F00000",
"WatchList": ""
"WatchList": "",
"DeveloperMode": false,
"GLimits": "",
"StaticIps": [
]
}
```
* `http://192.168.10.1/setSettings` - set device settings. Use an HTTP POST of JSON content in the format given above - posting only the fields containing the settings to be modified.
@ -144,22 +213,45 @@ Stratux makes available a webserver to retrieve statistics which may be useful t
```json
{
"Lat": 39.108533,
"Lng": -76.770862,
"Satellites": 7,
"Accuracy": 5.88,
"NACp": 10,
"Alt": 170.10767,
"LastFixLocalTime": "2015-12-18T23:47:06.015563066Z",
"TrueCourse": 0,
"GroundSpeed": 0,
"LastGroundTrackTime": "0001-01-01T00:00:00Z",
"Temp": 6553,
"Pressure_alt": 231.27980834234,
"Pitch": -0.006116937627108,
"Roll": -0.026442866350631,
"Gyro_heading": 45.844213419776,
"LastAttitudeTime": "2015-12-18T23:47:06.774039623Z"
"GPSLastFixSinceMidnightUTC": 67337.6,
"GPSLatitude": 39.108533,
"GPSLongitude": -76.770862,
"GPSFixQuality": 2,
"GPSHeightAboveEllipsoid": 115.51,
"GPSGeoidSep": -17.523,
"GPSSatellites": 5,
"GPSSatellitesTracked": 11,
"GPSSatellitesSeen": 8,
"GPSHorizontalAccuracy": 10.2,
"GPSNACp": 9,
"GPSAltitudeMSL": 170.10767,
"GPSVerticalAccuracy": 8,
"GPSVerticalSpeed": -0.6135171,
"GPSLastFixLocalTime": "0001-01-01T00:06:44.24Z",
"GPSTrueCourse": 0,
"GPSTurnRate": 0,
"GPSGroundSpeed": 0.77598433056951,
"GPSLastGroundTrackTime": "0001-01-01T00:06:44.24Z",
"GPSTime": "2017-09-26T18:42:17Z",
"GPSLastGPSTimeStratuxTime": "0001-01-01T00:06:43.65Z",
"GPSLastValidNMEAMessageTime": "0001-01-01T00:06:44.24Z",
"GPSLastValidNMEAMessage": "$PUBX,04,184426.00,260917,240266.00,1968,18,-177618,-952.368,21*1A",
"GPSPositionSampleRate": 0,
"BaroTemperature": 37.02,
"BaroPressureAltitude": 153.32,
"BaroVerticalSpeed": 1.3123479,
"BaroLastMeasurementTime": "0001-01-01T00:06:44.23Z",
"AHRSPitch": -0.97934145732801, // Degrees. 3276.7 = Invalid.
"AHRSRoll": -2.2013729217108, // Degrees. 3276.7 = Invalid.
"AHRSGyroHeading": 187741.08073052, // Degrees. Process mod 360. 3276.7 = Invalid.
"AHRSMagHeading": 3276.7, // Degrees. Process mod 360. 3276.7 = Invalid.
"AHRSSlipSkid": 0.52267604604907, // Degrees. 3276.7 = Invalid.
"AHRSTurnRate": 3276.7, // Degrees per second. 3276.7 = Invalid.
"AHRSGLoad": 0.99847599584255, // Current G load, in G's. Reads 1 G at rest.
"AHRSGLoadMin": 0.99815989027411, // Minimum recorded G load, in G's.
"AHRSGLoadMax": 1.0043409597397, // Maximum recorded G load, in G's.
"AHRSLastAttitudeTime": "0001-01-01T00:06:44.28Z", // Stratux clock ticks since last attitude update. Reference against /getStatus -> UptimeClock.
"AHRSStatus": 7 // Status bitmask. See main/sensors.go -> updateAHRSStatus().
}
```
@ -177,4 +269,17 @@ Subsequent update (2837120 = 2B4A80 reports a newer position, altitude increased
```json
{"Icao_addr":2837120,"OnGround":false,"Lat":42.193336,"Lng":-83.92136,"Position_valid":true,"Alt":3400,"Track":9,"Speed":92,"Speed_valid":true,"Vvel":0,"Tail":"","Last_seen":"2015-12-22T21:29:22.252914555Z","Last_source":2}
```
```
* `http://192.168.10.1/calibrateAHRS` - run AHRS sensor calibration routine. Submit a blank POST to this URL.
* `http://192.168.10.1/cageAHRS` - "level" attitude display. Submit a blank POST to this URL.
* `http://192.168.10.1/resetGMeter` - reset G-meter to zero. Submit a blank POST to this URL.
* `http://192.168.10.1/restart` - restart Stratux application.
* `http://192.168.10.1/reboot` - reboot the system.
* `http://192.168.10.1/shutdown` - shutdown the system.

BIN
notes/logo.bmp 100644

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 642 B

14942
notes/logo.dxf 100644

Plik diff jest za duży Load Diff

Wyświetl plik

@ -16,13 +16,36 @@ make
rm -rf work
mkdir -p work/bin
cp gen_gdl90 work/bin/
cp fancontrol work/bin/
cp libdump978.so work/bin/
cp linux-mpu9150/libimu.so work/bin/
cp init.d-stratux work/bin/
cp __lib__systemd__system__stratux.service work/bin/
cp __root__stratux-pre-start.sh work/bin/
cp dump1090/dump1090 work/bin/
cp image/rc.local work/bin/
cp image/wifi_watch.sh work/bin/
cp -r web work/bin/
cp image/hostapd.conf work/bin/
cp image/hostapd-edimax.conf work/bin/
cp image/config.txt work/bin/
cp image/rtl-sdr-blacklist.conf work/bin/
cp image/bashrc.txt work/bin/
cp image/modules.txt work/bin/
cp image/stxAliases.txt work/bin/
cp image/hostapd_manager.sh work/bin/
cp image/sdr-tool.sh work/bin/
cp image/10-stratux.rules work/bin/
cp image/99-uavionix.rules work/bin/
cp image/motd work/bin/
cp image/stratux-wifi.sh work/bin/
cp image/rc.local work/bin/
cp image/dhcpd-not_smart.conf work/bin/
cp image/dhcpd-smart.conf work/bin/
cp image/interfaces work/bin/
cp image/logrotate.conf work/bin/
cp image/logrotate_d_stratux work/bin/
cp image/rsyslog_d_stratux work/bin/
cp test-data/ahrs/ahrs_table.log work/bin/
cp ahrs_approx work/bin/
#TODO: librtlsdr.
cd work/
cat ../selfupdate/update_header.sh >update.sh

Wyświetl plik

@ -8,7 +8,11 @@ ssh -i ~/.ssh/id_rsa.updates stratux-updates@updates.stratux.me 'ls -1 queue/' |
cd selfupdate
./makeupdate.sh
cd ..
scp -i ~/.ssh/id_rsa.updates work/update*.sh stratux-updates@updates.stratux.me:finished/
for fl in `ls -1 work/update*.sh | cut -d/ -f2`
do
scp -i ~/.ssh/id_rsa.updates work/${fl} stratux-updates@updates.stratux.me:uploading/
ssh -i ~/.ssh/id_rsa.updates stratux-updates@updates.stratux.me "mv uploading/${fl} finished/"
done
cd ..
ssh -i ~/.ssh/id_rsa.updates stratux-updates@updates.stratux.me "rm -f queue/${git_hash}"
done

Wyświetl plik

@ -1,20 +1,105 @@
cp -f gen_gdl90 /usr/bin/gen_gdl90
chmod 755 /usr/bin/gen_gdl90
cp -f libdump978.so /usr/lib/libdump978.so
cp -f libimu.so /usr/lib/libimu.so
chmod 655 /usr/bin/gen_gdl90
# Startup script.
cp -f init.d-stratux /etc/init.d/stratux
chmod 755 /etc/init.d/stratux
ln -fs /etc/init.d/stratux /etc/rc2.d/S01stratux
ln -fs /etc/init.d/stratux /etc/rc6.d/K01stratux
RASPBIAN_VERSION=`cat /etc/debian_version`
if test "$RASPBIAN_VERSION" = "8.0" ; then
# Install the systemd startup scripts in any case, even if they won't be used. If this is being run, then the old init.d script
# is still intact and we just leave it. If running Wheezy, then remove the old init.d script.
rm -f /etc/init.d/stratux
rm -f /etc/rc2.d/S01stratux
rm -f /etc/rc6.d/K01stratux
fi
# Wifi watcher.
cp -f rc.local /etc/rc.local
cp -f wifi_watch.sh /usr/sbin/wifi_watch.sh
chmod +x /usr/sbin/wifi_watch.sh
cp -f __lib__systemd__system__stratux.service /lib/systemd/system/stratux.service
cp -f __root__stratux-pre-start.sh /root/stratux-pre-start.sh
chmod 644 /lib/systemd/system/stratux.service
chmod 744 /root/stratux-pre-start.sh
ln -fs /lib/systemd/system/stratux.service /etc/systemd/system/multi-user.target.wants/stratux.service
#wifi config
cp -f hostapd.conf /etc/hostapd/hostapd.conf
cp -f hostapd-edimax.conf /etc/hostapd/hostapd-edimax.conf
#rsyslog config
cp -f rsyslog_d_stratux /etc/rsyslog.d/stratux.conf
#logrotate config
cp -f logrotate.conf /etc/logrotate.conf
cp -f logrotate_d_stratux /etc/logrotate.d/stratux
#WiFi Hostapd ver test and hostapd.conf builder script
cp -f stratux-wifi.sh /usr/sbin/
chmod 755 /usr/sbin/stratux-wifi.sh
#WiFi Config Manager
cp -f hostapd_manager.sh /usr/sbin/
chmod 755 /usr/sbin/hostapd_manager.sh
#SDR Serial Script
cp -f sdr-tool.sh /usr/sbin/
chmod 755 /usr/sbin/sdr-tool.sh
#boot config
cp -f config.txt /boot/config.txt
#rc.local
cp -f rc.local /etc/
#disable serial console
sed -i /boot/cmdline.txt -e "s/console=ttyAMA0,[0-9]\+ //"
#modprobe.d blacklist
cp -f rtl-sdr-blacklist.conf /etc/modprobe.d/
#udev config
cp -f 10-stratux.rules /etc/udev/rules.d
cp -f 99-uavionix.rules /etc/udev/rules.d
#go setup
cp -f bashrc.txt /root/.bashrc
cp -f stxAliases.txt /root/.stxAliases
# /etc/modules
cp -f modules.txt /etc/modules
#motd
cp -f motd /etc/motd
#fan control utility
#remove old script
rm -f /usr/bin/fancontrol.py
#install new program
/usr/bin/fancontrol stop
/usr/bin/fancontrol remove
cp -f fancontrol /usr/bin/
chmod 755 /usr/bin/fancontrol
/usr/bin/fancontrol install
cp -f dump1090 /usr/bin/
chmod 755 /usr/bin/dump1090
# AHRS approx data.
cp -f ahrs_table.log /root/
cp -f ahrs_approx /usr/bin/
chmod 755 /usr/bin/ahrs_approx
# DHCPD Config.
cp -f dhcpd-not_smart.conf /etc/dhcp/
cp -f dhcpd-smart.conf /etc/dhcp/
ln -s /etc/dhcp/dhcpd-not_smart.conf /etc/dhcp/dhcpd.conf
# Interfaces file.
cp -f interfaces /etc/network/interfaces
# Web files install.
cd web/ && make stratuxBuild=${stratuxBuild}
cd web/ && make stratuxBuild=${stratuxBuild}
# Remove old Wi-Fi watcher script.
rm -f /usr/sbin/wifi_watch.sh
sed -i "/\bwifi_watch\b/d" /etc/rc.local
cd /
rm -rf /root/stratux-update

Wyświetl plik

@ -3,4 +3,4 @@
rm -rf /root/stratux-update
mkdir -p /root/stratux-update
cd /root/stratux-update
rm -f /var/log/stratux*

81
sensors/bmp280.go 100644
Wyświetl plik

@ -0,0 +1,81 @@
// Package sensors provides a stratux interface to sensors used for AHRS calculations.
package sensors
import (
"errors"
"time"
"../goflying/bmp280"
"github.com/kidoman/embd"
)
const (
bmp280PowerMode = bmp280.NormalMode
bmp280Standby = bmp280.StandbyTime63ms
bmp280FilterCoeff = bmp280.FilterCoeff16
bmp280TempRes = bmp280.Oversamp16x
bmp280PressRes = bmp280.Oversamp16x
)
// BMP280 represents a BMP280 sensor and implements the PressureSensor interface.
type BMP280 struct {
sensor *bmp280.BMP280
data *bmp280.BMPData
running bool
}
var errBMP = errors.New("BMP280 Error: BMP280 is not running")
// NewBMP280 looks for a BMP280 connected on the I2C bus having one of the valid addresses and begins reading it.
func NewBMP280(i2cbus *embd.I2CBus, freq time.Duration) (*BMP280, error) {
var (
bmp *bmp280.BMP280
errbmp error
)
bmp, errbmp = bmp280.NewBMP280(i2cbus, bmp280.Address1,
bmp280PowerMode, bmp280Standby, bmp280FilterCoeff, bmp280TempRes, bmp280PressRes)
if errbmp != nil { // Maybe the BMP280 isn't at Address1, try Address2
bmp, errbmp = bmp280.NewBMP280(i2cbus, bmp280.Address2,
bmp280PowerMode, bmp280Standby, bmp280FilterCoeff, bmp280TempRes, bmp280PressRes)
}
if errbmp != nil {
return nil, errbmp
}
newbmp := BMP280{sensor: bmp, data: new(bmp280.BMPData)}
go newbmp.run()
return &newbmp, nil
}
func (bmp *BMP280) run() {
bmp.running = true
clock := time.NewTicker(100 * time.Millisecond)
for bmp.running {
<-clock.C
bmp.data = <-bmp.sensor.C
}
}
// Temperature returns the current temperature in degrees C measured by the BMP280
func (bmp *BMP280) Temperature() (float64, error) {
if !bmp.running {
return 0, errBMP
}
return bmp.data.Temperature, nil
}
// Pressure returns the current pressure in mbar measured by the BMP280
func (bmp *BMP280) Pressure() (float64, error) {
if !bmp.running {
return 0, errBMP
}
return bmp.data.Pressure, nil
}
// Close stops the measurements of the BMP280
func (bmp *BMP280) Close() {
bmp.running = false
bmp.sensor.Close()
}

Wyświetl plik

@ -0,0 +1,98 @@
// Package sensors provides a stratux interface to sensors used for AHRS calculations.
package sensors
import (
"../goflying/icm20948"
"github.com/kidoman/embd"
)
const (
gyroRange = 250 // gyroRange is the default range to use for the Gyro.
accelRange = 4 // accelRange is the default range to use for the Accel.
updateFreq = 50 // updateFreq is the rate at which to update the sensor values.
)
// ICM20948 represents an InvenSense ICM-20948 attached to the I2C bus and satisfies
// the IMUReader interface.
type ICM20948 struct {
mpu *icm20948.ICM20948
}
// NewICM20948 returns an instance of the ICM-20948 IMUReader, connected to an
// ICM-20948 attached on the I2C bus with either valid address.
func NewICM20948(i2cbus *embd.I2CBus) (*ICM20948, error) {
var (
m ICM20948
mpu *icm20948.ICM20948
err error
)
mpu, err = icm20948.NewICM20948(i2cbus, gyroRange, accelRange, updateFreq, true, false)
if err != nil {
return nil, err
}
// Set Gyro (Accel) LPFs to 25 Hz to filter out prop/glareshield vibrations above 1200 (1260) RPM
mpu.SetGyroLPF(25)
mpu.SetAccelLPF(25)
m.mpu = mpu
return &m, nil
}
// Read returns the average (since last reading) time, Gyro X-Y-Z, Accel X-Y-Z, Mag X-Y-Z,
// error reading Gyro/Accel, and error reading Mag.
func (m *ICM20948) Read() (T int64, G1, G2, G3, A1, A2, A3, M1, M2, M3 float64, GAError, MAGError error) {
var (
data *icm20948.MPUData
i int8
)
data = new(icm20948.MPUData)
for data.N == 0 && i < 5 {
data = <-m.mpu.CAvg
T = data.T.UnixNano()
G1 = data.G1
G2 = data.G2
G3 = data.G3
A1 = data.A1
A2 = data.A2
A3 = data.A3
M1 = data.M1
M2 = data.M2
M3 = data.M3
GAError = data.GAError
MAGError = data.MagError
i++
}
return
}
// ReadOne returns the most recent time, Gyro X-Y-Z, Accel X-Y-Z, Mag X-Y-Z,
// error reading Gyro/Accel, and error reading Mag.
func (m *ICM20948) ReadOne() (T int64, G1, G2, G3, A1, A2, A3, M1, M2, M3 float64, GAError, MAGError error) {
var (
data *icm20948.MPUData
)
data = new(icm20948.MPUData)
data = <-m.mpu.C
T = data.T.UnixNano()
G1 = data.G1
G2 = data.G2
G3 = data.G3
A1 = data.A1
A2 = data.A2
A3 = data.A3
M1 = data.M1
M2 = data.M2
M3 = data.M3
GAError = data.GAError
MAGError = data.MagError
return
}
// Close stops reading the MPU.
func (m *ICM20948) Close() {
m.mpu.CloseMPU()
}

17
sensors/imu.go 100644
Wyświetl plik

@ -0,0 +1,17 @@
// Package sensors provides a stratux interface to sensors used for AHRS calculations.
package sensors
// IMUReader provides an interface to various Inertial Measurement Unit sensors,
// such as the InvenSense MPU9150 or MPU9250. It is a light abstraction on top
// of the current github.com/westphae/goflying MPU9250 driver so that it can accommodate other types
// of drivers.
type IMUReader interface {
// Read returns the average (since last reading) time, Gyro X-Y-Z, Accel X-Y-Z, Mag X-Y-Z,
// error reading Gyro/Accel, and error reading Mag.
Read() (T int64, G1, G2, G3, A1, A2, A3, M1, M2, M3 float64, GAError, MagError error)
// ReadOne returns the most recent time, Gyro X-Y-Z, Accel X-Y-Z, Mag X-Y-Z,
// error reading Gyro/Accel, and error reading Mag.
ReadOne() (T int64, G1, G2, G3, A1, A2, A3, M1, M2, M3 float64, GAError, MagError error)
// Close stops reading the MPU.
Close()
}

98
sensors/mpu9250.go 100644
Wyświetl plik

@ -0,0 +1,98 @@
// Package sensors provides a stratux interface to sensors used for AHRS calculations.
package sensors
import (
"../goflying/mpu9250"
"github.com/kidoman/embd"
)
const (
mpu9250GyroRange = 250 // mpu9250GyroRange is the default range to use for the Gyro.
mpu9250AccelRange = 4 // mpu9250AccelRange is the default range to use for the Accel.
mpu9250UpdateFreq = 50 // mpu9250UpdateFreq is the rate at which to update the sensor values.
)
// MPU9250 represents an InvenSense MPU9250 attached to the I2C bus and satisfies
// the IMUReader interface.
type MPU9250 struct {
mpu *mpu9250.MPU9250
}
// NewMPU9250 returns an instance of the MPU9250 IMUReader, connected to an
// MPU9250 attached on the I2C bus with either valid address.
func NewMPU9250(i2cbus *embd.I2CBus) (*MPU9250, error) {
var (
m MPU9250
mpu *mpu9250.MPU9250
err error
)
mpu, err = mpu9250.NewMPU9250(i2cbus, mpu9250GyroRange, mpu9250AccelRange, mpu9250UpdateFreq, true, false)
if err != nil {
return nil, err
}
// Set Gyro (Accel) LPFs to 20 (21) Hz to filter out prop/glareshield vibrations above 1200 (1260) RPM
mpu.SetGyroLPF(21)
mpu.SetAccelLPF(21)
m.mpu = mpu
return &m, nil
}
// Read returns the average (since last reading) time, Gyro X-Y-Z, Accel X-Y-Z, Mag X-Y-Z,
// error reading Gyro/Accel, and error reading Mag.
func (m *MPU9250) Read() (T int64, G1, G2, G3, A1, A2, A3, M1, M2, M3 float64, GAError, MAGError error) {
var (
data *mpu9250.MPUData
i int8
)
data = new(mpu9250.MPUData)
for data.N == 0 && i < 5 {
data = <-m.mpu.CAvg
T = data.T.UnixNano()
G1 = data.G1
G2 = data.G2
G3 = data.G3
A1 = data.A1
A2 = data.A2
A3 = data.A3
M1 = data.M1
M2 = data.M2
M3 = data.M3
GAError = data.GAError
MAGError = data.MagError
i++
}
return
}
// ReadOne returns the most recent time, Gyro X-Y-Z, Accel X-Y-Z, Mag X-Y-Z,
// error reading Gyro/Accel, and error reading Mag.
func (m *MPU9250) ReadOne() (T int64, G1, G2, G3, A1, A2, A3, M1, M2, M3 float64, GAError, MAGError error) {
var (
data *mpu9250.MPUData
)
data = new(mpu9250.MPUData)
data = <-m.mpu.C
T = data.T.UnixNano()
G1 = data.G1
G2 = data.G2
G3 = data.G3
A1 = data.A1
A2 = data.A2
A3 = data.A3
M1 = data.M1
M2 = data.M2
M3 = data.M3
GAError = data.GAError
MAGError = data.MagError
return
}
// Close stops reading the MPU.
func (m *MPU9250) Close() {
m.mpu.CloseMPU()
}

Wyświetl plik

@ -0,0 +1,10 @@
// Package sensors provides a stratux interface to sensors used for AHRS calculations.
package sensors
// PressureReader provides an interface to a sensor reading pressure and maybe
// temperature or humidity, like the BMP180 or BMP280.
type PressureReader interface {
Temperature() (temp float64, tempError error) // Temperature returns the temperature in degrees C.
Pressure() (press float64, pressError error) // Pressure returns the atmospheric pressure in mBar.
Close() // Close stops reading from the sensor.
}

Plik diff jest za duży Load Diff

Wyświetl plik

@ -1,444 +0,0 @@
//https://www.youtube.com/watch?v=sQxJkSFmy_M&t=12m14s
//https://www.youtube.com/watch?v=sQxJkSFmy_M&t=14m12s
//815
package main
import (
"fmt"
"log"
"os"
"bufio"
"strconv"
"encoding/json"
"errors"
"strings"
"net"
"math"
"time"
)
var Crc16Table [256]uint16
const (
IPAD_ADDR = "192.168.1.133"
LON_LAT_RESOLUTION = float64(180.0 / 8388608.0)
TRACK_RESOLUTION = float32(360.0 / 256.0)
)
type GPSData struct {
Timestamp int64
Lat float64
Lng float64
Alt float64
Speed float64
Course float64
}
type AHRSData struct {
Timestamp int64
RawGyro []int64
RawAccel []int64
RawQuat []int64
DmpTimestamp int64
RawMag []int64
MagTimestamp int64
CalibratedAccel []int64
CalibratedMag []int64
FusedQuat []float64
FusedEuler []float64
LastDMPYaw float64
LastYaw float64
}
// Construct the CRC table. Adapted from FAA ref above.
func crcInit() {
var i uint16
var bitctr uint16
var crc uint16
for i = 0; i < 256; i++ {
crc = (i << 8)
for bitctr = 0; bitctr < 8; bitctr++ {
z := uint16(0)
if (crc & 0x8000) != 0 {
z = 0x1021
}
crc = (crc << 1) ^ z
}
Crc16Table[i] = crc
}
}
func cleanStr(str string) string {
str = strings.Trim(str, "\r\n ")
str = strings.Replace(str, "\x00", "", -1)
return str
}
func seekTimestampInAHRS(fn string, startnsec, tol int64) (*os.File, int64, error) {
fp, err := os.OpenFile(fn, os.O_RDONLY, 0)
if err != nil {
return nil, 0, err
}
rdr := bufio.NewReader(fp)
for {
buf, err := rdr.ReadString('\n')
if err != nil {
break
}
buf = cleanStr(buf)
if len(buf) == 0 {
continue
}
var ahrs AHRSData
err = json.Unmarshal([]byte(buf), &ahrs)
if err != nil {
continue
}
i := ahrs.Timestamp
if ((i > startnsec) && (i - startnsec) <= tol) || ((i < startnsec) && (startnsec - i) <= tol) { // Found it.
return fp, i, nil
}
}
return nil, 0, errors.New("can't find start.")
}
func getLine(rdr *bufio.Reader) ([]string, int64) {
ret := make([]string, 0)
retIdx := int64(0)
for len(ret) == 0 {
buf, err := rdr.ReadString('\n')
if err != nil {
fmt.Printf("quitting. err: %s\n", err.Error())
os.Exit(0)
}
buf = cleanStr(buf)
ln := strings.Split(buf, ",")
if len(ln) < 2 {
continue
}
idx, err := strconv.ParseInt(ln[0], 10, 64)
if err != nil {
continue
}
ret = ln
retIdx = idx
}
return ret, retIdx
}
func getAHRS (rdr *bufio.Reader) (AHRSData, int64) {
var ahrs AHRSData
for ahrs.Timestamp == 0 {
buf, err := rdr.ReadString('\n')
if err != nil {
fmt.Printf("quitting. err: %s\n", err.Error())
os.Exit(0)
}
buf = cleanStr(buf)
err = json.Unmarshal([]byte(buf), &ahrs)
if err != nil {
continue
}
}
return ahrs, ahrs.Timestamp
}
func getGPS (rdr *bufio.Reader) (GPSData, int64) {
var gps GPSData
for gps.Timestamp == 0 {
buf, err := rdr.ReadString('\n')
if err != nil {
fmt.Printf("quitting. err: %s\n", err.Error())
os.Exit(0)
}
buf = cleanStr(buf)
err = json.Unmarshal([]byte(buf), &gps)
if err != nil {
continue
}
}
return gps, gps.Timestamp
}
// Compute CRC. Adapted from FAA ref above.
func crcCompute(data []byte) uint16 {
ret := uint16(0)
for i := 0; i < len(data); i++ {
ret = Crc16Table[ret>>8] ^ (ret << 8) ^ uint16(data[i])
}
return ret
}
func prepareMessage(data []byte) []byte {
// Compute CRC before modifying the message.
crc := crcCompute(data)
// Add the two CRC16 bytes before replacing control characters.
data = append(data, byte(crc&0xFF))
data = append(data, byte(crc>>8))
tmp := []byte{0x7E} // Flag start.
// Copy the message over, escaping 0x7E (Flag Byte) and 0x7D (Control-Escape).
for i := 0; i < len(data); i++ {
mv := data[i]
if (mv == 0x7E) || (mv == 0x7D) {
mv = mv ^ 0x20
tmp = append(tmp, 0x7D)
}
tmp = append(tmp, mv)
}
tmp = append(tmp, 0x7E) // Flag end.
return tmp
}
func makeHeartbeat() []byte {
msg := make([]byte, 7)
// See p.10.
msg[0] = 0x00 // Message type "Heartbeat".
msg[1] = 0x01 // "UAT Initialized".
msg[1] = msg[1] | 0x80
msg[1] = msg[1] | 0x10 //FIXME: Addr talkback.
nowUTC := time.Now().UTC()
// Seconds since 0000Z.
midnightUTC := time.Date(nowUTC.Year(), nowUTC.Month(), nowUTC.Day(), 0, 0, 0, 0, time.UTC)
secondsSinceMidnightUTC := uint32(nowUTC.Sub(midnightUTC).Seconds())
msg[2] = byte(((secondsSinceMidnightUTC >> 16) << 7) | 0x1) // UTC OK.
msg[3] = byte((secondsSinceMidnightUTC & 0xFF))
msg[4] = byte((secondsSinceMidnightUTC & 0xFFFF) >> 8)
// TODO. Number of uplink messages. See p.12.
// msg[5]
// msg[6]
return prepareMessage(msg)
}
func makeLatLng(v float64) []byte {
ret := make([]byte, 3)
v = v / LON_LAT_RESOLUTION
wk := int32(v)
ret[0] = byte((wk & 0xFF0000) >> 16)
ret[1] = byte((wk & 0x00FF00) >> 8)
ret[2] = byte((wk & 0x0000FF))
return ret
}
func makeOwnshipReport(gps GPSData) []byte {
msg := make([]byte, 28)
// See p.16.
msg[0] = 0x0A // Message type "Ownship".
msg[1] = 0x01 // Alert status, address type.
msg[2] = 1 // Address.
msg[3] = 1 // Address.
msg[4] = 1 // Address.
tmp := makeLatLng(gps.Lat)
msg[5] = tmp[0] // Latitude.
msg[6] = tmp[1] // Latitude.
msg[7] = tmp[2] // Latitude.
tmp = makeLatLng(gps.Lng)
msg[8] = tmp[0] // Longitude.
msg[9] = tmp[1] // Longitude.
msg[10] = tmp[2] // Longitude.
// This is **PRESSURE ALTITUDE**
//FIXME: Temporarily removing "invalid altitude" when pressure altitude not available - using GPS altitude instead.
// alt := uint16(0xFFF) // 0xFFF "invalid altitude."
alt := uint16(gps.Alt) //FIXME: This should not be here.
alt = (alt + 1000) / 25
alt = alt & 0xFFF // Should fit in 12 bits.
msg[11] = byte((alt & 0xFF0) >> 4) // Altitude.
msg[12] = byte((alt & 0x00F) << 4)
msg[12] = byte(((alt & 0x00F) << 4) | 0xB) // "Airborne" + "True Heading"
msg[13] = 0xBB // NIC and NACp.
gdSpeed := uint16(gps.Speed)
gdSpeed = gdSpeed & 0x0FFF // Should fit in 12 bits.
msg[14] = byte((gdSpeed & 0xFF0) >> 4)
msg[15] = byte((gdSpeed & 0x00F) << 4)
verticalVelocity := int16(1000 / 64) // ft/min. 64 ft/min resolution.
//TODO: 0x800 = no information available.
verticalVelocity = verticalVelocity & 0x0FFF // Should fit in 12 bits.
msg[15] = msg[15] | byte((verticalVelocity&0x0F00)>>8)
msg[16] = byte(verticalVelocity & 0xFF)
// Showing magnetic (corrected) on ForeFlight. Needs to be True Heading.
groundTrack := uint16(gps.Course)
trk := uint8(float32(groundTrack) / TRACK_RESOLUTION) // Resolution is ~1.4 degrees.
msg[17] = byte(trk)
msg[18] = 0x01 // "Light (ICAO) < 15,500 lbs"
return prepareMessage(msg)
}
//TODO
func makeOwnshipGeometricAltitudeReport(gps GPSData) []byte {
msg := make([]byte, 5)
// See p.28.
msg[0] = 0x0B // Message type "Ownship Geo Alt".
alt := int16(gps.Alt) // GPS Altitude.
alt = alt / 5
msg[1] = byte(alt >> 8) // Altitude.
msg[2] = byte(alt & 0x00FF) // Altitude.
//TODO: "Figure of Merit". 0x7FFF "Not available".
msg[3] = 0x00
msg[4] = 0x0A
return prepareMessage(msg)
}
var myGPS GPSData
func heartBeatSender() {
addr, err := net.ResolveUDPAddr("udp", IPAD_ADDR + ":4000")
if err != nil {
log.Printf("ResolveUDPAddr(%s): %s\n", IPAD_ADDR, err.Error())
return
}
gdlConn, err := net.DialUDP("udp", nil, addr)
if err != nil {
log.Printf("DialUDP(%s): %s\n", IPAD_ADDR, err.Error())
return
}
timer := time.NewTicker(1 * time.Second)
for {
<-timer.C
gdlConn.Write(makeHeartbeat())
gdlConn.Write(makeOwnshipReport(myGPS))
gdlConn.Write(makeOwnshipGeometricAltitudeReport(myGPS))
}
}
var cal_pitch float64
var cal_roll float64
var cal_num int
func main() {
crcInit()
if len(os.Args) < 5 {
fmt.Printf("%s <start second> <ahrs file> <gps file> <replay speed>\n", os.Args[0])
return
}
startsec, err := strconv.Atoi(os.Args[1])
if err != nil {
fmt.Printf("invalid: %s\n", os.Args[1])
return
}
replayspeed, err := strconv.Atoi(os.Args[4])
if err != nil {
fmt.Printf("invalid: %s\n", os.Args[4])
return
}
startnsec := int64(startsec) * 1000000000
ahrsfp, ahrsIdx, err := seekTimestampInAHRS(os.Args[2], startnsec, 1000000000) // Find the index with 1.00s tolerance.
if err != nil {
panic(err)
}
defer ahrsfp.Close()
gpsfp, err := os.OpenFile(os.Args[3], os.O_RDONLY, 0)
if err != nil {
panic(err)
}
defer gpsfp.Close()
addr, err := net.ResolveUDPAddr("udp", IPAD_ADDR + ":49002")
if err != nil {
log.Printf("ResolveUDPAddr(%s): %s\n", IPAD_ADDR, err.Error())
return
}
outConn, err := net.DialUDP("udp", nil, addr)
if err != nil {
log.Printf("DialUDP(%s): %s\n", IPAD_ADDR, err.Error())
return
}
go heartBeatSender()
ahrsReader := bufio.NewReader(ahrsfp)
gpsReader := bufio.NewReader(gpsfp)
lastTs := ahrsIdx
for {
gps, gpsIdx := getGPS(gpsReader)
ahrs, ahrsIdx := getAHRS(ahrsReader)
// Correct for drift between the samples.
drift := int64(math.Abs(float64(ahrsIdx - gpsIdx)))
// fmt.Printf("drift: %d\n", drift)
if drift >= 200000000 {
// There's a problem. One of the files is ahead of the other by more than 0.10s.
if gpsIdx > ahrsIdx { // GPS got ahead of AHRS? When does this happen?
// fmt.Printf("GPS sample ahead of AHRS - correcting\n")
for gpsIdx - ahrsIdx >= 200000000 {
ln, nidx := getAHRS(ahrsReader)
ahrsIdx = nidx
ahrs = ln
}
} else { // AHRS got ahead of GPS? This usually happens.
for ahrsIdx - gpsIdx >= 200000000 {
// fmt.Printf("AHRS sample ahead of GPS - correcting\n")
ln, nidx := getGPS(gpsReader)
gpsIdx = nidx
gps = ln
}
}
}
myGPS = gps
fmt.Printf("matchy: %d, %d\n", ahrs.Timestamp, gps.Timestamp)
pitch := ahrs.FusedEuler[0] * (180.0 / math.Pi)
roll := -ahrs.FusedEuler[1] * (180.0 / math.Pi)
if cal_num < 20 { // Average the first 5 measurements and call this "level".
cal_pitch = ((cal_pitch * float64(cal_num)) + pitch) / float64(cal_num + 1)
cal_roll = ((cal_roll * float64(cal_num)) + roll) / float64(cal_num + 1)
cal_num++
}
// Apply the calibration values.
pitch -= cal_pitch
roll -= cal_roll
fmt.Printf("%f %f\n", pitch, roll)
s := fmt.Sprintf("XATTStratux,%f,%f,%f", gps.Course, pitch, roll)
outConn.Write([]byte(s))
time.Sleep(time.Duration((ahrs.Timestamp - lastTs)/int64(replayspeed)))
lastTs = ahrs.Timestamp
// Now we're working with synced samples.
}
}

Plik diff jest za duży Load Diff

Plik binarny nie jest wyświetlany.

Wyświetl plik

@ -1 +0,0 @@
START,Wed Sep 23 22:08:32 +0000 UTC 2015

Plik binarny nie jest wyświetlany.

Plik binarny nie jest wyświetlany.

134
test/es_dump_csv.go 100644
Wyświetl plik

@ -0,0 +1,134 @@
package main
import (
"database/sql"
"encoding/csv"
"encoding/json"
"fmt"
_ "github.com/mattn/go-sqlite3"
"os"
"time"
)
type dump1090Data struct {
Icao_addr uint32
DF int // Mode S downlink format.
CA int // Lowest 3 bits of first byte of Mode S message (DF11 and DF17 capability; DF18 control field, zero for all other DF types)
TypeCode int // Mode S type code
SubtypeCode int // Mode S subtype code
SBS_MsgType int // type of SBS message (used in "old" 1090 parsing)
SignalLevel float64 // Decimal RSSI (0-1 nominal) as reported by dump1090-mutability. Convert to dB RSSI before setting in TrafficInfo.
Tail *string
Squawk *int // 12-bit squawk code in octal format
Emitter_category *int
OnGround *bool
Lat *float32
Lng *float32
Position_valid bool
NACp *int
Alt *int
AltIsGNSS bool //
GnssDiffFromBaroAlt *int16 // GNSS height above baro altitude in feet; valid range is -3125 to 3125. +/- 3138 indicates larger difference.
Vvel *int16
Speed_valid bool
Speed *uint16
Track *uint16
Timestamp time.Time // time traffic last seen, UTC
}
func main() {
if len(os.Args) < 2 {
fmt.Printf("es_dump_csv <sqlite file>\n")
return
}
db, err := sql.Open("sqlite3", os.Args[1])
if err != nil {
fmt.Printf("sql.Open(): %s\n", err.Error())
return
}
defer db.Close()
rows, err := db.Query("SELECT Data FROM es_messages")
if err != nil {
fmt.Printf("db.Exec(): %s\n", err.Error())
return
}
defer rows.Close()
csvOut := make([][]string, 0)
for rows.Next() {
var Data string
if err := rows.Scan(&Data); err != nil {
fmt.Printf("rows.Scan(): %s\n", err.Error())
continue
}
var d dump1090Data
err := json.Unmarshal([]byte(Data), &d)
if err != nil {
fmt.Printf("json.Unmarshal(): %s\n", err.Error())
continue
}
r := make([]string, 23)
r[0] = fmt.Sprintf("%06x", d.Icao_addr)
r[1] = fmt.Sprintf("%d", d.DF)
r[2] = fmt.Sprintf("%d", d.CA)
r[3] = fmt.Sprintf("%d", d.TypeCode)
r[4] = fmt.Sprintf("%d", d.SubtypeCode)
r[5] = fmt.Sprintf("%d", d.SBS_MsgType)
r[6] = fmt.Sprintf("%f", d.SignalLevel)
if d.Tail != nil {
r[7] = fmt.Sprintf("%s", *d.Tail)
}
if d.Squawk != nil {
r[8] = fmt.Sprintf("%d", *d.Squawk)
}
if d.Emitter_category != nil {
r[9] = fmt.Sprintf("%d", *d.Emitter_category)
}
if d.OnGround != nil {
r[10] = fmt.Sprintf("%t", *d.OnGround)
}
if d.Lat != nil {
r[11] = fmt.Sprintf("%f", *d.Lat)
}
if d.Lng != nil {
r[12] = fmt.Sprintf("%f", *d.Lng)
}
r[13] = fmt.Sprintf("%t", d.Position_valid)
if d.NACp != nil {
r[14] = fmt.Sprintf("%d", *d.NACp)
}
if d.Alt != nil {
r[15] = fmt.Sprintf("%d", *d.Alt)
}
r[16] = fmt.Sprintf("%t", d.AltIsGNSS)
if d.GnssDiffFromBaroAlt != nil {
r[17] = fmt.Sprintf("%d", *d.GnssDiffFromBaroAlt)
}
if d.Vvel != nil {
r[18] = fmt.Sprintf("%d", *d.Vvel)
}
r[19] = fmt.Sprintf("%t", d.Speed_valid)
if d.Speed != nil {
r[20] = fmt.Sprintf("%d", *d.Speed)
}
if d.Track != nil {
r[21] = fmt.Sprintf("%d", *d.Track)
}
r[22] = fmt.Sprintf("%s", d.Timestamp)
csvOut = append(csvOut, r)
}
w := csv.NewWriter(os.Stdout)
w.WriteAll(csvOut)
if err := rows.Err(); err != nil {
fmt.Printf("rows.Scan(): %s\n", err.Error())
return
}
}

173
test/icao2reg.go 100644
Wyświetl plik

@ -0,0 +1,173 @@
/*
icao2reg: Converts a 24-bit numeric value to a tail number of FAA
or Canadian registry.
(c) 2016 AvSquirrel
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package main
import (
"fmt"
"os"
"strconv"
)
func main() {
icao := uint32(0xAC82EC)
args := os.Args
if len(args) > 1 {
code, err := strconv.ParseInt(args[1], 16, 32)
if err != nil {
fmt.Printf("Error parsing argument %s. Input should be 24-bit hexadecimal, e.g. 'A00001'\n", args[1])
fmt.Printf("Showing example decoding for Mode S code %X,\n", icao)
} else {
icao = uint32(code)
}
} else {
fmt.Printf("Usage: ./icao2faa [code], where [code] is a 24-bit hexadecimal string, e.g. A00001\n")
fmt.Printf("Showing example decoding for Mode S code %X,\n", icao)
}
tail, valid := icao2reg(icao)
if valid {
fmt.Printf("ICAO %X successfully decodes as %s\n", icao, tail)
} else {
fmt.Printf("ICAO %X did not successfully decode. Response is `%s`\n", icao, tail)
}
}
func icao2reg(icao_addr uint32) (string, bool) {
// Initialize local variables
base34alphabet := string("ABCDEFGHJKLMNPQRSTUVWXYZ0123456789")
nationalOffset := uint32(0xA00001) // default is US
tail := ""
nation := ""
// Determine nationality
if (icao_addr >= 0xA00001) && (icao_addr <= 0xAFFFFF) {
nation = "US"
} else if (icao_addr >= 0xC00001) && (icao_addr <= 0xC3FFFF) {
nation = "CA"
} else {
//TODO: future national decoding.
return "NON-NA", false
}
if nation == "CA" { // Canada decoding
// First, discard addresses that are not assigned to aircraft on the civil registry
if icao_addr > 0xC0CDF8 {
//fmt.Printf("%X is a Canada aircraft, but not a CF-, CG-, or CI- registration.\n", icao_addr)
return "CA-MIL", false
}
nationalOffset := uint32(0xC00001)
serial := int32(icao_addr - nationalOffset)
// Fifth letter
e := serial % 26
// Fourth letter
d := (serial / 26) % 26
// Third letter
c := (serial / 676) % 26 // 676 == 26*26
// Second letter
b := (serial / 17576) % 26 // 17576 == 26*26*26
b_str := "FGI"
fmt.Printf("B = %d, C = %d, D = %d, E = %d\n", b, c, d, e)
tail = fmt.Sprintf("C-%c%c%c%c", b_str[b], c+65, d+65, e+65)
}
if nation == "US" { // FAA decoding
// First, discard addresses that are not assigned to aircraft on the civil registry
if icao_addr > 0xADF7C7 {
//fmt.Printf("%X is a US aircraft, but not on the civil registry.\n", icao_addr)
return "US-MIL", false
}
serial := int32(icao_addr - nationalOffset)
// First digit
a := (serial / 101711) + 1
// Second digit
a_remainder := serial % 101711
b := ((a_remainder + 9510) / 10111) - 1
// Third digit
b_remainder := (a_remainder + 9510) % 10111
c := ((b_remainder + 350) / 951) - 1
// This next bit is more convoluted. First, figure out if we're using the "short" method of
// decoding the last two digits (two letters, one letter and one blank, or two blanks).
// This will be the case if digit "B" or "C" are calculated as negative, or if c_remainder
// is less than 601.
c_remainder := (b_remainder + 350) % 951
var d, e int32
if (b >= 0) && (c >= 0) && (c_remainder > 600) { // alphanumeric decoding method
d = 24 + (c_remainder-601)/35
e = (c_remainder - 601) % 35
} else { // two-letter decoding method
if (b < 0) || (c < 0) {
c_remainder -= 350 // otherwise " " == 350, "A " == 351, "AA" == 352, etc.
}
d = (c_remainder - 1) / 25
e = (c_remainder - 1) % 25
if e < 0 {
d -= 1
e += 25
}
}
a_char := fmt.Sprintf("%d", a)
var b_char, c_char, d_char, e_char string
if b >= 0 {
b_char = fmt.Sprintf("%d", b)
}
if b >= 0 && c >= 0 {
c_char = fmt.Sprintf("%d", c)
}
if d > -1 {
d_char = string(base34alphabet[d])
if e > 0 {
e_char = string(base34alphabet[e-1])
}
}
tail = "N" + a_char + b_char + c_char + d_char + e_char
}
return tail, true
}

Wyświetl plik

@ -1,27 +1,25 @@
package main
import (
"fmt"
// "time"
// "time"
"../uatparse"
"os"
"bufio"
"gonum.org/v1/plot"
"gonum.org/v1/plot/plotter"
"gonum.org/v1/plot/plotutil"
"gonum.org/v1/plot/vg"
"os"
"sort"
"strconv"
"strings"
"unicode"
"strconv"
"github.com/gonum/plot"
"github.com/gonum/plot/plotter"
"github.com/gonum/plot/plotutil"
"github.com/gonum/plot/vg"
"sort"
)
const (
UPLINK_FRAME_DATA_BYTES = 432
)
/*
From AC 00-45G [http://www.faa.gov/documentLibrary/media/Advisory_Circular/AC_00-45G_CHG_1-2.pdf]
@ -51,29 +49,28 @@ Winds Aloft 12 hours 10 minutes
*/
func append_metars(rawUplinkMessage string, curMetars []string) []string {
func append_metars(rawUplinkMessage string, curMetars []string) []string {
ret := curMetars
uatMsg, err := uatparse.New(rawUplinkMessage)
if err != nil {
return ret
}
//fmt.Printf("*************************\n")
//fmt.Printf("*************************\n")
metars, _ := uatMsg.GetTextReports()
for _, v := range metars {
//fmt.Printf("EE: %s\n", v)
//fmt.Printf("EE: %s\n", v)
vSplit := strings.Split(v, " ")
if vSplit[0] != "METAR" || len(vSplit) < 3 { // Only looking for METARs.
continue
}
ret = append(ret, v)
}
//fmt.Printf("=========================\n")
//fmt.Printf("=========================\n")
return ret
}
/*
Average number of METARs received for an airport for which you first received a METAR in the first 5 minutes, over 10 minutes. Divided by two.
*/
@ -97,7 +94,7 @@ func metar_qos_one_period(a, b []string) float64 {
ret += float64(num)
}
if len(numMetarByIdent) > 0 {
ret = ret / float64(2 * len(numMetarByIdent))
ret = ret / float64(2*len(numMetarByIdent))
}
return ret
}
@ -124,7 +121,7 @@ func main() {
if err != nil {
break
}
buf = strings.TrimFunc(buf, func(r rune) bool {return unicode.IsControl(r)})
buf = strings.TrimFunc(buf, func(r rune) bool { return unicode.IsControl(r) })
linesplit := strings.Split(buf, ",")
if len(linesplit) < 2 { // Blank line or invalid.
continue
@ -132,9 +129,9 @@ func main() {
if linesplit[0] == "START" { // Reset ticker, new start.
//TODO: Support multiple sessions.
// Reset the counters, new session.
// qos = make(map[uint]float64)
// curWindowMetars = make([]string, 0)
// curWindow = 0
// qos = make(map[uint]float64)
// curWindowMetars = make([]string, 0)
// curWindow = 0
windowOffset = curWindow
} else { // If it's not "START", then it's a tick count.
i, err := strconv.ParseInt(linesplit[0], 10, 64)
@ -145,17 +142,17 @@ func main() {
// Window number in current session.
wnum := int64(i / (5 * 60 * 1000000000))
// fmt.Printf("%d\n", curWindow)
if wnum + windowOffset != curWindow { // Switched over.
// fmt.Printf("%d\n", curWindow)
if wnum+windowOffset != curWindow { // Switched over.
curWindow = wnum + windowOffset
beforeLastWindowMetars, ok := metarsByWindow[curWindow - 2]
lastWindowMetars, ok2 := metarsByWindow[curWindow - 1]
beforeLastWindowMetars, ok := metarsByWindow[curWindow-2]
lastWindowMetars, ok2 := metarsByWindow[curWindow-1]
if ok && ok2 {
// fmt.Printf("%v\n\n\nheyy\n\n%v\n", beforeLastWindowMetars, lastWindowMetars)
qos[curWindow - 1] = metar_qos_one_period(beforeLastWindowMetars, lastWindowMetars)
fmt.Printf("qos=%f\n", qos[curWindow - 1])
delete(metarsByWindow, curWindow - 2)
delete(metarsByWindow, curWindow - 1)
// fmt.Printf("%v\n\n\nheyy\n\n%v\n", beforeLastWindowMetars, lastWindowMetars)
qos[curWindow-1] = metar_qos_one_period(beforeLastWindowMetars, lastWindowMetars)
fmt.Printf("qos=%f\n", qos[curWindow-1])
delete(metarsByWindow, curWindow-2)
delete(metarsByWindow, curWindow-1)
}
}
metarsByWindow[curWindow] = append_metars(linesplit[1], metarsByWindow[curWindow])
@ -180,7 +177,7 @@ func main() {
pts := make(plotter.XYs, len(qos))
i := 0
for _,k := range keys {
for _, k := range keys {
v := qos[int64(k)]
fmt.Printf("%d, %f\n", k, v)
pts[i].X = float64(k)
@ -192,7 +189,7 @@ func main() {
if err != nil {
panic(err)
}
if err := p.Save(4 * vg.Inch, 4 * vg.Inch, "qos.png"); err != nil {
if err := p.Save(4*vg.Inch, 4*vg.Inch, "qos.png"); err != nil {
panic(err)
}
}

Wyświetl plik

@ -0,0 +1,3 @@
all:
gcc -o metar_to_text src/*.c

Wyświetl plik

@ -0,0 +1,382 @@
/* ref: http://limulus.net/mdsplib */
/*
METAR Decoder Software Package Library: Parses Aviation Routine Weather Reports
Copyright (C) 2003 Eric McCarthy
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/********************************************************************/
/* */
/* Title: metar.h */
/* Organization: W/OSO242 - GRAPHICS AND DISPLAY SECTION */
/* Date: 19 Jan 1996 */
/* Programmer: CARL MCCALLA */
/* Language: C/370 */
/* */
/* Abstract: METAR Decoder Header File. */
/* */
/* Modification History: */
/* 7 Jul 2001 by Eric McCarthy: Made suitable for */
/* use as header for the metar.a library. */
/* */
/********************************************************************/
/* Used in the METAR structs. */
typedef unsigned short int MDSP_BOOL;
/*********************************************/
/* */
/* RUNWAY VISUAL RANGE STRUCTURE DECLARATION */
/* AND VARIABLE TYPE DEFINITION */
/* */
/*********************************************/
typedef struct runway_VisRange {
char runway_designator[6];
MDSP_BOOL vrbl_visRange;
MDSP_BOOL below_min_RVR;
MDSP_BOOL above_max_RVR;
int visRange;
int Max_visRange;
int Min_visRange;
} Runway_VisRange;
/***********************************************/
/* */
/* DISPATCH VISUAL RANGE STRUCTURE DECLARATION */
/* AND VARIABLE TYPE DEFINITION */
/* */
/***********************************************/
typedef struct dispatch_VisRange {
MDSP_BOOL vrbl_visRange;
MDSP_BOOL below_min_DVR;
MDSP_BOOL above_max_DVR;
int visRange;
int Max_visRange;
int Min_visRange;
} Dispatch_VisRange;
/*****************************************/
/* */
/* CLOUD CONDITION STRUCTURE DECLARATION */
/* AND VARIABLE TYPE DEFINITION */
/* */
/*****************************************/
typedef struct cloud_Conditions {
char cloud_type[5];
char cloud_hgt_char[4];
char other_cld_phenom[4];
int cloud_hgt_meters;
} Cloud_Conditions;
/*****************************************/
/* */
/* WIND GROUP DATA STRUCTURE DECLARATION */
/* AND VARIABLE TYPE DEFINITION */
/* */
/*****************************************/
typedef struct windstruct {
char windUnits[ 4 ];
MDSP_BOOL windVRB;
int windDir;
int windSpeed;
int windGust;
} WindStruct;
/*****************************************/
/* */
/* RECENT WX GROUP STRUCTURE DECLARATION */
/* AND VARIABLE TYPE DEFINITION */
/* */
/*****************************************/
typedef struct recent_wx {
char Recent_weather[ 5 ];
int Bhh;
int Bmm;
int Ehh;
int Emm;
} Recent_Wx;
/***************************************/
/* */
/* DECODED METAR STRUCTURE DECLARATION */
/* AND VARIABLE TYPE DEFINITION */
/* */
/***************************************/
typedef struct decoded_METAR {
char synoptic_cloud_type[ 6 ];
char snow_depth_group[ 6 ];
char codeName[ 6 ];
char stnid[5];
char horiz_vsby[5];
char dir_min_horiz_vsby[3];
char vsby_Dir[ 3 ];
char WxObstruct[10][8];
char autoIndicator[5];
char VSBY_2ndSite_LOC[10];
char SKY_2ndSite_LOC[10];
char SKY_2ndSite[10];
char SectorVsby_Dir[ 3 ];
char ObscurAloft[ 12 ];
char ObscurAloftSkyCond[ 12 ];
char VrbSkyBelow[ 4 ];
char VrbSkyAbove[ 4 ];
char LTG_DIR[ 3 ];
char CloudLow;
char CloudMedium;
char CloudHigh;
char CIG_2ndSite_LOC[10];
char VIRGA_DIR[3];
char TornadicType[15];
char TornadicLOC[10];
char TornadicDIR[4];
char TornadicMovDir[3];
char CHINO_LOC[6];
char VISNO_LOC[6];
char PartialObscurationAmt[2][7];
char PartialObscurationPhenom[2][12];
char SfcObscuration[6][10];
char charPrevailVsby[12];
char charVertVsby[10];
char TS_LOC[3];
char TS_MOVMNT[3];
MDSP_BOOL Indeterminant3_6HrPrecip;
MDSP_BOOL Indeterminant_24HrPrecip;
MDSP_BOOL CIGNO;
MDSP_BOOL SLPNO;
MDSP_BOOL ACFTMSHP;
MDSP_BOOL NOSPECI;
MDSP_BOOL FIRST;
MDSP_BOOL LAST;
MDSP_BOOL SunSensorOut;
MDSP_BOOL AUTO;
MDSP_BOOL COR;
MDSP_BOOL NIL_rpt;
MDSP_BOOL CAVOK;
MDSP_BOOL RVRNO;
MDSP_BOOL A_altstng;
MDSP_BOOL Q_altstng;
MDSP_BOOL VIRGA;
MDSP_BOOL VOLCASH;
MDSP_BOOL GR;
MDSP_BOOL CHINO;
MDSP_BOOL VISNO;
MDSP_BOOL PNO;
MDSP_BOOL PWINO;
MDSP_BOOL FZRANO;
MDSP_BOOL TSNO;
MDSP_BOOL DollarSign;
MDSP_BOOL PRESRR;
MDSP_BOOL PRESFR;
MDSP_BOOL Wshft_FROPA;
MDSP_BOOL OCNL_LTG;
MDSP_BOOL FRQ_LTG;
MDSP_BOOL CNS_LTG;
MDSP_BOOL CG_LTG;
MDSP_BOOL IC_LTG;
MDSP_BOOL CC_LTG;
MDSP_BOOL CA_LTG;
MDSP_BOOL DSNT_LTG;
MDSP_BOOL AP_LTG;
MDSP_BOOL VcyStn_LTG;
MDSP_BOOL OVHD_LTG;
MDSP_BOOL LightningVCTS;
MDSP_BOOL LightningTS;
int TornadicDistance;
int ob_hour;
int ob_minute;
int ob_date;
int minWnDir;
int maxWnDir;
int VertVsby;
int temp;
int dew_pt_temp;
int QFE;
int hectoPasc_altstng;
int char_prestndcy;
int minCeiling;
int maxCeiling;
int WshfTime_hour;
int WshfTime_minute;
int min_vrbl_wind_dir;
int max_vrbl_wind_dir;
int PKWND_dir;
int PKWND_speed;
int PKWND_hour;
int PKWND_minute;
int SKY_2ndSite_Meters;
int Ceiling;
int Estimated_Ceiling;
int SNINCR;
int SNINCR_TotalDepth;
int SunshineDur;
int ObscurAloftHgt;
int VrbSkyLayerHgt;
int Num8thsSkyObscured;
int CIG_2ndSite_Meters;
int snow_depth;
int BTornadicHour;
int BTornadicMinute;
int ETornadicHour;
int ETornadicMinute;
float SectorVsby;
float WaterEquivSnow;
float VSBY_2ndSite;
float prevail_vsbySM;
float prevail_vsbyM;
float prevail_vsbyKM;
float prestndcy;
float precip_amt;
float precip_24_amt;
float maxtemp;
float mintemp;
float max24temp;
float min24temp;
float minVsby;
float maxVsby;
float hourlyPrecip;
float TWR_VSBY;
float SFC_VSBY;
float Temp_2_tenths;
float DP_Temp_2_tenths;
float SLP;
float GR_Size;
double inches_altstng;
Runway_VisRange RRVR[12];
Dispatch_VisRange DVR;
Recent_Wx ReWx[3];
WindStruct winData;
Cloud_Conditions cldTypHgt[6];
} Decoded_METAR;
/********************************************************************/
/* */
/* Title: DcdMETAR */
/* Organization: W/OSO242 - GRAPHICS AND DISPLAY SECTION */
/* Date: 14 Sep 1994 */
/* Programmer: CARL MCCALLA */
/* Language: C/370 */
/* */
/* Abstract: DcdMETAR takes a pointer to a METAR report char- */
/* acter string as input, decodes the report, and */
/* puts the individual decoded/parsed groups into */
/* a structure that has the variable type */
/* Decoded_METAR. */
/* */
/* Input: string - a pointer to a METAR report character */
/* string. */
/* */
/* Output: Mptr - a pointer to a structure that has the */
/* variable type Decoded_METAR. */
/* */
/* Modification History: */
/* 3 Jul 2001 by Eric McCarthy: Added stringCpy */
/* so cosnt char *'s could be passed in. */
/* */
/********************************************************************/
int DcdMETAR( char *string , Decoded_METAR *Mptr );
/********************************************************************/
/* */
/* Title: prtDMETR */
/* Organization: W/OSO242 - GRAPHICS AND DISPLAY SECTION */
/* Date: 15 Sep 1994 */
/* Programmer: CARL MCCALLA */
/* Language: C/370 */
/* */
/* Abstract: prtDMETR prints, in order of the ASOS METAR */
/* format, all non-initialized members of the structure */
/* addressed by the Decoded_METAR pointer. */
/* */
/* External Functions Called: */
/* None. */
/* */
/* Input: Mptr - ptr to a decoded_METAR structure. */
/* */
/* Output: NONE */
/* */
/* Modification History: */
/* None. */
/* */
/********************************************************************/
void prtDMETR( Decoded_METAR *Mptr );
/********************************************************************/
/* */
/* Title: dcdNetMETAR */
/* Date: 24 Jul 2001 */
/* Programmer: Eric McCarthy */
/* Language: C */
/* */
/* Abstract: dcdNetMETAR */
/* The METARs supplied by the NWS server need to */
/* be reformatted before they can be sent through */
/* dcdMETAR. This calls dcdMETAR on the correctly */
/* formated METAR. */
/* */
/* Input: a pointer to a METAR string from a NWS server */
/* */
/* Output: Mptr - a pointer to a structure that has the */
/* variable type Decoded_METAR. */
/* */
/* Modification History: */
/* None. */
/* */
/********************************************************************/
int dcdNetMETAR (char *string, Decoded_METAR *Mptr);
/********************************************************************/
/* */
/* Title: sprint_metar */
/* Date: 24 Jul 2001 */
/* Programmer: Eric McCarthy */
/* Language: C */
/* */
/* Abstract: sprtDMETR */
/* Does what prtDMETR does, but into a string. */
/* */
/* Input: string containing the printout, decoded METAR */
/* */
/* Modification History: */
/* None. */
/* */
/********************************************************************/
void sprint_metar( char *string, Decoded_METAR *Mptr );

Wyświetl plik

@ -0,0 +1,92 @@
/*
METAR Decoder Software Package Library: Parses Aviation Routine Weather Reports
Copyright (C) 2003 Eric McCarthy
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#pragma comment(compiler)
#pragma comment(date)
#pragma comment(timestamp)
#include <stdlib.h>
#pragma title("antoi - char array to integer")
#pragma pagesize (80)
#pragma page(1)
/********************************************************************/
/* */
/* Title: antoi */
/* Date: Jan 28, 1991 */
/* Organization: W/OSO242 - Graphics and Display Section */
/* Programmer: Allan Darling */
/* Language: C/370 */
/* */
/* Abstract: This function will convert a character array */
/* (string) of length (len) into an integer. */
/* The integer is created via a call to the */
/* function atoi. This function extends the */
/* functionality of atoi by removing the */
/* requirement for a sentinal delimited string */
/* as input. */
/* */
/* Input: - Pointer to an array of characters. */
/* - Integer indicating the number of character to include */
/* in the conversion. */
/* */
/* Output:- An integer corresponding to the value in the character */
/* array or MAXNEG (-2147483648) if the function is */
/* unable to acquire system storage. */
/* */
/* Modification History: */
/* None */
/* */
/********************************************************************/
int antoi(char * string, int len)
{
/*******************/
/* local variables */
/*******************/
char * tmpstr;
int i,
retval;
/*****************/
/* function body */
/*****************/
tmpstr = malloc((len+1) * sizeof(char));
if (tmpstr == NULL) return (-2147483648);
for (i = 0; i < len; i++)
tmpstr[i] = string[i];
tmpstr[len] = '\0';
retval = atoi(tmpstr);
free(tmpstr);
return(retval);
} /* end antoi */
#pragma page(1)

Wyświetl plik

@ -0,0 +1,191 @@
/*
METAR Decoder Software Package Library: Parses Aviation Routine Weather Reports
Copyright (C) 2003 Eric McCarthy
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#pragma comment (compiler)
#pragma comment (date)
#pragma comment (timestamp)
#pragma pagesize(80)
#include "local.h" /* standard header file */
#pragma subtitle(" ")
#pragma page(1)
#pragma subtitle("charcmp - characters compare with patterns ")
/********************************************************************/
/* */
/* Title: charcmp */
/* Organization: W/OSO242 - GRAPHICS AND DISPLAY SECTION */
/* Date: 12 Dec 1995 */
/* Programmer: CINDY L. CHONG */
/* Language: C/370 */
/* */
/* Abstract: This function will compare each character in the */
/* string match with each character in the pattern */
/* which is made up of characters. The str can */
/* be longer than the pattern. */
/* */
/* External Functions Called: */
/* None. */
/* */
/* Input: str is a pointer to char */
/* pattern is a pointer to char */
/* */
/* Output: Return true if str matches pattern, */
/* otherwise, return false */
/* */
/* Modification History: */
/* None. */
/* */
/********************************************************************/
#pragma page(1)
MDSP_BOOL charcmp(char *str, char *pattern)
{
/**********************************************************/
/* Loop while str and pattern is not equal to null, then */
/* inscreases str and pattern by one */
/**********************************************************/
for (; *pattern != '\0'; pattern++)
{
if (*str == '\0')
return FALSE;
/************************************************************/
/* If pattern match str, then increase str and jump out the */
/* case and read next char of the str and pattern */
/************************************************************/
if ( isspace(*pattern) )
pattern = nxtalpha(pattern);
switch( *pattern )
{
case 'c':
if ( !isalnum(*str++) )
{
return FALSE;
}
break;
case 'a':
if ( !isalpha(*str) )
{
return FALSE;
}
str++;
break;
case 'n':
if ( !iscntrl(*str++) )
{
return FALSE;
}
break;
case 'd':
if ( !isdigit(*str) )
{
return FALSE;
}
str++;
break;
case 'g':
if ( !isgraph(*str++) )
{
return FALSE;
}
break;
case 'i':
if ( !islower(*str++) )
{
return FALSE;
}
break;
case 'p':
if ( !isprint(*str++) )
{
return FALSE;
}
break;
case 't':
if ( !ispunct(*str++) )
{
return FALSE;
}
break;
case 'w':
if ( !isspace(*str++) )
{
return FALSE;
}
break;
case 'u':
if ( !isupper(*str++) )
{
return FALSE;
}
break;
case 's':
if (*str++ != ' ')
{
return FALSE;
}
break;
case 'm':
if ( !isspace(*str) )
{
return FALSE;
}
else
{
while ( isspace(*str) )
str++;
}
break;
case '\'':
pattern++;
if (*pattern != *str)
{
return FALSE;
}
pattern++;
str++;
break;
default:
return FALSE;
} /* end switch */
} /* end for */
return (TRUE);
}

Wyświetl plik

@ -0,0 +1,685 @@
/*
METAR Decoder Software Package Library: Parses Aviation Routine Weather Reports
Copyright (C) 2003 Eric McCarthy
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "metar_structs.h"
#ifdef SYNOPTIC
char *BldSynop( Decoded_METAR * , char * );
/*char *Sec0MeSm(Decoded_METAR *);*/
/*char *Sec1MeSm(Decoded_METAR *, char *);*/
/*char *Sec3MeSm(Decoded_METAR *, char *);*/
/*char *Sec5MeSm(Decoded_METAR *, char *);*/
#endif
void prtDMETR( Decoded_METAR *);
int DcdMETAR( char *, Decoded_METAR * );
#pragma page(1)
#pragma subtitle(" ")
#pragma subtitle("subtitle - description ")
/********************************************************************/
/* */
/* Title: dRVMETAR */
/* Organization: W/OSO242 - GRAPHICS AND DISPLAY SECTION */
/* Date: 28 Oct 1994 */
/* Programmer: CARL MCCALLA */
/* Language: C/370 */
/* */
/* Abstract: DRVMETAR is a main routine that acts a driver */
/* for testing the METAR Decoder function. */
/* */
/* External Functions Called: */
/* None. */
/* DcdMETAR */
/* prtDcdMetar */
/* Sec0MTSm */
/* Sec1MTSm */
/* */
/* Input: None */
/* */
/* Output: None */
/* */
/* Modification History: */
/* None. */
/* */
/********************************************************************/
#pragma page(1)
main()
{
static char *string[] =
{
"KMKG 18022G29KT 3SM BR BKN018 BR 24/22 A2995 RMK A02 VIS 2",
"KPIT 132351Z 33013KT 4SM +TSRA BR BKN018CB OVC031 12/11 A2977 RMK "
"AO2 PK WND 31041/2305 WSHFT 2300 PRESSRR SLP090 FRQ LTGCGCC OHD "
"TS OHD MOV E CB OHD MOV E 8/3// P0051 60052 T01170111 10222 20122 "
"53030",
"KCAK 132351Z 28016G22KT 10SM BKN021 OVC030 11/09 A2981 RMK AO2 "
"TSE00RAE10 PRESRR SLP093 TS MOV NE CIG RGD 8/5// P0002 60066 "
"T01110094 10217 20111 51053",
"KBUF 132354Z 21007KT 3SM +TSRA BR FEW009 OVC 12/11 A2959 RMK "
"AO2 PRESFR SLP021 8/9// TS ALQDS MOV E OCNL LTGICCCCG P0031 "
"60073 T01170111 10233 20111 50000 0",
"KPIT 132356Z 32012G21KT 4SM TSRA BR BKN018CB OVC031 12/11 A2978 "
"RMK AO2 WSHFT 2338 PRESFR FRQ LTGCGCC OHD TS OHD MOV E CB OHD MOV "
"E P0001",
"KCAK 132358Z 28015G22KT 10SM BKN013 OVC023 11/10 A2982 RMK AO2",
"KBUF 140001Z 22008KT 3SM +TSRA BR BKN009 BKN013 OVC022 12/12 A2959 "
"RMK AO2 P0003",
"KRIL 031853Z AUTO 33008KT 10SM SCT022 BKN032 OVC060 07/01 A3004 "
"RMK AO2 SLP157 T00720006 TSNO",
"METAR KCLE 091657Z COR 35021KT 3SM -PL SHPL VV004 M03/M04 A2964 "
"RMK VIS S M1/4=",
"METAR KCLE 091657Z COR 35021KT 3SM -PE SHPE VV004 M03/M04 A2964 "
"RMK VIS S M1/4=",
"METAR KCLE 091657Z COR 35021KT 3SM -PE TSPL VV004 M03/M04 A2964 "
"RMK VIS S M1/4=",
"METAR KCLE 091657Z COR 35021KT 3SM -PL TSPE VV004 M03/M04 A2964 "
"RMK VIS S M1/4=",
"KMLB 200450Z 18006KT 7SM OVC100 23/22 A2986 RMK FQT LTGIG W-N",
"KMLB 200450Z 18006KT 7SM OVC100 23/22 A2986 RMK FQT LTGIG W-N=",
"KMLB 200450Z 18006KT 7SM OVC100 23/22 A2986 RMK FRQ LTGIC NW",
"KMLB 200450Z 18006KT 7SM OVC100 23/22 A2986 RMK FRQ LTGCC NW=",
"SPECI KEKO 151609Z 00000KT 5SM BR FEW003 SCT013 M04/M06 A3018 "
"RMK VIS N-NE M1/4",
"KPIT 1935Z 22015G25KT 1 3/4SM R22L/2700FT "
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB 18/MM A2992",
"KPIT 1935Z 22015G25KT 1 3/4SM R22L/2700FT "
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB MM/M12 A2992",
"METAR KLAX 281156Z AUTO VRB100G135KT 130V210 3 9999 "
"R15L/0500FT R22L/2700FT R16/1200FT R34/1000V1600FT R01L/P6000FT FC "
"+TS VCTS FEW/// SCT000 BKN050 SCT150 OVC250 3/M1 A2991 RMK "
"TORNADO B13 DSNT NE A01 PK WND 18515/45 "
"WSHFT 1350 FROPA TWR VIS 1 1/2 SFC VIS 1/4 VIS 1/4V1 1/4 "
"VIS 2 1/2 RWY11 "
"DVR/1000V1600FT "
"SHRAB05E30SHSNB20E55 FZDZB1057E1059 CIG 1000V1500 CIG 020 RWY11 "
"PRESFR PRESRR SLP013 FG FEW/// HZ SCT000 VIS NW 2 1/2 GR 3/4 "
"VIRGA SE -XRAFG3 CIGE005 BKN014 V OVC "
"FU BKN020 NOSPECI LAST 8/365 SNINCR 2/10 4/178 "
"933125 98096 P0125 60225 70565 "
"T00261015 10369 21026 "
"404800360 52101 VISNO RWY05 CHINO RWY27 PNO RVRNO "
"PWINO FZRANO TSNO $",
"METAR KAFF 091657Z COR 35021KT 3SM -SG BR VV004 M03/M04 A2964 "
"RMK SLP046 ESTMD SLP VIS SW-NW 2 "
"PWINO FZRANO TSNO $",
"METAR KAFF 091657Z COR 35021KT 3SM -SG BR VV004 M03/M04 A2964 "
"RMK SLP046 ESTMD SLP VIS SW-NW 2 1/2 "
"PWINO FZRANO TSNO $",
"METAR KAFF 091657Z COR 35021KT 3SM -SG BR VV004 M03/M04 A2964 "
"RMK SLP046 ESTMD SLP VIS SW-NW 2",
"METAR KAFF 091657Z COR 35021KT 3SM -SG BR VV004 M03/M04 A2964 "
"RMK SLP046 ESTMD SLP VIS SW-NW 2 1/2=",
"METAR KAFF 091657Z COR 35021KT 3SM -SG BR VV004 M03/M04 A2964 "
"RMK SLP046 ESTMD SLP VIS SW-NW 2",
"METAR KAFF 091657Z COR 35021KT 3SM -SG BR VV004 M03/M04 A2964 "
"RMK CIG 003V026 SLP046 ESTMD SLP VIS SW-NW 2",
"METAR KAFF 091657Z COR 35021KT 3SM -SG BR VV004 M03/M04 A2964 "
"RMK VIS S 2",
"SPECI KEKO 151609Z 00000KT 5SM BR FEW003 SCT013 M04/M06 A3018 "
"RMK VIS N-NE 1",
"KPIT 1935Z 22015G25KT 1 3/4SM R22L/2700FT "
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB 18/MM A2992",
"KPIT 1935Z 22015G25KT 1 3/4SM R22L/2700FT "
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB MM/M12 A2992",
"KPIT 1935Z 22015G25KT 1 3/4SM R22L/2700FT "
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB M18/MM A2992",
"METAR KAFF 091657Z COR 35021KT 3SM -SG BR VV004 M03/M04 A2964 "
"RMK CIG 003V026 SLP046 ESTMD SLP VIS SW-NW 2=",
"METAR KAFF 091657Z COR 35021KT 3SM -SG BR VV004 M03/M04 A2964 "
"RMK VIS S 2=",
"SPECI KEKO 151609Z 00000KT 5SM BR FEW003 SCT013 M04/M06 A3018 "
"RMK VIS N-NE 1=",
"METAR KAFF 091657Z COR 35021KT 3SM -SG BR VV004 M03/M04 A2964 "
"RMK SLP046 ESTMD SLP VIS SW-NW 2",
"METAR KAFF 091657Z COR 35021KT 3SM -SG BR VV004 M03/M04 A2964 "
"RMK CIG 003V026 SLP046 ESTMD SLP VIS SW-NW 2",
"METAR KAFF 091657Z COR 35021KT 3SM -SG BR VV004 M03/M04 A2964 "
"RMK VIS S 2",
"SPECI KEKO 151609Z 00000KT 5SM BR FEW003 SCT013 M04/M06 A3018 "
"RMK VIS N-NE 1",
"METAR KAFF 091657Z COR 35021KT 3SM -SG BR VV004 M03/M04 A2964 "
"RMK SLP046 ESTMD SLP VIS SW 2",
"METAR KAFF 091657Z COR 35021KT 3SM -SG BR VV004 M03/M04 A2964 "
"RMK CIG 003V026 SLP046 ESTMD SLP VIS NW 2",
"METAR KAFF 091657Z COR 35021KT 3SM -SG BR VV004 M03/M04 A2964 "
"RMK VIS S 2",
"SPECI KEKO 151609Z 00000KT 5SM BR FEW003 SCT013 M04/M06 A3018 "
"RMK VIS NE 1",
"KPIT 1935Z 22015G25KT 1/8SM R22L/2700FT "
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB 18/12 A2992",
"KPIT 1935Z 22015G25KT 6SM R22L/2700FT "
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB M12/M18 A2992",
"KPIT 1935Z 22015G25KT 8SM R22L/2700FT "
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB M18/12 A2992",
"KPIT 1935Z 22015G25KT 9SM R22L/2700FT "
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB 18/M01 A2992",
"KPIT 1935Z 22015G25KT 1 3/4SM R22L/2700FT "
"TSRA -DZ FG +SNPE SCT005TCU BKN010ACSL OVC250CB MM/12 A2992",
"KPIT 1935Z 22015G25KT 1 3/4SM R22L/2700FT "
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB 18/MM A2992",
"KPIT 1935Z 22015G25KT 1 3/4SM R22L/2700FT "
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB MM/M12 A2992",
"KPIT 1935Z 22015G25KT 1 3/4SM R22L/2700FT "
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB M18/MM A2992",
"KPIT 1935Z 22015G25KT 1 3/4SM R22L/2700FT "
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB MM/MM A2992",
"SPECI KGFI 041430Z 18045G56KT M1/4SM R15/0200FT FC +TS VV010 20/18 "
"A2900 RMK A02A PK WND 18056/28 OCNL LTG AP "
"RAB15E25TSB20 FCB1430 PRESFR "
"SLP 701 P 0254 T01990182",
"METAR KLAX 281156Z AUTO VRB100G135KT 130V210 3 9999 "
"R15L/0500FT R22L/2700FT R16/1200FT R34/1000V1600FT R01L/P6000FT FC "
"+TS VCTS FEW/// SCT000 BKN050 SCT150 OVC250 3/M1 A2991 RMK "
"TORNADO B13 DSNT NE A01 PK WND 18515/45 "
"WSHFT 1350 FROPA TWR VIS 1 1/2 SFC VIS 1/4 VIS 1/4V1 1/4 "
"VIS 2 1/2 RWY11 "
"DVR/1000V1600FT "
"SHRAB05E30SHSNB20E55 FZDZB1057E1059 CIG 1000V1500 CIG 020 RWY11 "
"PRESFR PRESRR SLP013 FG FEW/// HZ SCT000 VIS NW 2 1/2 GR 3/4 "
"VIRGA SE -XRAFG3 CIGE005 BKN014 V OVC "
"FU BKN020 NOSPECI LAST 8/365 SNINCR 2/10 4/178 "
"933125 98096 P0125 60225 70565 "
"T00261015 10369 21026 "
"404800360 52101 VISNO RWY05 CHINO RWY27 PNO RVRNO "
"PWINO FZRANO TSNO $",
"KP88 1919Z 09001KT 14/03 RMK AO / PKWND 002/RNO 158 Z T01440034",
"K40B 1924Z 29004KT 15/M07 RMK AO PKWND 011/RM MV263 T01501072",
"SPECI KGFI 041430Z COR 18045G56KT "
"M1/4SM R15/0200FT R01L/0600V1000FT R01L/M0600FT R27/P6000FT "
"+FC +TS -FZDZ VV010 04/M02 "
"A2900 RMK TORNADO B13 6 NE A02A PK WND 18056/28 WSHFT 30 FROPA "
"TWR VIS 1 1/2 VIS NE 2 1/2 VIS 2 1/2 RWY11 DVR/0600V1000FT "
"OCNL LTGICCG OVHD RAB15E25 TSB20 FCB1430 TS SE MOV NE GR 1 3/4 "
"VIRGA SW CIG 005V010 FG SCT000 BKN014 V OVC CB DSNT W "
"CIG 002 RWY11 PRESFR PRESRR "
"SLP701 ACFT MSHP NOSPECI SNINCR 2/10 FIRST "
"P0254 60217 70125 4/021 933036 8/903 98096 T00261015 "
"11021 21001 401120084 52032RVRNO PWINO PNO FZRANO TSNO "
"VISNO RWY06 CHINO RWY12 $",
"KPHX 281156Z 12004KT 16KM CLR 15/05 A2996 RMK AOA SLP135 T01500050 "
"10250 20150 53006",
"KFCA 281156Z 30003KT 10SM CLR 06/02 A3009 RMRK AO TNO $ SLP191 "
"T00610023 10167 20056 53003",
"KAST 281156Z 00000KT 10SM BKN095 09/08 A2997 REMARK AOA SLP150 "
"T00940084 10161 20094 52005 ",
"KHVR 281156Z 03003KT 10SM OVC020 09/07 A3010 REMARKS AO TNO ZRNO "
"$ SLP194 T00940073 10156 20089 51005",
"KGGW 281156Z 35006KT 5SM BR OVC010 10/09 A3003 RMK AOA $ SLP177 "
"70003 T01000095 10156 20110 53008",
"KELY 1153Z AUTO 14004KT 10SM SCT075 01/M01 A3011 RMK AOA TNO ZRNO "
"SLP171 70001 T00061011 10139 21006 51005",
"KFLG 281156Z 29006KT 10SM CLR 04/M01 A3012 RMK AO TNO SLP147 "
"T00391011 21006 51004",
"KGTF 281156Z 27005KT 7SM BKN080 04/04 A3010 RMK AOA SLP205 "
"T00440045 10117 20039 51006",
"KHLN 281156Z AUTO 27005KT 10SM OVC023 07/05 A3011 RMK AOA OVC V "
"BKN $ SLP202 60000 70001 T00670050 10122 20061 53003",
"K13A 1918Z 20011KT 26/M06 RMK AO PKWND 020/RNO 644V264 T02611061",
"KGGW 1756Z 33018KT 10SM OVC015 M03/M06 A3041 RMK AOA SLP338 "
"4/007 60002 T10281055 11028 21072 51009",
"KPHX 1756Z 130004KT 10SM CLR 18/M03 A3001 RMK AOA SLP154 "
"T01781033 10178 20067 58007",
"KFCA 1756Z 29005KT 10SM CLR 05/M11 A3049 RMK AOA TNO SLP352 "
"T00501111 10050 21044 50004",
"KAST 1756Z 01006KT 10SM CLR 11/04 A3047 RMK AOA SLP316 "
"T01110045 10111 20000 50002",
"KHVR 1756Z 31007KT 5SM -SN SCT011 BKN024 OVC030 M05/M08 A3056 "
"RMK AOA 933004 "
"BKN V SCT TNO P0000 $ SLP389 4/015 60002 "
"T10501077 11050 21078 51010",
"KELY 1753Z 34010KT 10SM CLR 01/M07 A3022 RMK AOA TNO FZRNO "
"SLP240 T00111066 10011 21078 58007",
"KFLG 1756Z 07006KT 10SM CLR 06/M12 A3009 RMK AO TNO FZRNO "
"SLP178 T00561122 10061 21100 58005",
"KGTF 1756Z 35010KT 1/2SM -SN FG VV09 M06/M08 A3051 RMK AOA "
"933004 SFC VSBY 3/4 "
"P0009 SLP393 60010 T10611077 11044 21067 53013",
"KHLN 1756Z 35012KT 10SM SCT032 OVC060 M02/M09 A3048 RMK AOA "
"SLP369 60000 T10171094 11017 21061 53006",
"KAST 1756Z 01006KT 10SM CLR 11/04 A3047 RMK AOA SLP316 61104 "
"71235 T01110045 10111 20000 401720056 58002",
"METAR KLAX 04281156Z AUTO VRB100G135KT 130V210 3 1/2SM "
"R15L/0500FT R22L/2700FT R16/1200FT R34/1000V1600FT R01L/P6000FT FC "
"+TS BLPY FEW000 BKN050 SCT150 OVC250 3/M1 A2991 RMK "
"TORNADO B13 DSNT NE A02 PK WND 18515/45 "
"WSHFT 1350 FROPA TWR VIS 1 1/2 SFC VIS 1/4 VIS 1/4V1 1/4 "
"VIS 2 1/2 RWY11 OCNL LTG VCY STN "
"RAB1030E1145 FZDZE56 BLPYE57 CIG 1000V1500 CIG 020 RWY11 "
"PRESFR PRESRR SLP013 FG FEW000 VIS NW2 1/2 GR 3/4 "
"VIRGA SE -XRAFG3 CIGE005 BKN014 V OVC "
"FU BKN020 NOSPECI LAST 8/365 SNINCR 2/10 4/178 "
"933125 98096 P0125 60225 70565 "
"T00261015 10369 21026 "
"404800360 52101 PWINO FZRANO TSNO $",
"METAR KGFI 041356Z AUTO 17012KT 130V210 3 1/2SM R15L/0500FT -RA "
"SCT050 OVC110 26/18 A2991 RMK FUNNEL CLOUDS A02 RAB30 "
"SLP 101 GR M1/4 VIRGA SCT V BKN P 0010 T02640178",
"METAR KGFI 041356Z AUTO 05008KT 10SM R15L/P6000FT CLR A2991 "
"RMK WATERSPOUTS VCY STN NW A02 SLP 101 10288 20243 52021 $ ",
"SPECI KGFI 041420Z AUTO 18030KT 3 1/2SM RVRNO TS -RA BKN008 OVC060 "
"26/22 A2991 RMK A02 RA15TSB20 PRESFR SLP 101 P 0000 T02640218",
"KABE 281900Z NIL",
"METAR KPIT NIL",
"METAR KCLE 04281156Z 170100G135KT 110V180 M1/4SM "
"R01L/P6000FT +TSSHRA VCFG "
"BKN025 SCT100 OVC200 M26/ A2991 RMK PK WND 18515/45 A02 "
"WSHFT 1350 TWR VIS 1 1/2 SFC VIS 1/4 VIS 1/4V1 1/4 "
"CIG 1000V1500 PRESFR FRQ LTG CG NW "
"RAB1030E1145 FZDZE56 PRESRR SLP135 GS "
"T1263 "
"VIRGA NW 8/365 4/178 P 0125 60225 7//// 70565 10369 21026 "
"404800360 52101 PWINO FZRANO TSNO $",
"METAR KPHL 040256Z AUTO 170100G135KT 130V210 1/2SM "
"R15L/0500FT R22L/2700FT R16/1200FT R34/1000V1600FT R01L/P6000FT "
"FC +TS BKN050 SCT150 OVC250 M26/ A2991 RMK A02 PK WND 185150/1345 "
"WSHFT 1350 TWR VIS 1 1/2 SFC VIS 1/4 VIS 1/4V1 1/4 LTG DSNT "
"RAB1030E1145 FZDZE56 CIG 1000V1500 PRESFR PRESRR SLP037 GR 2 3/4 "
"VIRGA E 8/365 4/178 P 0125 70565 21026 T0263 10369 60225 "
"404800360 52101 PWINO FZRANO TSNO $",
"SPECI KGFI 041420Z AUTO 18030KT 2 1/2SM RVRNO TS -RA BKN008 "
"OVC060 25/22 A2991 RMK A02 LTG DSNT W "
"RAB15TSB20 PRESFR SLP101 P 0000 "
"254/218",
"METAR KGFI 041356Z AUTO 170100G135KT 130V210 3 1/2SM "
"R15L/0500FT R22L/2700FT R16/1200FT R34/1000V1600FT R01L/P6000FT "
"FC +TS BKN050 SCT150 OVC250 M26/ A2991 RMK A02 PK WND 185150/1345 "
"WSHFT 1350 TWR VIS 1 1/2 SFC VIS 1/4 VIS 1/4V1 1/4 "
"RAB1030E1145 FZDZE56 CIG 1000V1500 PRESFR PRESRR SLP997 GR M1/4 "
"VIRGA SE 8/365 4/178 P 0125 6//// 60225 70565 T0263 10369 21026 "
"404800360 52101 PWINO FZRANO TSNO $",
"METAR KGFI 041356Z AUTO 170100G135KT 130V210 3 1/2SM "
"R15L/0500FT R22L/2700FT R16/1200FT R34/1000V1600FT R01L/P6000FT "
"FC +TS BKN050 SCT150 OVC250 M26/ A2991 RMK A02 PK WND 185150/1345 "
"WSHFT 1350 TWR VIS 1 1/2 SFC VIS 1/4 VIS 1/4V1 1/4 "
"RAB1030E1145 FZDZE56 CIG 1000V1500 PRESFR PRESRR SLP997 GR 25 "
"VIRGA 35 8/365 4/178 P 0125 6//// 60225 70565 T0263 10369 21026 "
"VIRGA 35 8/365 4/178 P 0125 21026 70565 10369 60225 T0263 21026 "
"404800360 52101 PWINO FZRANO TSNO $",
"METAR KGFI 041356Z AUTO 170100G135KT 130V210 3 1/2SM "
"R15L/0500FT R22L/2700FT R16/1200FT R34/1000V1600FT R01L/P6000FT "
"FC +TS BKN050 SCT150 OVC250 3/M1 A2991 RMK A02 PK WND 18515/45 "
"WSHFT 1350 TWR VIS 1 1/2 SFC VIS 1/4 VIS 1/4V1 1/4 "
"RAB1030E1145 FZDZE56 CIG 1000V1500 PRESFR PRESRR SLP997 GR 25 "
"VIRGA 35 8/365 4/178 P 0125 60225 70565 T00261015 10369 21026 "
"404800360 52101 PWINO FZRANO TSNO $",
"METAR KGFI 041356Z AUTO 170100G135KT 130V210 3 1/2SM "
"R15L/0500FT R22L/2700FT R16/1200FT R34/1000V1600FT R01L/P6000FT "
"FC +TS BKN050 SCT150 OVC250 3/M1 A2991 RMK A02 PK WND 185150/1345 "
"WSHFT 1350 TWR VIS 1 1/2 SFC VIS 1/4 VIS 1/4V1 1/4 "
"RAB1030E1145 FZDZE56 CIG 1000V1500 PRESFR PRESRR SLP997 GR 25 "
"VIRGA 35 8/365 4/178 P 0125 60225 70565 T00261015 10369 21026 "
"404800360 52101 PWINO FZRANO TSNO",
"METAR KGFI 041356Z AUTO 05008KT 10SM R15L/P6000FT CLR A2991 RMK "
"A02 SLP 101 10288 20243 52021",
"SPECI DGFI 041430Z 18045G56KT M1/4SM R15/0200FT FC +TS VV010 20/18 "
"M20/M18 A2900 RMK A02A PK WND 18056/28 RAB15E25TSB20 FCB1430 PRESFR "
"SLP 701 P 0254 M199/M182",
"SPECI DGFI 041430Z 18045G56KT M1/4SM R15/0200FT FC +TS VV010 20/18 "
"M20/M18 A2900 RMK A02A PK WND 18056/28 RAB15E25TSB20 FCB1430 PRESFR "
"SLP 701 P 0254 M199/182",
"SPECI DGFI 041430Z 18045G56KT M1/4SM R15/0200FT FC +TS VV010 20/18 "
"M20/M18 A2900 RMK A02A PK WND 18056/28 RAB15E25TSB20 FCB1430 PRESFR "
"SLP 701 P 0254 199/M182",
"METAR APIT 171755Z AUTO 22015G25KT 1 3/4SM R22L/2700FT R16/1200FT "
"R34/1000V1600FT R01L/P6000FT R04RR/900FT "
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB 18/16 A2992 "
"RMK 4/369 58033 6003/ TWELVE 70125 10039 20029 410840112 "
"PCPN 0009 8/563 WSHFT 1715 PK WND 2032/1725 "
"CIG 20V25 WND 12V25 TWR VIS 2 1/2 "
"SFC VIS 1 1/2 VIS 1 1/2V2 SLP875 SGB1213E1225",
"NZWN 1700Z 35030G49KT 320V030 20KM 02 5SC021 7SC046 12/08 "
" Q0994.2 TEMPO 6000 RA 5ST012 2CB015 RMK SLP056 "
"RAE0123",
"SPECI APIT 171755Z 22015G25KT 1 3/4SM R22L/2700FT R16/1200FT "
"R34/1000V1600FT R01L/P6000FT R04RR/900FT "
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB 18/16 A2992 "
"RMK 58033 6003/ TWELVE 70125 8/321 10039 20029 410840112 "
"PCPN 0009 WSHFT 1715 PK WND 2032/1725 "
"CIG 20V25 WND 12V25 TWR VIS 2 1/2 "
"SFC VIS 1 1/2 VIS 1 SLP875 FGB1713",
"APIT 1755Z 22015G25KT 1 3/4SM R22L/2700FT R16/1200FT "
"R34/1000V1600FT R01L/P6000FT R04RR/900FT "
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB 18/16 A2992 "
"RMK 58033 6003/ TWELVE 70125 10039 20029 410840112 "
"PCPN 0009 WSHFT 1715 PK WND 2032/1725 "
"CIG 20V25 WND 12V25 TWR VIS 2 1/2 "
"SFC VIS 1 1/2 VIS 1V2 SLP875",
"APIT 1755Z 22015G25KT 1 3/4SM R22L/2700FT R16/1200FT "
"R34/1000V1600FT R01L/P6000FT R04RR/900FT "
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB 18/16 A2992 "
"RMK 58033 6003/ TWELVE 70125 10039 20029 410840112 "
"PCPN 0009 WSHFT 1715 PK WND 2032/1725 "
"CIG 20V25 WND 12V25 TWR VIS 2 1/2 "
"SFC VIS 1 1/2 VIS 1 1/2V2 1/2 SLP875",
"APIT 1755Z 22015G25KT 1 3/4SM R22L/2700FT R16/1200FT "
"R34/1000V1600FT R01L/P6000FT R04RR/900FT "
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB 18/16 A2992 "
"RMK 58033 6003/ TWELVE 70125 10039 20029 410840112 "
"PCPN 0009 WSHFT 1715 PK WND 2032/1725 "
"CIG 20V25 WND 12V25 TWR VIS 2 1/2 "
"SFC VIS 1 1/2 VIS 1V2 1/2 SLP875",
"EGPF 1720Z 00000KT 9999 -SHRA STC014 SCT020CB BNK024 12/09 "
"Q1003 NOSIG",
"NZAA 1700Z 03010KT 30KM 03 5CU022 7SC035 11/07 Q1006.5 NOSIG",
"NZWN 1700Z 35030G49KT 320V030 20KM 02 5SC021 7SC046 12/08 "
" Q0994.2 TEMPO 6000 RA 5ST012 2CB015 RMK KAUKAU 30050KT",
"DGAA 1800Z 22012KT 9999 SCT009 BKN120 25/21 Q1015",
"DAAT 1830Z 30010KT CAVOK 29/06 Q1019",
"GQPP 1800Z 34023KT 3000 DRSA SKC 24/20 Q1011 NSG",
"DAAG 1830Z 06006KT 9999 SCT020 25/22 Q1015",
"DABB 1830Z 04010KT 9999 SCT030TCU SCT033CB 27/18 Q1017",
"DABC 1830Z 00000KT 9999 SCT026TCU SCT036CB 22/18 Q1020 RETS",
"NZAA 1700Z 03010KT 30KM 03 5CU022 7SC035 11/07 Q1006.5 NOSIG",
"NZWN 1700Z 35030G49KT 320V030 20KM 02 5SC021 7SC046 12/08 "
" Q0994.2 TEMPO 6000 RA 5ST012 2CB015 RMK K",
"NZWN 1700Z 35030G49KT 320V030 20KM 02 5SC021 7SC046 12/08 "
" Q0994.2 TEMPO 6000 RA 5ST012 2CB015 RMK KAUKAU 30050KT",
"DGAA 1800Z 22012KT 9999 SCT009 BKN120 25/21 Q1015",
"GFLL 1900Z NIL",
"GOOY 1800Z 03006G17KT 340V080 6000 TSRA BKN016 BKN030CB "
"BKN133 26/23 Q1013 NOSIG",
"GCXO 1930Z 32018KT 8000 SCT003 SCT007 18/16 Q1019",
"APIT 1755Z 22015G25KT 1 3/4SM R22L/2700FT R16/1200FT "
"R34/1000V1600FT R01L/P6000FT R04RR/900FT "
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB 18/16 A2992 "
"RMK 58033 6003/ TWELVE 70125 10039 20029 410840112 "
"PCPN 0009 WSHFT 1715 PK WND 2032/1725 "
"CIG 20V25 WND 12V25 TWR VIS 2 1/2 "
"SFC VIS 1 1/2 VIS 1 1/2V2",
"BPIT 1755Z 22015G25KT 1 3/4SM R22L/2700FT R16/1200FT "
"R34/1000V1600FT R01L/P6000FT R04RR/900FT "
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB 18/16 A2992 "
"RMK 58033 6003/ TWELVE 70125 10039 20029 410840112 "
"PCPN 0009 WSHFT 1715 PK WND 2032/1725 "
"CIG 20V25 WND 12V25 TWR VIS 2 1/2 "
"SFC VIS 1 1/2 VIS 1V2",
"CPIT 1755Z 22015G25KT 1 3/4SM R22L/2700FT R16/1200FT "
"R34/1000V1600FT R01L/P6000FT R04RR/900FT "
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB 18/16 A2992 "
"RMK 58033 6003/ TWELVE 70125 10039 20029 410840112 "
"PCPN 0009 WSHFT 1715 PK WND 2032/1725 "
"CIG 20V25 WND 12V25 TWR VIS 2 1/2 "
"SFC VIS 1 1/2 VIS 1V2 1/2",
"DPIT 1755Z 22015G25KT 1 3/4SM R22L/2700FT R16/1200FT "
"R34/1000V1600FT R01L/P6000FT R04RR/900FT "
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB 18/16 A2992 "
"RMK 58033 6003/ TWELVE 70125 10039 20029 410840112 "
"PCPN 0009 WSHFT 1715 PK WND 2032/1725 "
"CIG 20V25 WND 12V25 TWR VIS 2 1/2 "
"SFC VIS 1 1/2 VIS 1 1/2V2 1/2",
"EPIT 1755Z 22015G25KT 1 3/4SM R22L/2700FT R16/1200FT "
"R34/1000V1600FT R01L/P6000FT R04RR/900FT "
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB 18/16 A2992 "
"RMK 58033 6003/ TWELVE 70125 10039 20029 410840112 "
"PCPN 0009 WSHFT 1715 PK WND 2032/1725 "
"CIG 20V25 WND 12V25 TWR VIS 2 1/2 "
"SFC VIS 1 1/2 VIS 1/2V3/4",
"FPIT 1755Z 22015G25KT 1 3/4SM R22L/2700FT R16/1200FT "
"R34/1000V1600FT R01L/P6000FT R04RR/900FT "
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB 18/16 A2992 "
"RMK 58033 6003/ TWELVE 70125 10039 20029 410840112 "
"PCPN 0009 WSHFT 1715 PK WND 2032/1725 "
"CIG 20V25 WND 12V25 TWR VIS 2 1/2 "
"SFC VIS 1 1/2 VIS 3/4V2 1/2",
"GPIT 1755Z 22015G25KT 1 3/4SM R22L/2700FT R16/1200FT "
"R34/1000V1600FT R01L/P6000FT R04RR/900FT "
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB 18/16 A2992 "
"RMK 58033 6003/ TWELVE 70125 10039 20029 410840112 "
"PCPN 0009 WSHFT 1715 PK WND 2032/1725 "
"CIG 20V25 WND 12V25 TWR VIS 2 1/2 "
"SFC VIS 1 1/2 VIS 3/4V3",
"KPIT 1935Z 22015G25KT 1 3/4SM R22L/2700FT "
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB M18/M16 A2992",
"KPIT 1935Z 22015G25KT 1 3/4SM R22L/2700FT "
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB M18/16 A2992",
"KPIT 1935Z 22015G25KT 1 3/4SM R22L/2700FT "
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB 18/M16 A2992",
"KPIT 1935Z 22015G25KT 1 3/4SM R22L/2700FT "
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB MM/M16 A2992",
"KPIT 1935Z 22015G25KT 1 3/4SM R22L/2700FT "
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB MM/16 A2992",
"KPIT 1935Z 22015G25KT 1 3/4SM R22L/2700FT "
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB M18/MM A2992",
NULL};
/***************************/
/* DECLARE LOCAL VARIABLES */
/***************************/
Decoded_METAR Metar;
Decoded_METAR *Mptr = &Metar;
int j,
ErReturn;
static char *synopRTRN = NULL;
char bltn_prefix[20];
/***************************************************/
/* START BODY OF MAIN ROUTINE FOR CALLING DcdMETAR */
/***************************************************/
j = 0;
while( string[j] != NULL)
{
/*-- PRINT INPUT METAR REPORT ----------------------------*/
printf("\n\nINPUT METAR REPORT:\n\n %s\n\n",string[j] );
/*-- DECODE INPUT REPORT ---------------------------------*/
if ( (ErReturn = DcdMETAR( string[ j ], Mptr )) != 0 )
printf("DcdMETAR: Error Return Number: %d\n",ErReturn);
/*-- PRINT DECODED METAR REPORT ELEMENTS -----------------*/
printf("\n\nFINAL DECODED PRODUCT...\n\n");
prtDMETR( Mptr );
#ifdef OLDSTUFF
/************************************************/
/* Convert Decoded METAR into Synoptic format */
/************************************************/
printf("Just after call to prtDMETR\n");
sprintf( bltn_prefix, "AAXX YYGGi##," );
synopRTRN = BldSynop( Mptr, bltn_prefix );
printf("After BldSynop, SynopRep =:\n%s\n",synopRTRN);
/**********************************************************/
/*-- ENCODE SECTION 0 OF THE SYNTHETIC SYNOPTIC REPORT ---*/
/**********************************************************/
printf("Just before call to Sec0MeSM\n");
if( (synopRTRN = Sec0MeSm( Mptr )) == NULL )
printf("Sec0MeSm returned a NULL pointer\n");
else
printf("After Sec0MeSm: %s\n",synopRTRN);
/**********************************************************/
/*-- ENCODE SECTION 1 OF THE SYNTHETIC SYNOPTIC REPORT ---*/
/**********************************************************/
if( synopRTRN != NULL )
synopRTRN = Sec1MeSm( Mptr,synopRTRN );
printf("After Sec1MeSm: %s\n",synopRTRN);
/**********************************************************/
/*-- ENCODE SECTION 3 OF THE SYNTHETIC SYNOPTIC REPORT ---*/
/**********************************************************/
if( synopRTRN != NULL )
synopRTRN = Sec3MeSm( Mptr,synopRTRN );
printf("After Sec3MeSm: %s\n",synopRTRN);
/**********************************************************/
/*-- ENCODE SECTION 5 OF THE SYNTHETIC SYNOPTIC REPORT ---*/
/**********************************************************/
if( synopRTRN != NULL )
synopRTRN = Sec5MeSm( Mptr,synopRTRN);
printf("After Sec5MeSm: %s\n",synopRTRN);
/**********************************************************/
/*-- PRINT THE ENCODED SYNTHETIC SYNOPTIC REPORT ---------*/
/**********************************************************/
if( synopRTRN != NULL ) {
printf("\n\nOutput Synoptic Report: %s\n\n",synopRTRN);
free( synopRTRN);
}
#endif
j++;
}
}

Wyświetl plik

@ -0,0 +1,84 @@
/*
METAR Decoder Software Package Library: Parses Aviation Routine Weather Reports
Copyright (C) 2003 Eric McCarthy
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "metar_structs.h"
#pragma subtitle(" ")
#pragma page(1)
#pragma subtitle("subtitle - description ")
/********************************************************************/
/* */
/* Title: fracPart */
/* Organization: W/OSO242 - GRAPHICS AND DISPLAY SECTION */
/* Date: 13 Jun 1995 */
/* Programmer: CARL MCCALLA */
/* Language: C/370 */
/* */
/* Abstract: Convert a character string fraction into a */
/* decimal (floating point) number. */
/* */
/* External Functions Called: */
/* None. */
/* */
/* Input: string - a pointer to a character string frac- */
/* tion. */
/* Output: A decimal (floating point) number. */
/* */
/* Modification History: */
/* None. */
/* */
/********************************************************************/
#pragma page(1)
float fracPart( char *string )
{
/***************************/
/* DECLARE LOCAL VARIABLES */
/***************************/
char buf[ 6 ],
*slash;
float numerator,
denominator;
/*************************/
/* START BODY OF ROUTINE */
/*************************/
slash = strchr(string, '/');
memset(buf , '\0', 6);
strncpy( buf, string, slash-string);
numerator = (float) atoi(buf);
memset(buf , '\0', 6);
strcpy( buf, slash+1);
denominator = (float) atoi(buf);
if( denominator == 0.0 )
return ((float) MAXINT);
else
return (numerator/denominator);
}

Wyświetl plik

@ -0,0 +1,283 @@
/*
METAR Decoder Software Package Library: Parses Aviation Routine Weather Reports
Copyright (C) 2003 Eric McCarthy
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef METARX
#define METARX
/********************************************************************/
/* */
/* Title: METAR H */
/* Organization: W/OSO242 - GRAPHICS AND DISPLAY SECTION */
/* Date: 19 Jan 1996 */
/* Programmer: CARL MCCALLA */
/* Language: C/370 */
/* */
/* Abstract: METAR Decoder Header File. */
/* */
/* Modification History: */
/* None. */
/* */
/********************************************************************/
#include "local.h" /* standard header file */
/*********************************************/
/* */
/* RUNWAY VISUAL RANGE STRUCTURE DECLARATION */
/* AND VARIABLE TYPE DEFINITION */
/* */
/*********************************************/
typedef struct runway_VisRange {
char runway_designator[6];
MDSP_BOOL vrbl_visRange;
MDSP_BOOL below_min_RVR;
MDSP_BOOL above_max_RVR;
int visRange;
int Max_visRange;
int Min_visRange;
} Runway_VisRange;
/***********************************************/
/* */
/* DISPATCH VISUAL RANGE STRUCTURE DECLARATION */
/* AND VARIABLE TYPE DEFINITION */
/* */
/***********************************************/
typedef struct dispatch_VisRange {
MDSP_BOOL vrbl_visRange;
MDSP_BOOL below_min_DVR;
MDSP_BOOL above_max_DVR;
int visRange;
int Max_visRange;
int Min_visRange;
} Dispatch_VisRange;
/*****************************************/
/* */
/* CLOUD CONDITION STRUCTURE DECLARATION */
/* AND VARIABLE TYPE DEFINITION */
/* */
/*****************************************/
typedef struct cloud_Conditions {
char cloud_type[5];
char cloud_hgt_char[4];
char other_cld_phenom[4];
int cloud_hgt_meters;
} Cloud_Conditions;
/*****************************************/
/* */
/* WIND GROUP DATA STRUCTURE DECLARATION */
/* AND VARIABLE TYPE DEFINITION */
/* */
/*****************************************/
typedef struct windstruct {
char windUnits[ 4 ];
MDSP_BOOL windVRB;
int windDir;
int windSpeed;
int windGust;
} WindStruct;
/*****************************************/
/* */
/* RECENT WX GROUP STRUCTURE DECLARATION */
/* AND VARIABLE TYPE DEFINITION */
/* */
/*****************************************/
typedef struct recent_wx {
char Recent_weather[ 5 ];
int Bhh;
int Bmm;
int Ehh;
int Emm;
} Recent_Wx;
/***************************************/
/* */
/* DECODED METAR STRUCTURE DECLARATION */
/* AND VARIABLE TYPE DEFINITION */
/* */
/***************************************/
typedef struct decoded_METAR {
char synoptic_cloud_type[ 6 ];
char snow_depth_group[ 6 ];
char codeName[ 6 ];
char stnid[5];
char horiz_vsby[5];
char dir_min_horiz_vsby[3];
char vsby_Dir[ 3 ];
char WxObstruct[10][8];
char autoIndicator[5];
char VSBY_2ndSite_LOC[10];
char SKY_2ndSite_LOC[10];
char SKY_2ndSite[10];
char SectorVsby_Dir[ 3 ];
char ObscurAloft[ 12 ];
char ObscurAloftSkyCond[ 12 ];
char VrbSkyBelow[ 4 ];
char VrbSkyAbove[ 4 ];
char LTG_DIR[ 3 ];
char CloudLow;
char CloudMedium;
char CloudHigh;
char CIG_2ndSite_LOC[10];
char VIRGA_DIR[3];
char TornadicType[15];
char TornadicLOC[10];
char TornadicDIR[4];
char TornadicMovDir[3];
char CHINO_LOC[6];
char VISNO_LOC[6];
char PartialObscurationAmt[2][7];
char PartialObscurationPhenom[2][12];
char SfcObscuration[6][10];
char charPrevailVsby[12];
char charVertVsby[10];
char TS_LOC[3];
char TS_MOVMNT[3];
MDSP_BOOL Indeterminant3_6HrPrecip;
MDSP_BOOL Indeterminant_24HrPrecip;
MDSP_BOOL CIGNO;
MDSP_BOOL SLPNO;
MDSP_BOOL ACFTMSHP;
MDSP_BOOL NOSPECI;
MDSP_BOOL FIRST;
MDSP_BOOL LAST;
MDSP_BOOL SunSensorOut;
MDSP_BOOL AUTO;
MDSP_BOOL COR;
MDSP_BOOL NIL_rpt;
MDSP_BOOL CAVOK;
MDSP_BOOL RVRNO;
MDSP_BOOL A_altstng;
MDSP_BOOL Q_altstng;
MDSP_BOOL VIRGA;
MDSP_BOOL VOLCASH;
MDSP_BOOL GR;
MDSP_BOOL CHINO;
MDSP_BOOL VISNO;
MDSP_BOOL PNO;
MDSP_BOOL PWINO;
MDSP_BOOL FZRANO;
MDSP_BOOL TSNO;
MDSP_BOOL DollarSign;
MDSP_BOOL PRESRR;
MDSP_BOOL PRESFR;
MDSP_BOOL Wshft_FROPA;
MDSP_BOOL OCNL_LTG;
MDSP_BOOL FRQ_LTG;
MDSP_BOOL CNS_LTG;
MDSP_BOOL CG_LTG;
MDSP_BOOL IC_LTG;
MDSP_BOOL CC_LTG;
MDSP_BOOL CA_LTG;
MDSP_BOOL DSNT_LTG;
MDSP_BOOL AP_LTG;
MDSP_BOOL VcyStn_LTG;
MDSP_BOOL OVHD_LTG;
MDSP_BOOL LightningVCTS;
MDSP_BOOL LightningTS;
int TornadicDistance;
int ob_hour;
int ob_minute;
int ob_date;
int minWnDir;
int maxWnDir;
int VertVsby;
int temp;
int dew_pt_temp;
int QFE;
int hectoPasc_altstng;
int char_prestndcy;
int minCeiling;
int maxCeiling;
int WshfTime_hour;
int WshfTime_minute;
int min_vrbl_wind_dir;
int max_vrbl_wind_dir;
int PKWND_dir;
int PKWND_speed;
int PKWND_hour;
int PKWND_minute;
int SKY_2ndSite_Meters;
int Ceiling;
int Estimated_Ceiling;
int SNINCR;
int SNINCR_TotalDepth;
int SunshineDur;
int ObscurAloftHgt;
int VrbSkyLayerHgt;
int Num8thsSkyObscured;
int CIG_2ndSite_Meters;
int snow_depth;
int BTornadicHour;
int BTornadicMinute;
int ETornadicHour;
int ETornadicMinute;
float SectorVsby;
float WaterEquivSnow;
float VSBY_2ndSite;
float prevail_vsbySM;
float prevail_vsbyM;
float prevail_vsbyKM;
float prestndcy;
float precip_amt;
float precip_24_amt;
float maxtemp;
float mintemp;
float max24temp;
float min24temp;
float minVsby;
float maxVsby;
float hourlyPrecip;
float TWR_VSBY;
float SFC_VSBY;
float Temp_2_tenths;
float DP_Temp_2_tenths;
float SLP;
float GR_Size;
double inches_altstng;
Runway_VisRange RRVR[12];
Dispatch_VisRange DVR;
Recent_Wx ReWx[3];
WindStruct winData;
Cloud_Conditions cldTypHgt[6];
} Decoded_METAR;
#define MAXWXSYMBOLS 10 /*-- NOT TO EXCEED 10 PRES. WX GRPS --*/
#define MAXTOKENS 500 /*-- RPT NOT TO EXCEED 500 GRPS --*/
#endif

Wyświetl plik

@ -0,0 +1,963 @@
/*
METAR Decoder Software Package Library: Parses Aviation Routine Weather Reports
Copyright (C) 2003 Eric McCarthy
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "metar_structs.h"
void say_text(char *speech, char *text) {
int i;
char tmp[2];
for (i = 0; i < strlen(text); i++) {
switch(text[i]) {
case '-':
strcat(speech, "minus");
break;
case '0':
strcat(speech, "zero");
break;
case '1':
strcat(speech, "one");
break;
case '2':
strcat(speech, "two");
break;
case '3':
strcat(speech, "three");
break;
case '4':
strcat(speech, "four");
break;
case '5':
strcat(speech, "five");
break;
case '6':
strcat(speech, "six");
break;
case '7':
strcat(speech, "seven");
break;
case '8':
strcat(speech, "eight");
break;
case '9':
strcat(speech, "niner");
break;
case '@':
strcat(speech, "at");
break;
default:
sprintf(tmp, "%c", text[i]);
strcat(speech, tmp);
break;
}
strcat(speech, " ");
}
}
void sprint_metar (char * string, Decoded_METAR *Mptr)
{
/***************************/
/* DECLARE LOCAL VARIABLES */
/***************************/
int i;
char temp[100];
/*************************/
/* START BODY OF ROUTINE */
/*************************/
strcat(string, "ME TAR. ");
if ( Mptr->stnid[ 0 ] == '\0' ) {
strcat(string, "Error");
return;
}
for (i = 0; i < strlen(Mptr->stnid); i++) {
sprintf(temp, "%c ", Mptr->stnid[i]);
strcat(string, temp);
}
strcat(string, ". ");
if (Mptr->ob_hour != MAXINT && Mptr->ob_minute != MAXINT) {
if (Mptr->AUTO) {
strcat(string, "Automated ");
}
if (Mptr->COR) {
strcat(string, "Corrected ");
}
strcat(string, "Observation ");
sprintf(temp, "%d%d", Mptr->ob_hour, Mptr->ob_minute);
say_text(string, temp);
strcat(string, "zulu. ");
}
strcat(string, "Wind ");
if (Mptr->winData.windDir != MAXINT) {
sprintf(temp, "%03d", Mptr->winData.windDir);
say_text(string, temp);
}
if ( Mptr->winData.windVRB ) {
strcat(string, "variable ");
}
//FIXME.
if ( Mptr->minWnDir != MAXINT ) {
sprintf(temp, "%03d", Mptr->minWnDir);
say_text(string, temp);
}
//FIXME.
if ( Mptr->maxWnDir != MAXINT ) {
sprintf(temp, "%03d", Mptr->maxWnDir);
say_text(string, temp);
}
if ( Mptr->winData.windSpeed != MAXINT ) {
sprintf(temp, "@%d", Mptr->winData.windSpeed);
say_text(string, temp);
} else {
strcat(string, "calm ");
}
if ( Mptr->winData.windGust != MAXINT ) {
strcat(string, "gusting ");
sprintf(temp, "%d", Mptr->winData.windGust);
say_text(string, temp);
}
strcat(string, ". ");
if ( Mptr->prevail_vsbyM != (float) MAXINT ) {
strcat(string, "Visibility ");
sprintf(temp, "%d", (int)Mptr->prevail_vsbyM);
say_text(string, temp);
strcat(string, "miles. ");
}
if ( Mptr->prevail_vsbySM != (float) MAXINT ) {
strcat(string, "Visibility ");
sprintf(temp, "%d", (int)Mptr->prevail_vsbySM);
say_text(string, temp);
strcat(string, "miles. ");
}
/* for ( i = 0; i < 12; i++ )
{
if( Mptr->RRVR[i].runway_designator[0] != '\0' ) {
sprintf(temp, "RUNWAY DESIGNATOR : %s\n",
Mptr->RRVR[i].runway_designator);
strcat(string, temp);
}
if( Mptr->RRVR[i].visRange != MAXINT ) {
sprintf(temp, "R_WAY VIS RANGE (FT): %d\n",
Mptr->RRVR[i].visRange);
strcat(string, temp);
}
if ( Mptr->RRVR[i].vrbl_visRange ) {
sprintf(temp, "VRBL VISUAL RANGE : TRUE\n");
strcat(string, temp);
}
if ( Mptr->RRVR[i].below_min_RVR ) {
sprintf(temp, "BELOW MIN RVR : TRUE\n");
strcat(string, temp);
}
if ( Mptr->RRVR[i].above_max_RVR ) {
sprintf(temp, "ABOVE MAX RVR : TRUE\n");
strcat(string, temp);
}
if( Mptr->RRVR[i].Max_visRange != MAXINT ) {
sprintf(temp, "MX R_WAY VISRNG (FT): %d\n",
Mptr->RRVR[i].Max_visRange);
strcat(string, temp);
}
if( Mptr->RRVR[i].Min_visRange != MAXINT ) {
sprintf(temp, "MN R_WAY VISRNG (FT): %d\n",
Mptr->RRVR[i].Min_visRange);
strcat(string, temp);
}
}
if( Mptr->DVR.visRange != MAXINT ) {
sprintf(temp, "DISPATCH VIS RANGE : %d\n",
Mptr->DVR.visRange);
strcat(string, temp);
}
if ( Mptr->DVR.vrbl_visRange ) {
sprintf(temp, "VRBL DISPATCH VISRNG: TRUE\n");
strcat(string, temp);
}
if ( Mptr->DVR.below_min_DVR ) {
sprintf(temp, "BELOW MIN DVR : TRUE\n");
strcat(string, temp);
}
if ( Mptr->DVR.above_max_DVR ) {
sprintf(temp, "ABOVE MAX DVR : TRUE\n");
strcat(string, temp);
}
if( Mptr->DVR.Max_visRange != MAXINT ) {
sprintf(temp, "MX DSPAT VISRNG (FT): %d\n",
Mptr->DVR.Max_visRange);
strcat(string, temp);
}
if( Mptr->DVR.Min_visRange != MAXINT ) {
sprintf(temp, "MN DSPAT VISRNG (FT): %d\n",
Mptr->DVR.Min_visRange);
strcat(string, temp);
}
i = 0;
while ( Mptr->WxObstruct[i][0] != '\0' && i < MAXWXSYMBOLS )
{
sprintf(temp, "WX/OBSTRUCT VISION : %s\n",
Mptr->WxObstruct[i] );
strcat(string, temp);
i++;
}
if ( Mptr->PartialObscurationAmt[0][0] != '\0' ) {
sprintf(temp, "OBSCURATION AMOUNT : %s\n",
&(Mptr->PartialObscurationAmt[0][0]));
strcat(string, temp);
}
if ( Mptr->PartialObscurationPhenom[0][0] != '\0' ) {
sprintf(temp, "OBSCURATION PHENOM : %s\n",
&(Mptr->PartialObscurationPhenom[0][0]));
strcat(string, temp);
}
if ( Mptr->PartialObscurationAmt[1][0] != '\0' ) {
sprintf(temp, "OBSCURATION AMOUNT : %s\n",
&(Mptr->PartialObscurationAmt[1][0]));
strcat(string, temp);
}
if ( Mptr->PartialObscurationPhenom[1][0] != '\0' ) {
sprintf(temp, "OBSCURATION PHENOM : %s\n",
&(Mptr->PartialObscurationPhenom[1][0]));
strcat(string, temp);
}
*/
strcat(string, "Sky condition ");
i = 0;
while ( Mptr->cldTypHgt[ i ].cloud_type[0] != '\0' &&
i < 6 )
{
if ( Mptr->cldTypHgt[ i ].cloud_type[0] != '\0' ) {
if (strcmp(Mptr->cldTypHgt[ i ].cloud_type, "CLR") == 0) {
strcat(string, "clear. ");
} else {
if (strcmp(Mptr->cldTypHgt[ i ].cloud_type, "FEW") == 0) {
strcat(string, "scattered ");
}
if (strcmp(Mptr->cldTypHgt[ i ].cloud_type, "SCT") == 0) {
strcat(string, "scattered ");
}
if (strcmp(Mptr->cldTypHgt[ i ].cloud_type, "BKN") == 0) {
strcat(string, "broken ");
}
if (strcmp(Mptr->cldTypHgt[ i ].cloud_type, "OVC") == 0) {
strcat(string, "overcast ");
}
//TODO: Others?
}
}
if ( Mptr->cldTypHgt[ i ].cloud_hgt_char[0] != '\0' ) {
char thousands[4];
char hundreds[4];
int height = atoi(Mptr->cldTypHgt[i].cloud_hgt_char);
if ((height - (height%10)) > 0) {
sprintf(thousands, "%d", height/10);
say_text(string, thousands);
strcat(string, "thousand ");
}
if (height%10) {
sprintf(hundreds, "%d", height%10);
say_text(string, hundreds);
strcat(string, "hundred ");
}
}
strcat(string, ". ");
/*
//TODO: TCU, Towering Cumulus, etc.
if ( Mptr->cldTypHgt[ i ].other_cld_phenom[0] != '\0' ) {
sprintf(temp, "OTHER CLOUD PHENOM : %s\n",
Mptr->cldTypHgt[ i ].other_cld_phenom);
strcat(string, temp);
}
*/
i++;
}
if ( Mptr->temp != MAXINT ) {
strcat(string, "Temperature ");
sprintf(temp, "%d", Mptr->temp);
say_text(string, temp);
strcat(string, "celsius. ");
}
if ( Mptr->dew_pt_temp != MAXINT ) {
strcat(string, "Dew point ");
sprintf(temp, "%d", Mptr->dew_pt_temp);
say_text(string, temp);
strcat(string, "celsius. ");
}
if ( Mptr->A_altstng ) {
strcat(string, "Altimeter ");
sprintf(temp, "%d", (int)Mptr->inches_altstng);
say_text(string, temp);
strcat(string, ", ");
sprintf(temp, "%02d", (int)(100*Mptr->inches_altstng)%100);
say_text(string, temp);
strcat(string, ". ");
}
/*
if ( Mptr->TornadicType[0] != '\0' ) {
sprintf(temp, "TORNADIC ACTVTY TYPE: %s\n",
Mptr->TornadicType );
strcat(string, temp);
}
if ( Mptr->BTornadicHour != MAXINT ) {
sprintf(temp, "TORN. ACTVTY BEGHOUR: %d\n",
Mptr->BTornadicHour );
strcat(string, temp);
}
if ( Mptr->BTornadicMinute != MAXINT ) {
sprintf(temp, "TORN. ACTVTY BEGMIN : %d\n",
Mptr->BTornadicMinute );
strcat(string, temp);
}
if ( Mptr->ETornadicHour != MAXINT ) {
sprintf(temp, "TORN. ACTVTY ENDHOUR: %d\n",
Mptr->ETornadicHour );
strcat(string, temp);
}
if ( Mptr->ETornadicMinute != MAXINT ) {
sprintf(temp, "TORN. ACTVTY ENDMIN : %d\n",
Mptr->ETornadicMinute );
strcat(string, temp);
}
if ( Mptr->TornadicDistance != MAXINT ) {
sprintf(temp, "TORN. DIST. FROM STN: %d\n",
Mptr->TornadicDistance );
strcat(string, temp);
}
if ( Mptr->TornadicLOC[0] != '\0' ) {
sprintf(temp, "TORNADIC LOCATION : %s\n",
Mptr->TornadicLOC );
strcat(string, temp);
}
if ( Mptr->TornadicDIR[0] != '\0' ) {
sprintf(temp, "TORNAD. DIR FROM STN: %s\n",
Mptr->TornadicDIR );
strcat(string, temp);
}
if ( Mptr->TornadicMovDir[0] != '\0' ) {
sprintf(temp, "TORNADO DIR OF MOVM.: %s\n",
Mptr->TornadicMovDir );
strcat(string, temp);
}
if ( Mptr->autoIndicator[0] != '\0' ) {
sprintf(temp, "AUTO INDICATOR : %s\n",
Mptr->autoIndicator);
strcat(string, temp);
}
if ( Mptr->PKWND_dir != MAXINT ) {
sprintf(temp, "PEAK WIND DIRECTION : %d\n",Mptr->PKWND_dir);
strcat(string, temp);
}
if ( Mptr->PKWND_speed != MAXINT ) {
sprintf(temp, "PEAK WIND SPEED : %d\n",Mptr->PKWND_speed);
strcat(string, temp);
}
if ( Mptr->PKWND_hour != MAXINT ) {
sprintf(temp, "PEAK WIND HOUR : %d\n",Mptr->PKWND_hour);
strcat(string, temp);
}
if ( Mptr->PKWND_minute != MAXINT ) {
sprintf(temp, "PEAK WIND MINUTE : %d\n",Mptr->PKWND_minute);
strcat(string, temp);
}
if ( Mptr->WshfTime_hour != MAXINT ) {
sprintf(temp, "HOUR OF WIND SHIFT : %d\n",Mptr->WshfTime_hour);
strcat(string, temp);
}
if ( Mptr->WshfTime_minute != MAXINT ) {
sprintf(temp, "MINUTE OF WIND SHIFT: %d\n",Mptr->WshfTime_minute);
strcat(string, temp);
}
if ( Mptr->Wshft_FROPA != FALSE ) {
sprintf(temp, "FROPA ASSOC. W/WSHFT: TRUE\n");
strcat(string, temp);
}
if ( Mptr->TWR_VSBY != (float) MAXINT ) {
sprintf(temp, "TOWER VISIBILITY : %.2f\n",Mptr->TWR_VSBY);
strcat(string, temp);
}
if ( Mptr->SFC_VSBY != (float) MAXINT ) {
sprintf(temp, "SURFACE VISIBILITY : %.2f\n",Mptr->SFC_VSBY);
strcat(string, temp);
}
if ( Mptr->minVsby != (float) MAXINT ) {
sprintf(temp, "MIN VRBL_VIS (SM) : %.4f\n",Mptr->minVsby);
strcat(string, temp);
}
if ( Mptr->maxVsby != (float) MAXINT ) {
sprintf(temp, "MAX VRBL_VIS (SM) : %.4f\n",Mptr->maxVsby);
strcat(string, temp);
}
if( Mptr->VSBY_2ndSite != (float) MAXINT ) {
sprintf(temp, "VSBY_2ndSite (SM) : %.4f\n",Mptr->VSBY_2ndSite);
strcat(string, temp);
}
if( Mptr->VSBY_2ndSite_LOC[0] != '\0' ) {
sprintf(temp, "VSBY_2ndSite LOC. : %s\n",
Mptr->VSBY_2ndSite_LOC);
strcat(string, temp);
}
if ( Mptr->OCNL_LTG ) {
sprintf(temp, "OCCASSIONAL LTG : TRUE\n");
strcat(string, temp);
}
if ( Mptr->FRQ_LTG ) {
sprintf(temp, "FREQUENT LIGHTNING : TRUE\n");
strcat(string, temp);
}
if ( Mptr->CNS_LTG ) {
sprintf(temp, "CONTINUOUS LTG : TRUE\n");
strcat(string, temp);
}
if ( Mptr->CG_LTG ) {
sprintf(temp, "CLOUD-GROUND LTG : TRUE\n");
strcat(string, temp);
}
if ( Mptr->IC_LTG ) {
sprintf(temp, "IN-CLOUD LIGHTNING : TRUE\n");
strcat(string, temp);
}
if ( Mptr->CC_LTG ) {
sprintf(temp, "CLD-CLD LIGHTNING : TRUE\n");
strcat(string, temp);
}
if ( Mptr->CA_LTG ) {
sprintf(temp, "CLOUD-AIR LIGHTNING : TRUE\n");
strcat(string, temp);
}
if ( Mptr->AP_LTG ) {
sprintf(temp, "LIGHTNING AT AIRPORT: TRUE\n");
strcat(string, temp);
}
if ( Mptr->OVHD_LTG ) {
sprintf(temp, "LIGHTNING OVERHEAD : TRUE\n");
strcat(string, temp);
}
if ( Mptr->DSNT_LTG ) {
sprintf(temp, "DISTANT LIGHTNING : TRUE\n");
strcat(string, temp);
}
if ( Mptr->LightningVCTS ) {
sprintf(temp, "L'NING W/I 5-10(ALP): TRUE\n");
strcat(string, temp);
}
if ( Mptr->LightningTS ) {
sprintf(temp, "L'NING W/I 5 (ALP) : TRUE\n");
strcat(string, temp);
}
if ( Mptr->VcyStn_LTG ) {
sprintf(temp, "VCY STN LIGHTNING : TRUE\n");
strcat(string, temp);
}
if ( Mptr->LTG_DIR[0] != '\0' ) {
sprintf(temp, "DIREC. OF LIGHTNING : %s\n", Mptr->LTG_DIR);
strcat(string, temp);
}
i = 0;
while( i < 3 && Mptr->ReWx[ i ].Recent_weather[0] != '\0' )
{
sprintf(temp, "RECENT WEATHER : %s",
Mptr->ReWx[i].Recent_weather);
strcat(string, temp);
if ( Mptr->ReWx[i].Bhh != MAXINT ) {
sprintf(temp, " BEG_hh = %d",Mptr->ReWx[i].Bhh);
strcat(string, temp);
}
if ( Mptr->ReWx[i].Bmm != MAXINT ) {
sprintf(temp, " BEG_mm = %d",Mptr->ReWx[i].Bmm);
strcat(string, temp);
}
if ( Mptr->ReWx[i].Ehh != MAXINT ) {
sprintf(temp, " END_hh = %d",Mptr->ReWx[i].Ehh);
strcat(string, temp);
}
if ( Mptr->ReWx[i].Emm != MAXINT ) {
sprintf(temp, " END_mm = %d",Mptr->ReWx[i].Emm);
strcat(string, temp);
}
strcat(string, "\n");
i++;
}
if ( Mptr->minCeiling != MAXINT ) {
sprintf(temp, "MIN VRBL_CIG (FT) : %d\n",Mptr->minCeiling);
strcat(string, temp);
}
if ( Mptr->maxCeiling != MAXINT ) {
sprintf(temp, "MAX VRBL_CIG (FT)) : %d\n",Mptr->maxCeiling);
strcat(string, temp);
}
if ( Mptr->CIG_2ndSite_Meters != MAXINT ) {
sprintf(temp, "CIG2ndSite (FT) : %d\n",Mptr->CIG_2ndSite_Meters);
strcat(string, temp);
}
if ( Mptr->CIG_2ndSite_LOC[0] != '\0' ) {
sprintf(temp, "CIG @ 2nd Site LOC. : %s\n",Mptr->CIG_2ndSite_LOC);
strcat(string, temp);
}
if ( Mptr->PRESFR ) {
sprintf(temp, "PRESFR : TRUE\n");
strcat(string, temp);
}
if ( Mptr->PRESRR ) {
sprintf(temp, "PRESRR : TRUE\n");
strcat(string, temp);
}
if ( Mptr->SLPNO ) {
sprintf(temp, "SLPNO : TRUE\n");
strcat(string, temp);
}
if ( Mptr->SLP != (float) MAXINT ) {
sprintf(temp, "SLP (hPa) : %.1f\n", Mptr->SLP);
strcat(string, temp);
}
if ( Mptr->SectorVsby != (float) MAXINT ) {
sprintf(temp, "SECTOR VSBY (MILES) : %.2f\n", Mptr->SectorVsby );
strcat(string, temp);
}
if ( Mptr->SectorVsby_Dir[ 0 ] != '\0' ) {
sprintf(temp, "SECTOR VSBY OCTANT : %s\n", Mptr->SectorVsby_Dir );
strcat(string, temp);
}
if ( Mptr->TS_LOC[ 0 ] != '\0' ) {
sprintf(temp, "THUNDERSTORM LOCAT. : %s\n", Mptr->TS_LOC );
strcat(string, temp);
}
if ( Mptr->TS_MOVMNT[ 0 ] != '\0' ) {
sprintf(temp, "THUNDERSTORM MOVMNT.: %s\n", Mptr->TS_MOVMNT);
strcat(string, temp);
}
if ( Mptr->GR ) {
sprintf(temp, "GR (HAILSTONES) : TRUE\n");
strcat(string, temp);
}
if ( Mptr->GR_Size != (float) MAXINT ) {
sprintf(temp, "HLSTO SIZE (INCHES) : %.3f\n",Mptr->GR_Size);
strcat(string, temp);
}
if ( Mptr->VIRGA ) {
sprintf(temp, "VIRGA : TRUE\n");
strcat(string, temp);
}
if ( Mptr->VIRGA_DIR[0] != '\0' ) {
sprintf(temp, "DIR OF VIRGA FRM STN: %s\n", Mptr->VIRGA_DIR);
strcat(string, temp);
}
for( i = 0; i < 6; i++ ) {
if( Mptr->SfcObscuration[i][0] != '\0' ) {
sprintf(temp, "SfcObscuration : %s\n",
&(Mptr->SfcObscuration[i][0]) );
strcat(string, temp);
}
}
if ( Mptr->Num8thsSkyObscured != MAXINT ) {
sprintf(temp, "8ths of SkyObscured : %d\n",Mptr->Num8thsSkyObscured);
strcat(string, temp);
}
if ( Mptr->CIGNO ) {
sprintf(temp, "CIGNO : TRUE\n");
strcat(string, temp);
}
if ( Mptr->Ceiling != MAXINT ) {
sprintf(temp, "Ceiling (ft) : %d\n",Mptr->Ceiling);
strcat(string, temp);
}
if ( Mptr->Estimated_Ceiling != MAXINT ) {
sprintf(temp, "Estimated CIG (ft) : %d\n",Mptr->Estimated_Ceiling);
strcat(string, temp);
}
if ( Mptr->VrbSkyBelow[0] != '\0' ) {
sprintf(temp, "VRB SKY COND BELOW : %s\n",Mptr->VrbSkyBelow);
strcat(string, temp);
}
if ( Mptr->VrbSkyAbove[0] != '\0' ) {
sprintf(temp, "VRB SKY COND ABOVE : %s\n",Mptr->VrbSkyAbove);
strcat(string, temp);
}
if ( Mptr->VrbSkyLayerHgt != MAXINT ) {
sprintf(temp, "VRBSKY COND HGT (FT): %d\n",Mptr->VrbSkyLayerHgt);
strcat(string, temp);
}
if ( Mptr->ObscurAloftHgt != MAXINT ) {
sprintf(temp, "Hgt Obscur Aloft(ft): %d\n",Mptr->ObscurAloftHgt);
strcat(string, temp);
}
if ( Mptr->ObscurAloft[0] != '\0' ) {
sprintf(temp, "Obscur Phenom Aloft : %s\n",Mptr->ObscurAloft);
strcat(string, temp);
}
if ( Mptr->ObscurAloftSkyCond[0] != '\0' ) {
sprintf(temp, "Obscur ALOFT SKYCOND: %s\n",Mptr->ObscurAloftSkyCond);
strcat(string, temp);
}
if ( Mptr->NOSPECI ) {
sprintf(temp, "NOSPECI : TRUE\n");
strcat(string, temp);
}
if ( Mptr->LAST ) {
sprintf(temp, "LAST : TRUE\n");
strcat(string, temp);
}
if ( Mptr->synoptic_cloud_type[ 0 ] != '\0' ) {
sprintf(temp, "SYNOPTIC CLOUD GROUP: %s\n",Mptr->synoptic_cloud_type);
strcat(string, temp);
}
if ( Mptr->CloudLow != '\0' ) {
sprintf(temp, "LOW CLOUD CODE : %c\n",Mptr->CloudLow);
strcat(string, temp);
}
if ( Mptr->CloudMedium != '\0' ) {
sprintf(temp, "MEDIUM CLOUD CODE : %c\n",Mptr->CloudMedium);
strcat(string, temp);
}
if ( Mptr->CloudHigh != '\0' ) {
sprintf(temp, "HIGH CLOUD CODE : %c\n",Mptr->CloudHigh);
strcat(string, temp);
}
if ( Mptr->SNINCR != MAXINT ) {
sprintf(temp, "SNINCR (INCHES) : %d\n",Mptr->SNINCR);
strcat(string, temp);
}
if ( Mptr->SNINCR_TotalDepth != MAXINT ) {
sprintf(temp, "SNINCR(TOT. INCHES) : %d\n",Mptr->SNINCR_TotalDepth);
strcat(string, temp);
}
if ( Mptr->snow_depth_group[ 0 ] != '\0' ) {
sprintf(temp, "SNOW DEPTH GROUP : %s\n",Mptr->snow_depth_group);
strcat(string, temp);
}
if ( Mptr->snow_depth != MAXINT ) {
sprintf(temp, "SNOW DEPTH (INCHES) : %d\n",Mptr->snow_depth);
strcat(string, temp);
}
if ( Mptr->WaterEquivSnow != (float) MAXINT ) {
sprintf(temp, "H2O EquivSno(inches): %.2f\n",Mptr->WaterEquivSnow);
strcat(string, temp);
}
if ( Mptr->SunshineDur != MAXINT ) {
sprintf(temp, "SUNSHINE (MINUTES) : %d\n",Mptr->SunshineDur);
strcat(string, temp);
}
if ( Mptr->SunSensorOut ) {
sprintf(temp, "SUN SENSOR OUT : TRUE\n");
strcat(string, temp);
}
if ( Mptr->hourlyPrecip != (float) MAXINT ) {
sprintf(temp, "HRLY PRECIP (INCHES): %.2f\n",Mptr->hourlyPrecip);
strcat(string, temp);
}
if( Mptr->precip_amt != (float) MAXINT) {
sprintf(temp, "3/6HR PRCIP (INCHES): %.2f\n",
Mptr->precip_amt);
strcat(string, temp);
}
if( Mptr->Indeterminant3_6HrPrecip ) {
sprintf(temp, "INDTRMN 3/6HR PRECIP: TRUE\n");
strcat(string, temp);
}
if( Mptr->precip_24_amt != (float) MAXINT) {
sprintf(temp, "24HR PRECIP (INCHES): %.2f\n",
Mptr->precip_24_amt);
strcat(string, temp);
}
if ( Mptr->Indeterminant_24HrPrecip ) {
sprintf(temp, "INDTRMN 24 HR PRECIP: TRUE\n");
strcat(string, temp);
}
if ( Mptr->Temp_2_tenths != (float) MAXINT ) {
sprintf(temp, "TMP2TENTHS (CELSIUS): %.1f\n",Mptr->Temp_2_tenths);
strcat(string, temp);
}
if ( Mptr->DP_Temp_2_tenths != (float) MAXINT ) {
sprintf(temp, "DPT2TENTHS (CELSIUS): %.1f\n",Mptr->DP_Temp_2_tenths);
strcat(string, temp);
}
if ( Mptr->maxtemp != (float) MAXINT) {
sprintf(temp, "MAX TEMP (CELSIUS) : %.1f\n",
Mptr->maxtemp);
strcat(string, temp);
}
if ( Mptr->mintemp != (float) MAXINT) {
sprintf(temp, "MIN TEMP (CELSIUS) : %.1f\n",
Mptr->mintemp);
strcat(string, temp);
}
if ( Mptr->max24temp != (float) MAXINT) {
sprintf(temp, "24HrMAXTMP (CELSIUS): %.1f\n",
Mptr->max24temp);
strcat(string, temp);
}
if ( Mptr->min24temp != (float) MAXINT) {
sprintf(temp, "24HrMINTMP (CELSIUS): %.1f\n",
Mptr->min24temp);
strcat(string, temp);
}
if ( Mptr->char_prestndcy != MAXINT) {
sprintf(temp, "CHAR PRESS TENDENCY : %d\n",
Mptr->char_prestndcy );
strcat(string, temp);
}
if ( Mptr->prestndcy != (float) MAXINT) {
sprintf(temp, "PRES. TENDENCY (hPa): %.1f\n",
Mptr->prestndcy );
strcat(string, temp);
}
if ( Mptr->PWINO ) {
sprintf(temp, "PWINO : TRUE\n");
strcat(string, temp);
}
if ( Mptr->PNO ) {
sprintf(temp, "PNO : TRUE\n");
strcat(string, temp);
}
if ( Mptr->CHINO ) {
sprintf(temp, "CHINO : TRUE\n");
strcat(string, temp);
}
if ( Mptr->CHINO_LOC[0] != '\0' ) {
sprintf(temp, "CHINO_LOC : %s\n",Mptr->CHINO_LOC);
strcat(string, temp);
}
if ( Mptr->VISNO ) {
sprintf(temp, "VISNO : TRUE\n");
strcat(string, temp);
}
if ( Mptr->VISNO_LOC[0] != '\0' ) {
sprintf(temp, "VISNO_LOC : %s\n",Mptr->VISNO_LOC);
strcat(string, temp);
}
if ( Mptr->FZRANO ) {
sprintf(temp, "FZRANO : TRUE\n");
strcat(string, temp);
}
if ( Mptr->TSNO ) {
sprintf(temp, "TSNO : TRUE\n");
strcat(string, temp);
}
if ( Mptr->DollarSign) {
sprintf(temp, "DOLLAR $IGN INDCATR : TRUE\n");
strcat(string, temp);
}
if ( Mptr->horiz_vsby[ 0 ] != '\0' ) {
sprintf(temp, "HORIZ VISIBILITY : %s\n",Mptr->horiz_vsby);
strcat(string, temp);
}
if ( Mptr->dir_min_horiz_vsby[ 0 ] != '\0' ) {
sprintf(temp, "DIR MIN HORIZ VSBY : %s\n",Mptr->dir_min_horiz_vsby);
strcat(string, temp);
}
if ( Mptr->CAVOK ) {
sprintf(temp, "CAVOK : TRUE\n");
strcat(string, temp);
}
if( Mptr->VertVsby != MAXINT ) {
sprintf(temp, "Vert. Vsby (meters) : %d\n",
Mptr->VertVsby );
strcat(string, temp);
}
*/
/*
if( Mptr->charVertVsby[0] != '\0' )
sprintf(temp, "Vert. Vsby (CHAR) : %s\n",
Mptr->charVertVsby );
*/
/*
if ( Mptr->QFE != MAXINT ) {
sprintf(temp, "QFE : %d\n", Mptr->QFE);
strcat(string, temp);
}
if ( Mptr->VOLCASH ) {
sprintf(temp, "VOLCANIC ASH : TRUE\n");
strcat(string, temp);
}
if ( Mptr->min_vrbl_wind_dir != MAXINT ) {
sprintf(temp, "MIN VRBL WIND DIR : %d\n",Mptr->min_vrbl_wind_dir);
strcat(string, temp);
}
if ( Mptr->max_vrbl_wind_dir != MAXINT ) {
sprintf(temp, "MAX VRBL WIND DIR : %d\n",Mptr->max_vrbl_wind_dir);
strcat(string, temp);
}
*/
strcat(string, "\n\n\n");
}
void prtDMETR (Decoded_METAR *Mptr)
{
char string[5000];
sprint_metar(string, Mptr);
printf(string);
}

Wyświetl plik

@ -0,0 +1,230 @@
/*
METAR Decoder Software Package Library: Parses Aviation Routine Weather Reports
Copyright (C) 2003 Eric McCarthy
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#pragma comment (compiler)
#pragma comment (date)
#pragma comment (timestamp)
#pragma pagesize(80)
#include "local.h" /* standard header file */
#pragma page(1)
#pragma subtitle(" ")
#pragma subtitle("stspack2 - Local string test functions ")
/********************************************************************/
/* */
/* Title: stspack2 */
/* Organization: W/OSO242 - GRAPHICS AND DISPLAY SECTION */
/* Date: 05 Oct 1992 */
/* Programmer: ALLAN DARLING */
/* Language: C/2 */
/* */
/* Abstract: The stspack2 package contains functions to */
/* perform the isalnum through isxdigit functions */
/* on strings. The functions come in four forms: */
/* those that test NULL delimited strings and are */
/* named in the form sxxxxxxx, those that test at */
/* most n characters and are named in the form */
/* nxxxxxxx, those that search forward in a string */
/* and are named in the form nxtyyyyy, and those */
/* that search backward in a string and are named */
/* in the form lstyyyyy. */
/* */
/* The xxxxxxx is the name of the test applied to */
/* each character in the string, such as isalpha, */
/* thus a function to test a NULL delimited string */
/* an return a nonzero value if all characters in */
/* the string are digits is named sisdigit. */
/* */
/* The yyyyy is the name of the test applied to */
/* characters in a string, minus the 'is' prefix. */
/* Thus a function to find the next digit in a NULL */
/* delimited string and return a pointer to it is */
/* named nxtdigit. */
/* */
/* The only exception to the naming rule is for the */
/* functions that test for hexadecimal digits. */
/* These are named sisxdigi, nisxdigi, nxtxdigi, */
/* and lstxdigi because of the eight character */
/* function name limitation. */
/* */
/* The nxxxxxxx class of functions will test up to */
/* n characters or the first NULL character */
/* encountered, whichever comes first. For all */
/* classes of functions, the string sentinal is */
/* not included in the test. */
/* */
/* External Functions Called: */
/* isalnum, isalpha, iscntrl, isdigit, isgraph, */
/* islower, isprint, ispunct, isspace, isupper, */
/* isxdigit. */
/* */
/* Input: For sxxxxxxx class functions, a pointer to a */
/* NULL delimited character string. */
/* */
/* For nxtyyyyy class functions, a pointer to a */
/* NULL delimited character string. */
/* */
/* for nxxxxxxx class functions, a pointer to a */
/* character array, and a positive, nonzero integer.*/
/* */
/* for lstyyyyy class functions, a pointer to a */
/* character array, and a positive, nonzero integer.*/
/* */
/* Output: A nonzero value if the test is true for all */
/* characters in the string, a zero value otherwise.*/
/* */
/* Modification History: */
/* None. */
/* */
/********************************************************************/
#pragma page(1)
int nisalnum(char *s, int n) {
for (; *s && n; s++, n--)
if (!isalnum(*s))
return (0);
return (1);
} /* end nisalnum */
int nisalpha(char *s, int n) {
for (; *s && n; s++, n--)
if (!isalpha(*s))
return (0);
return (1);
} /* end nisalpha */
int niscntrl(char *s, int n) {
for (; *s && n; s++, n--)
if (!iscntrl(*s))
return (0);
return (1);
} /* end niscntrl */
int nisdigit(char *s, int n) {
for (; *s && n; s++, n--)
if (!isdigit(*s))
return (0);
return (1);
} /* end nisdigit */
int nisgraph(char *s, int n) {
for (; *s && n; s++, n--)
if (!isgraph(*s))
return (0);
return (1);
} /* end nisgraph */
int nislower(char *s, int n) {
for (; *s && n; s++, n--)
if (!islower(*s))
return (0);
return (1);
} /* end nislower */
int nisprint(char *s, int n) {
for (; *s && n; s++, n--)
if (!isprint(*s))
return (0);
return (1);
} /* end nisprint */
int nispunct(char *s, int n) {
for (; *s && n; s++, n--)
if (!ispunct(*s))
return (0);
return (1);
} /* end nispunct */
int nisspace(char *s, int n) {
for (; *s && n; s++, n--)
if (!isspace(*s))
return (0);
return (1);
} /* end nisspace */
int nisupper(char *s, int n) {
for (; *s && n; s++, n--)
if (!isupper(*s))
return (0);
return (1);
} /* end nisupper */
int nisxdigi(char *s, int n) {
for (; *s && n; s++, n--)
if (!isxdigit(*s))
return (0);
return (1);
} /* end nisxdigi */
#pragma page(1)

Wyświetl plik

@ -0,0 +1,230 @@
/*
METAR Decoder Software Package Library: Parses Aviation Routine Weather Reports
Copyright (C) 2003 Eric McCarthy
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#pragma comment (compiler)
#pragma comment (date)
#pragma comment (timestamp)
#pragma pagesize(80)
#include "local.h" /* standard header file */
#pragma page(1)
#pragma subtitle(" ")
#pragma subtitle("stspack3 - Local string test functions ")
/********************************************************************/
/* */
/* Title: stspack3 */
/* Organization: W/OSO242 - GRAPHICS AND DISPLAY SECTION */
/* Date: 05 Oct 1992 */
/* Programmer: ALLAN DARLING */
/* Language: C/2 */
/* */
/* Abstract: The stspack3 package contains functions to */
/* perform the isalnum through isxdigit functions */
/* on strings. The functions come in four forms: */
/* those that test NULL delimited strings and are */
/* named in the form sxxxxxxx, those that test at */
/* most n characters and are named in the form */
/* nxxxxxxx, those that search forward in a string */
/* and are named in the form nxtyyyyy, and those */
/* that search backward in a string and are named */
/* in the form lstyyyyy. */
/* */
/* The xxxxxxx is the name of the test applied to */
/* each character in the string, such as isalpha, */
/* thus a function to test a NULL delimited string */
/* an return a nonzero value if all characters in */
/* the string are digits is named sisdigit. */
/* */
/* The yyyyy is the name of the test applied to */
/* characters in a string, minus the 'is' prefix. */
/* Thus a function to find the next digit in a NULL */
/* delimited string and return a pointer to it is */
/* named nxtdigit. */
/* */
/* The only exception to the naming rule is for the */
/* functions that test for hexadecimal digits. */
/* These are named sisxdigi, nisxdigi, nxtxdigi, */
/* and lstxdigi because of the eight character */
/* function name limitation. */
/* */
/* The nxxxxxxx class of functions will test up to */
/* n characters or the first NULL character */
/* encountered, whichever comes first. For all */
/* classes of functions, the string sentinal is */
/* not included in the test. */
/* */
/* External Functions Called: */
/* isalnum, isalpha, iscntrl, isdigit, isgraph, */
/* islower, isprint, ispunct, isspace, isupper, */
/* isxdigit. */
/* */
/* Input: For sxxxxxxx class functions, a pointer to a */
/* NULL delimited character string. */
/* */
/* For nxtyyyyy class functions, a pointer to a */
/* NULL delimited character string. */
/* */
/* for nxxxxxxx class functions, a pointer to a */
/* character array, and a positive, nonzero integer.*/
/* */
/* for lstyyyyy class functions, a pointer to a */
/* character array, and a positive, nonzero integer.*/
/* */
/* Output: A nonzero value if the test is true for all */
/* characters in the string, a zero value otherwise.*/
/* */
/* Modification History: */
/* None. */
/* */
/********************************************************************/
#pragma page(1)
char *nxtalnum(char *s) {
for (; !isalnum(*s) && *s; s++) ;
if (*s)
return (s);
else
return (NULL);
} /* end nxtalnum */
char *nxtalpha(char *s) {
for (; !isalpha(*s) && *s; s++) ;
if (*s)
return (s);
else
return (NULL);
} /* end nxtalpha */
char *nxtcntrl(char *s) {
for (; !iscntrl(*s) && *s; s++) ;
if (*s)
return (s);
else
return (NULL);
} /* end nxtcntrl */
char *nxtdigit(char *s) {
for (; !isdigit(*s) && *s; s++) ;
if (*s)
return (s);
else
return (NULL);
} /* end nxtdigit */
char *nxtgraph(char *s) {
for (; !isgraph(*s) && *s; s++) ;
if (*s)
return (s);
else
return (NULL);
} /* end nxtgraph */
char *nxtlower(char *s) {
for (; !islower(*s) && *s; s++) ;
if (*s)
return (s);
else
return (NULL);
} /* end nxtlower */
char *nxtprint(char *s) {
for (; !isprint(*s) && *s; s++) ;
if (*s)
return (s);
else
return (NULL);
} /* end nxtprint */
char *nxtpunct(char *s) {
for (; !ispunct(*s) && *s; s++) ;
if (*s)
return (s);
else
return (NULL);
} /* end nxtpunct */
char *nxtspace(char *s) {
for (; !isspace(*s) && *s; s++) ;
if (*s)
return (s);
else
return (NULL);
} /* end nxtspace */
char *nxtupper(char *s) {
for (; !isupper(*s) && *s; s++) ;
if (*s)
return (s);
else
return (NULL);
} /* end nxtupper */
char *nxtxdigi(char *s) {
for (; !isxdigit(*s) && *s; s++) ;
if (*s)
return (s);
else
return (NULL);
} /* end nxtxdigi */
#pragma page(1)

73
test/mtk_config.sh 100755
Wyświetl plik

@ -0,0 +1,73 @@
#!/bin/bash
#
# mtk_config.sh: Script to set up MTK3339 receiver for Stratux.
# Resets receiver to 9600 and 1 Hz GPRMC messaging, then enables
# WAAS, 5 Hz position reporting, the NMEA messages needed by
# Stratux, and 38400 bps serial output.
printf "About to configure MTK3339 receiver on /dev/ttyAMA0.\n"
printf "Press ctrl-C to abort or any other key to continue.\n"
read
# Iterate through common bitrates and send commands to reduce output to 1 Hz / 9600 bps.
printf "Setting MTK and RPi baud rate of /dev/ttyAMA0 to 9600. Iterating through common rates.\n"
printf "Current /dev/ttyAMA0 baudrate.\n"
printf "\$PMTK220,1000*1F\r\n" > /dev/ttyAMA0
printf "\$PMTK251,9600*17\r\n" > /dev/ttyAMA0
sleep 0.2
printf "38400 bps.\n"
stty -F /dev/ttyAMA0 38400
printf "\$PMTK220,1000*1F\r\n" > /dev/ttyAMA0
printf "\$PMTK251,9600*17\r\n" > /dev/ttyAMA0
sleep 0.2
printf "115200 bps.\n"
printf "\$PMTK220,1000*1F\r\n" > /dev/ttyAMA0
stty -F /dev/ttyAMA0 115200
printf "\$PMTK220,1000*1F\r\n" > /dev/ttyAMA0
printf "\$PMTK251,9600*17\r\n" > /dev/ttyAMA0
sleep 0.2
printf "57600 bps.\n"
stty -F /dev/ttyAMA0 57600
printf "\$PMTK220,1000*1F\r\n" > /dev/ttyAMA0
printf "\$PMTK251,9600*17\r\n" > /dev/ttyAMA0
sleep 0.2
printf "19200 bps.\n"
stty -F /dev/ttyAMA0 19200
printf "\$PMTK220,1000*1F\r\n" > /dev/ttyAMA0
printf "\$PMTK251,9600*17\r\n" > /dev/ttyAMA0
sleep 0.2
printf "4800 bps.\n"
stty -F /dev/ttyAMA0 4800
printf "\$PMTK220,1000*1F\r\n" > /dev/ttyAMA0
printf "\$PMTK251,9600*17\r\n" > /dev/ttyAMA0
sleep 0.2
stty -F /dev/ttyAMA0 9600
printf "\$PMTK314,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*29\r\n" > /dev/ttyAMA0
printf "MTK has been set to 9600 baud with RMC messages at 1 Hz.\n"
printf "Press ctrl-C to abort, or any other key enter to continue with setup.\n"
read
# Now start the Stratux setup.
printf "Sending MTK command to set GPS baud rate to 38400\n"
printf "\$PMTK251,38400*27\r\n" > /dev/ttyAMA0
printf "Setting RPi baud rate of /dev/ttyAMA0 to 38400\n"
stty -F /dev/ttyAMA0 38400
sleep 0.2
printf "Sending MTK command to configure NMEA message output\n"
printf "\$PMTK314,0,1,1,1,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0*29\r\n" > /dev/ttyAMA0
sleep 0.2
printf "Sending MTK commands to enable WAAS\n"
printf "\$PMTK301,2*2E\r\n" > /dev/ttyAMA0
sleep 0.2
printf "\$PMTK513,1*28\r\n" > /dev/ttyAMA0
sleep 0.2
printf "Sending MTK commands to enable 5 Hz position reporting\n"
printf "\$PMTK220,200*2C\r\n" > /dev/ttyAMA0
# Finally, test the connection.
printf "Opening /dev/ttyAMA0 to listen to GPS. Press ctrl-C to cancel.\n"
cat /dev/ttyAMA0

Wyświetl plik

@ -1,19 +1,18 @@
package main
import (
"fmt"
// "time"
"os"
// "time"
"bufio"
"gonum.org/v1/plot"
"gonum.org/v1/plot/plotter"
"gonum.org/v1/plot/plotutil"
"gonum.org/v1/plot/vg"
"os"
"sort"
"strconv"
"strings"
"unicode"
"strconv"
"github.com/gonum/plot"
"github.com/gonum/plot/plotter"
"github.com/gonum/plot/plotutil"
"github.com/gonum/plot/vg"
"sort"
)
func main() {
@ -37,7 +36,7 @@ func main() {
if err != nil {
break
}
buf = strings.TrimFunc(buf, func(r rune) bool {return unicode.IsControl(r)})
buf = strings.TrimFunc(buf, func(r rune) bool { return unicode.IsControl(r) })
linesplit := strings.Split(buf, ",")
if len(linesplit) < 2 { // Blank line or invalid.
continue
@ -53,10 +52,10 @@ func main() {
// Window number in current session.
wnum := int64(i / (60 * 1000000000))
// fmt.Printf("%d\n", curWindow)
if wnum + windowOffset != curWindow { // Switched over.
// fmt.Printf("%d\n", curWindow)
if wnum+windowOffset != curWindow { // Switched over.
curWindow = wnum + windowOffset
fmt.Printf("ppm=%d\n", ppm[curWindow - 1])
fmt.Printf("ppm=%d\n", ppm[curWindow-1])
}
ppm[curWindow]++
}
@ -80,7 +79,7 @@ func main() {
pts := make(plotter.XYs, len(ppm))
i := 0
for _,k := range keys {
for _, k := range keys {
v := ppm[int64(k)]
fmt.Printf("%d, %d\n", k, v)
pts[i].X = float64(k)
@ -92,7 +91,7 @@ func main() {
if err != nil {
panic(err)
}
if err := p.Save(4 * vg.Inch, 4 * vg.Inch, "ppm.png"); err != nil {
if err := p.Save(4*vg.Inch, 4*vg.Inch, "ppm.png"); err != nil {
panic(err)
}
}
}

Plik binarny nie jest wyświetlany.

Wyświetl plik

@ -0,0 +1,94 @@
#!/usr/bin/env python
from luma.core.interface.serial import i2c
from luma.oled.device import ssd1306, sh1106
from luma.core.render import canvas
from PIL import ImageDraw, ImageFont, Image
import urllib2
import json
import time
from daemon import runner
class StratuxScreen():
def __init__(self):
self.stdin_path = '/dev/null'
self.stdout_path = '/var/log/stratux-screen.log'
self.stderr_path = '/var/log/stratux-screen.log'
self.pidfile_path = '/var/run/stratux-screen.pid'
self.pidfile_timeout = 5
def run(self):
font2 = ImageFont.truetype('/etc/stratux-screen/CnC_Red_Alert.ttf', 12)
serial = i2c(port=1, address=0x3c)
oled = ssd1306(serial)
with canvas(oled) as draw:
logo = Image.open('/etc/stratux-screen/stratux-logo-64x64.bmp')
draw.bitmap((32, 0), logo, fill=1)
time.sleep(10)
n = 0
while 1:
time.sleep(1)
response = urllib2.urlopen('http://localhost/getStatus')
getStatusHTML = response.read()
getStatusData = json.loads(getStatusHTML)
CPUTemp = getStatusData["CPUTemp"]
uat_current = getStatusData["UAT_messages_last_minute"]
uat_max = getStatusData["UAT_messages_max"]
es_current = getStatusData["ES_messages_last_minute"]
es_max = getStatusData["ES_messages_max"]
response = urllib2.urlopen('http://localhost/getTowers')
getTowersHTML = response.read()
getTowersData = json.loads(getTowersHTML)
NumTowers = 0
for towerLatLng in getTowersData:
print getTowersData[towerLatLng]["Messages_last_minute"]
if (getTowersData[towerLatLng]["Messages_last_minute"] > 0):
NumTowers += 1
with canvas(oled) as draw:
pad = 2 # Two pixels on the left and right.
text_margin = 25
# UAT status.
draw.text((50, 0), "UAT", font=font2, fill=255)
# "Status bar", 2 pixels high.
status_bar_width_max = oled.width - (2 * pad) - (2 * text_margin)
status_bar_width = 0
if uat_max > 0:
status_bar_width = int((float(uat_current) / uat_max) * status_bar_width_max)
draw.rectangle((pad + text_margin, 14, pad + text_margin + status_bar_width, 20), outline=255, fill=255) # Top left, bottom right.
# Draw the current (left) and max (right) numbers.
draw.text((pad, 14), str(uat_current), font=font2, fill=255)
draw.text(((2*pad) + text_margin + status_bar_width_max, 14), str(uat_max), font=font2, fill=255)
# ES status.
draw.text((44, 24), "1090ES", font=font2, fill=255)
status_bar_width = 0
if es_max > 0:
status_bar_width = int((float(es_current) / es_max) * status_bar_width_max)
draw.rectangle((pad + text_margin, 34, pad + text_margin + status_bar_width, 40), outline=255, fill=255) # Top left, bottom right.
# Draw the current (left) and max (right) numbers.
draw.text((pad, 34), str(es_current), font=font2, fill=255)
draw.text(((2*pad) + text_margin + status_bar_width_max, 34), str(es_max), font=font2, fill=255)
# Other stats.
seq = (n / 5) % 2
t = ""
if seq == 0:
t = "CPU: %0.1fC, Towers: %d" % (CPUTemp, NumTowers)
if seq == 1:
t = "GPS Sat: %d/%d/%d" % (getStatusData["GPS_satellites_locked"], getStatusData["GPS_satellites_seen"], getStatusData["GPS_satellites_tracked"])
if getStatusData["GPS_solution"] == "GPS + SBAS (WAAS / EGNOS)":
t = t + " (WAAS)"
#print t
draw.text((pad, 45), t, font=font2, fill=255)
n = n+1
stratuxscreen = StratuxScreen()
daemon_runner = runner.DaemonRunner(stratuxscreen)
daemon_runner.do_action()

Some files were not shown because too many files have changed in this diff Show More