Porównaj commity

...

45 Commity

Autor SHA1 Wiadomość Data
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
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
30 zmienionych plików z 505 dodań i 474 usunięć

Wyświetl plik

@ -7,9 +7,7 @@
RTL-SDR UAT tools
Use with Raspberry Pi 3.
Raspberry Pi 2 with the Edimax EW-7811Un Wi-Fi dongle is supported but not recommended for new builds.
Use with Raspberry Pi 3B. The 3B+ and Pi 4B will work but use a lot more power.
Tested and works well with most common R820T and R820T2 RTL-SDR devices.
@ -25,6 +23,7 @@ Apps with stratux recognition/support:
* iFly GPS 9.4+.
* DroidEFB 2.1.1+.
* kwikEFIS
* Pilots Atlas
Tested weather/traffic displays:
* Avare
@ -48,3 +47,4 @@ Jet tests (high gain antennas):
* Lear 35
* Rockwell B-1b
* Boeing C-17
* Gulfstream G450

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

Wyświetl plik

@ -2,10 +2,12 @@
# Auto-detect common USB stratux peripherals.
# u-blox devices. Known devices include
# ublox8: RY835AI, RY836AI
# ublox7: VK-172, RY725AI
# 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"
@ -41,3 +43,6 @@ SUBSYSTEMS=="usb", ATTRS{interface}=="Stratux Serialout", SYMLINK+="serialout%n"
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,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,118 +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;
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

@ -90,6 +90,7 @@ const (
GPS_TYPE_GARMIN = 0x06
*/
GPS_TYPE_UBX9 = 0x09
GPS_TYPE_UBX8 = 0x08
GPS_TYPE_UBX7 = 0x07
GPS_TYPE_UBX6 = 0x06
@ -294,18 +295,24 @@ func makeOwnshipReport() bool {
// See p.16.
msg[0] = 0x0A // Message type "Ownship".
msg[1] = 0x01 // Alert status, address type.
// Retrieve ICAO code from settings
code, _ := hex.DecodeString(globalSettings.OwnshipModeS)
if len(code) != 3 {
// Ownship Target Identify (see 3.5.1.2 of GDL-90 Specifications)
// First half of byte is 0 for Alert type of 'No Traffic Alert'
// Second half of byte is 0 for traffic type 'ADS-B with ICAO'
// Send 0x01 by default, unless ICAO is set, send 0x00
if (len(code) == 3 && code[0] != 0xF0 && code[0] != 0x00) {
msg[1] = 0x00 // ADS-B Out with ICAO
msg[2] = code[0] // Mode S address.
msg[3] = code[1] // Mode S address.
msg[4] = code[2] // Mode S address.
} else {
msg[1] = 0x01 // ADS-B Out with self-assigned code
// Reserved dummy code.
msg[2] = 0xF0
msg[3] = 0x00
msg[4] = 0x00
} else {
msg[2] = code[0] // Mode S address.
msg[3] = code[1] // Mode S address.
msg[4] = code[2] // Mode S address.
}
var tmp []byte
@ -1096,6 +1103,7 @@ func getProductNameFromId(product_id int) string {
}
type settings struct {
DarkMode bool
UAT_Enabled bool
ES_Enabled bool
Ping_Enabled bool
@ -1121,6 +1129,8 @@ type settings struct {
WiFiChannel int
WiFiSecurityEnabled bool
WiFiPassphrase string
WiFiSmartEnabled bool // "Smart WiFi" - disables the default gateway for iOS.
NoSleep bool
}
type status struct {
@ -1177,6 +1187,7 @@ var globalSettings settings
var globalStatus status
func defaultSettings() {
globalSettings.DarkMode = false
globalSettings.UAT_Enabled = true
globalSettings.ES_Enabled = true
globalSettings.GPS_Enabled = true
@ -1195,6 +1206,7 @@ func defaultSettings() {
globalSettings.OwnshipModeS = "F00000"
globalSettings.DeveloperMode = false
globalSettings.StaticIps = make([]string, 0)
globalSettings.NoSleep = false
}
func readSettings() {
@ -1305,6 +1317,14 @@ func saveWiFiUserSettings() {
fmt.Fprintf(writer, "wpa_passphrase=%s\n", globalSettings.WiFiPassphrase)
}
writer.Flush()
// "Smart WiFi". Just use one of two pre-made dhcpd config files.
dhcpd_config := "/etc/dhcp/dhcpd-not_smart.conf"
if globalSettings.WiFiSmartEnabled {
dhcpd_config = "/etc/dhcp/dhcpd-smart.conf"
}
os.Remove("/etc/dhcp/dhcpd.conf")
os.Symlink(dhcpd_config, "/etc/dhcp/dhcpd.conf")
}
func openReplay(fn string, compressed bool) (WriteCloser, error) {

Wyświetl plik

@ -195,10 +195,13 @@ func initGPSSerial() bool {
isSirfIV := bool(false)
globalStatus.GPS_detected_type = 0 // reset detected type on each initialization
if _, err := os.Stat("/dev/ublox8"); err == nil { // u-blox 8 (RY83xAI over USB).
if _, err := os.Stat("/dev/ublox9"); err == nil { // u-blox 8 (RY83xAI over USB).
device = "/dev/ublox9"
globalStatus.GPS_detected_type = GPS_TYPE_UBX9
} else if _, err := os.Stat("/dev/ublox8"); err == nil { // u-blox 8 (RY83xAI or GPYes 2.0).
device = "/dev/ublox8"
globalStatus.GPS_detected_type = GPS_TYPE_UBX8
} else if _, err := os.Stat("/dev/ublox7"); err == nil { // u-blox 7 (VK-172, VK-162 Rev 2, RY725AI over USB).
} else if _, err := os.Stat("/dev/ublox7"); err == nil { // u-blox 7 (VK-172, VK-162 Rev 2, GPYes, RY725AI over USB).
device = "/dev/ublox7"
globalStatus.GPS_detected_type = GPS_TYPE_UBX7
} else if _, err := os.Stat("/dev/ublox6"); err == nil { // u-blox 6 (VK-162 Rev 1).
@ -214,7 +217,9 @@ func initGPSSerial() bool {
device = "/dev/ttyAMA0"
globalStatus.GPS_detected_type = GPS_TYPE_UART
} else {
log.Printf("No suitable device found.\n")
if globalSettings.DEBUG {
log.Printf("No GPS device found.\n")
}
return false
}
if globalSettings.DEBUG {
@ -303,8 +308,10 @@ func initGPSSerial() bool {
glonass := []byte{0x06, 0x04, 0x0E, 0x00, 0x00, 0x00, 0x01, 0x01} // this disables GLONASS
galileo := []byte{0x02, 0x04, 0x08, 0x00, 0x00, 0x00, 0x01, 0x01} // this disables Galileo
if (globalStatus.GPS_detected_type == GPS_TYPE_UBX8) || (globalStatus.GPS_detected_type == GPS_TYPE_UART) { // assume that any GPS connected to serial GPIO is ublox8 (RY835/6AI)
log.Printf("UBX8 device detected on USB, or GPS serial connection in use. Attempting GLONASS and Galelio configuration.\n")
if (globalStatus.GPS_detected_type == GPS_TYPE_UBX8) || (globalStatus.GPS_detected_type == GPS_TYPE_UBX9) || (globalStatus.GPS_detected_type == GPS_TYPE_UART) { // assume that any GPS connected to serial GPIO is ublox8 (RY835/6AI)
if globalSettings.DEBUG {
log.Printf("UBX8/9/unknown device detected on USB, or GPS serial connection in use. Attempting GLONASS and Galelio configuration.\n")
}
glonass = []byte{0x06, 0x08, 0x0E, 0x00, 0x01, 0x00, 0x01, 0x01} // this enables GLONASS with 8-14 tracking channels
galileo = []byte{0x02, 0x04, 0x08, 0x00, 0x01, 0x00, 0x01, 0x01} // this enables Galileo with 4-8 tracking channels
updatespeed = []byte{0x06, 0x00, 0xF4, 0x01, 0x01, 0x00} // Nav speed 2Hz

Wyświetl plik

@ -271,6 +271,8 @@ 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":
@ -378,6 +380,9 @@ func handleSettingsSetRequest(w http.ResponseWriter, r *http.Request) {
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)
}

Wyświetl plik

@ -145,6 +145,9 @@ func getDHCPLeases() (map[string]string, error) {
***WARNING***: netMutex must be locked before calling this function.
*/
func isSleeping(k string) bool {
if globalSettings.NoSleep == true {
return false
}
ipAndPort := strings.Split(k, ":")
// No ping response. Assume disconnected/sleeping device.
if lastPing, ok := pingResponse[ipAndPort[0]]; !ok || stratuxClock.Since(lastPing) > (10*time.Second) {

Wyświetl plik

@ -19,6 +19,12 @@ 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 (
@ -123,13 +129,36 @@ func tempAndPressureSender() {
}
func initIMU() (ok bool) {
imu, err := sensors.NewMPU9250()
if err == nil {
myIMUReader = imu
return true
// 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
}
// TODO westphae: try to connect to MPU9150 or other IMUs.
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
}

Wyświetl plik

@ -223,7 +223,7 @@ func sendTrafficUpdates() {
if globalSettings.DEBUG {
log.Printf("Ownship target detected for code %X\n", code)
}
// OwnshipTrafficInfo = ti
OwnshipTrafficInfo = ti
} else {
cur_n := len(msgs) - 1
if len(msgs[cur_n]) >= 35 {

Wyświetl plik

@ -27,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
@ -233,17 +241,17 @@ Stratux makes available a webserver to retrieve statistics which may be useful t
"BaroPressureAltitude": 153.32,
"BaroVerticalSpeed": 1.3123479,
"BaroLastMeasurementTime": "0001-01-01T00:06:44.23Z",
"AHRSPitch": -0.97934145732801,
"AHRSRoll": -2.2013729217108,
"AHRSGyroHeading": 187741.08073052,
"AHRSMagHeading": 3276.7,
"AHRSSlipSkid": 0.52267604604907,
"AHRSTurnRate": 3276.7,
"AHRSGLoad": 0.99847599584255,
"AHRSGLoadMin": 0.99815989027411,
"AHRSGLoadMax": 1.0043409597397,
"AHRSLastAttitudeTime": "0001-01-01T00:06:44.28Z",
"AHRSStatus": 7
"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().
}
```

Wyświetl plik

@ -36,7 +36,8 @@ 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.conf 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/

Wyświetl plik

@ -87,7 +87,9 @@ cp -f ahrs_approx /usr/bin/
chmod 755 /usr/bin/ahrs_approx
# DHCPD Config.
cp -f dhcpd.conf /etc/dhcp/dhcpd.conf
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

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()
}

Wyświetl plik

@ -3,12 +3,13 @@ package sensors
import (
"../goflying/mpu9250"
"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.
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
@ -19,14 +20,14 @@ type MPU9250 struct {
// NewMPU9250 returns an instance of the MPU9250 IMUReader, connected to an
// MPU9250 attached on the I2C bus with either valid address.
func NewMPU9250() (*MPU9250, error) {
func NewMPU9250(i2cbus *embd.I2CBus) (*MPU9250, error) {
var (
m MPU9250
mpu *mpu9250.MPU9250
err error
)
mpu, err = mpu9250.NewMPU9250(gyroRange, accelRange, updateFreq, true, false)
mpu, err = mpu9250.NewMPU9250(i2cbus, mpu9250GyroRange, mpu9250AccelRange, mpu9250UpdateFreq, true, false)
if err != nil {
return nil, err
}

Wyświetl plik

@ -1,87 +0,0 @@
package main
import (
"bufio"
"fmt"
"github.com/gonum/plot"
"github.com/gonum/plot/plotter"
"github.com/gonum/plot/plotutil"
"github.com/gonum/plot/vg"
"net/http"
"os"
"strconv"
"strings"
"time"
)
type XY struct {
X float64
Y float64
}
func imageWriter() {
for {
p, err := plot.New()
if err != nil {
panic(err)
}
p.Title.Text = "AHRS Plot"
p.X.Label.Text = "Roll"
p.Y.Label.Text = "Pitch"
file, err := os.Open("ahrs_table.log")
if err != nil {
panic(err)
}
defer file.Close()
scanner := bufio.NewScanner(file)
vals := make([]XY, 0)
for scanner.Scan() {
l := scanner.Text()
x := strings.Split(l, ",")
if len(x) < 3 {
continue
}
roll, err := strconv.ParseFloat(x[0], 64)
if err != nil {
continue
}
pitch, err := strconv.ParseFloat(x[1], 64)
if err != nil {
continue
}
v := XY{X: roll, Y: pitch}
vals = append(vals, v)
}
vals_XY := make(plotter.XYs, len(vals))
for i := 0; i < len(vals); i++ {
vals_XY[i].X = vals[i].X
vals_XY[i].Y = vals[i].Y
}
err = plotutil.AddScatters(p, "First", vals_XY)
if err != nil {
panic(err)
}
if err := p.Save(8*vg.Inch, 8*vg.Inch, "out.png"); err != nil {
panic(err)
}
time.Sleep(1000 * time.Millisecond)
}
}
func main() {
go imageWriter()
http.Handle("/", http.FileServer(http.Dir(".")))
err := http.ListenAndServe(":8080", nil)
if err != nil {
fmt.Printf("managementInterface ListenAndServe: %s\n", err.Error())
}
for {
time.Sleep(1 * time.Second)
}
}

Wyświetl plik

@ -1,109 +0,0 @@
package main
import (
"encoding/hex"
"encoding/json"
"fmt"
"io/ioutil"
"net"
"net/http"
"os"
"sync"
"time"
)
const (
SITUATION_URL = "http://127.0.0.1/getSituation"
)
type MySituation struct {
AHRSRoll float64
AHRSPitch float64
}
var Location MySituation
var situationMutex *sync.Mutex
func chkErr(err error) {
if err != nil {
fmt.Printf("error: %s\n", err.Error())
os.Exit(1)
}
}
var currentAHRSString string
func listener() {
t := time.Now()
addr := net.UDPAddr{Port: 41504, IP: net.ParseIP("0.0.0.0")}
conn, err := net.ListenUDP("udp", &addr)
if err != nil {
fmt.Printf("error listening: %s\n", err.Error())
return
}
defer conn.Close()
for {
buf := make([]byte, 1024)
n, _, err := conn.ReadFrom(buf)
if err != nil {
fmt.Printf("Err receive: %s\n", err.Error())
continue
}
buf_encoded := make([]byte, hex.EncodedLen(n))
hex.Encode(buf_encoded, buf[:n])
t2 := time.Now()
time_diff := t2.Sub(t)
t = t2
fmt.Sprintf("%d,%s\n", time_diff/time.Millisecond, buf_encoded)
currentAHRSString = string(buf_encoded)
}
}
func situationUpdater() {
situationUpdateTicker := time.NewTicker(100 * time.Millisecond)
for {
<-situationUpdateTicker.C
situationMutex.Lock()
resp, err := http.Get(SITUATION_URL)
if err != nil {
fmt.Printf("HTTP GET error: %s\n", err.Error())
situationMutex.Unlock()
continue
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Printf("HTTP GET body error: %s\n", err.Error())
resp.Body.Close()
situationMutex.Unlock()
continue
}
// fmt.Printf("body: %s\n", string(body))
err = json.Unmarshal(body, &Location)
if err != nil {
fmt.Printf("HTTP JSON unmarshal error: %s\n", err.Error())
}
resp.Body.Close()
situationMutex.Unlock()
}
}
func main() {
situationMutex = &sync.Mutex{}
go listener()
go situationUpdater()
tm := time.NewTicker(125 * time.Millisecond)
for {
<-tm.C
fmt.Printf("%f,%f,%s\n", Location.AHRSRoll, Location.AHRSPitch, currentAHRSString)
}
}

Wyświetl plik

@ -1,34 +0,0 @@
package main
import (
"encoding/hex"
"fmt"
"net"
"time"
)
func main() {
t := time.Now()
addr := net.UDPAddr{Port: 41504, IP: net.ParseIP("0.0.0.0")}
conn, err := net.ListenUDP("udp", &addr)
if err != nil {
fmt.Printf("ffMonitor(): error listening: %s\n", err.Error())
return
}
defer conn.Close()
for {
buf := make([]byte, 1024)
n, _, err := conn.ReadFrom(buf)
if err != nil {
fmt.Printf("Err receive: %s\n", err.Error())
continue
}
buf_encoded := make([]byte, hex.EncodedLen(n))
hex.Encode(buf_encoded, buf[:n])
t2 := time.Now()
time_diff := t2.Sub(t)
t = t2
fmt.Printf("%d,%s\n", time_diff/time.Millisecond, buf_encoded)
}
}

Wyświetl plik

@ -1,67 +0,0 @@
package main
import (
"bufio"
"encoding/hex"
"fmt"
"net"
"os"
"strconv"
"strings"
"time"
)
func main() {
if len(os.Args) < 2 {
fmt.Printf("%s: <file>\n", os.Args[0])
return
}
f, err := os.Open(os.Args[1])
if err != nil {
fmt.Printf("error: %s\n", err.Error())
return
}
defer f.Close()
scanner := bufio.NewScanner(f)
// Open a socket.
BROADCAST_IPv4 := net.IPv4(255, 255, 255, 255)
// addr, _ := net.ResolveUDPAddr("udp", "192.168.10.10:41501")
// laddr, _ := net.ResolveUDPAddr("udp", "192.168.10.1:58814")
// conn, err := net.DialUDP("udp", laddr, addr)
conn, err := net.DialUDP("udp", nil, &net.UDPAddr{
IP: BROADCAST_IPv4,
Port: 41504,
})
if err != nil {
fmt.Printf("DialUDP(): %s\n", err.Error())
return
}
for scanner.Scan() {
s := scanner.Text()
x := strings.Split(s, ",")
if len(x) < 2 {
continue
}
i, err := strconv.ParseInt(x[0], 10, 32)
if err != nil {
fmt.Printf("error parsing '%s': %s.\n", x[0], err.Error())
continue
}
buf := make([]byte, hex.DecodedLen(len(x[1])))
n, err := hex.Decode(buf, []byte(x[1]))
if err != nil {
fmt.Printf("error parsing '%s': %s.\n", x[1], err.Error())
continue
}
fmt.Printf("sleeping %dms, sending %s\n", i, x[1])
time.Sleep(time.Duration(i) * time.Millisecond)
conn.Write(buf[:n])
}
}

Wyświetl plik

@ -0,0 +1,184 @@
pre {
color: #9b9b9b;
}
.app-body,
.panel-default,
.scrollable-content,
.form-group {
color: #9b9b9b;
background-color: #121212;
}
.help-page {
background-color: #121212;
}
a,
.btn,
.navbar-app .btn {
color: #1e88e5;
}
a:hover,
a:focus,
.btn:hover,
.btn:focus,
.navbar-app .btn:hover,
.navbar-app .btn:focus {
color: #42a5f5;
}
.btn-primary {
color: #121212;
background-color: #1e88e5;
border-color: #1e88e5;
}
.btn-primary:hover {
color: #121212;
background-color: #42a5f5;
border-color: #42a5f5;
}
.btn-default {
color: #e0e0e0;
background-color: #343434;
}
.btn-default:hover {
background-color: #383838;
}
a.list-group-item,
.list-group-item {
color: #e0e0e0;
border-color: #373737;
background-color: #242424;
}
a.list-group-item:hover,
.list-group-item:hover {
text-decoration: none;
color: #e0e0e0;
background-color: #373737;
}
.list-group-item.active,
.list-group-item.active:focus,
.list-group-item.active:hover {
color: #121212;
background-color: #1e88e5;
border-color: #1e88e5;
}
.navbar-app {
background-color: #2d2d2d;
border-color: #373737;
}
.panel {
border-color: #373737;
}
.panel-default>.panel-heading {
color: #e0e0e0;
background-color: #2d2d2d;
border-color: #373737;
}
.panel-default>.panel-footer {
color: #e0e0e0;
background-color: #2d2d2d;
border-color: #373737;
}
.row-header {
background-color: #212121;
}
.separator {
border-bottom-color: #2d2d2d;
}
.sidebar-header,
.app-name {
color: #e0e0e0;
background-color: #2d2d2d;
border-color: #373737;
}
.switch {
background-color: #2d2d2d;
border-color: #9b9b9b;
}
.switch .switch-handle {
background-color: #9b9b9b;
border-color: #9b9b9b;
}
.switch.active {
background-color: #1e88e5;
border-color: #1e88e5;
}
.text-primary {
color: #1e88e5;
}
.label-success {
color: #121212;
background-color: #4caf50;
}
.label-warning {
color: #121212;
background-color: #ffeb3b;
}
.label-danger {
color: #121212;
background-color: #f44336;
}
/* Input changes */
input[type=text],
input[type=number] {
color: #e0e0e0;
background-color: #212121;
border: 2px solid #2d2d2d;
border-radius: 4px;
}
input.ng-invalid:not(.grayout) {
color: #121212;
}
select {
color: #e0e0e0;
background-color: #212121;
border: 2px solid #2d2d2d;
border-radius: 4px;
}
/* Modal changes */
.modal-content {
background-color: #343434;
}
.modal-header {
border-color: #9b9b9b;
}
.modal-title {
color: #e0e0e0;
}
.modal-body {
color: #9b9b9b;
}
.modal-footer {
border-color: #9b9b9b;
}

Wyświetl plik

@ -262,6 +262,9 @@
width: 100%;
}
.row-header {
background-color: #f7f7f7;
}
/* ***************************************************************************
everything below this comment represents tweaks to the mobile-angular-uis CSS

Wyświetl plik

@ -50,6 +50,7 @@
<link rel="stylesheet" href="css/main.css" />
<link rel="stylesheet" href="css/ahrs.css" />
<link rel="stylesheet" id="themeStylesheet" href="" />
<script src="maui/js/angular.min.js"></script>
<script src="maui/js/angular-ui-router.min.js"></script>

Wyświetl plik

@ -99,7 +99,23 @@ app.controller('MainCtrl', function ($scope, $http) {
.then(function(response) {
var settings = angular.fromJson(response.data);
$scope.DeveloperMode = settings.DeveloperMode;
// Update theme
$scope.updateTheme(settings.DarkMode);
}, function(response) {
//Second function handles error
});
$scope.updateTheme = function(darkMode) {
if(darkMode != $scope.DarkMode) {
// console.log("Updating theme, use dark mode?", darkMode);
$scope.DarkMode = darkMode;
if($scope.DarkMode) {
document.getElementById('themeStylesheet').href = 'css/dark-mode.css';
} else {
document.getElementById('themeStylesheet').href = '';
}
}
};
});

Wyświetl plik

@ -83,7 +83,11 @@
</div>
<div class="row">
<span class="col-xs-6 text-center">{{gps_lat}}, {{gps_lon}} &plusmn; {{gps_horizontal_accuracy}} m <br>
{{gps_alt}} &plusmn; {{gps_vertical_accuracy}} ft @ {{gps_vert_speed}} ft/min</span>
<b>Altitude MSL:</b> <br>
{{gps_alt}} &plusmn; {{gps_vertical_accuracy}} ft @ {{gps_vert_speed}} ft/min <br>
<b>Height WGS-84 ellipsoid:</b> <br>
{{ gps_height_above_ellipsoid }} ft
</span>
<span class="col-xs-6 text-center">{{gps_track}}&deg; @ {{gps_speed}} KTS</span>
</div>
</div>

Wyświetl plik

@ -165,6 +165,7 @@ function GPSCtrl($rootScope, $scope, $state, $http, $interval) {
$scope.gps_lat = situation.GPSLatitude.toFixed(5); // result is string
$scope.gps_lon = situation.GPSLongitude.toFixed(5); // result is string
$scope.gps_alt = situation.GPSAltitudeMSL.toFixed(1);
$scope.gps_height_above_ellipsoid = situation.GPSHeightAboveEllipsoid.toFixed(1);
$scope.gps_track = situation.GPSTrueCourse.toFixed(1);
$scope.gps_speed = situation.GPSGroundSpeed.toFixed(1);
$scope.gps_vert_speed = situation.GPSVerticalSpeed.toFixed(1);
@ -172,6 +173,7 @@ function GPSCtrl($rootScope, $scope, $state, $http, $interval) {
$scope.gps_lat = "--";
$scope.gps_lon = "--";
$scope.gps_alt = "--";
$scope.gps_height_above_ellipsoid = "--";
$scope.gps_track = "--";
$scope.gps_speed = "--";
$scope.gps_vert_speed = "--";

Wyświetl plik

@ -8,7 +8,7 @@ function SettingsCtrl($rootScope, $scope, $state, $location, $window, $http) {
$scope.$parent.helppage = 'plates/settings-help.html';
var toggles = ['UAT_Enabled', 'ES_Enabled', 'Ping_Enabled', 'GPS_Enabled', 'IMU_Sensor_Enabled',
'BMP_Sensor_Enabled', 'DisplayTrafficSource', 'DEBUG', 'ReplayLog', 'AHRSLog'];
'BMP_Sensor_Enabled', 'DisplayTrafficSource', 'DEBUG', 'ReplayLog', 'AHRSLog', 'DarkMode'];
var settings = {};
for (var i = 0; i < toggles.length; i++) {
settings[toggles[i]] = undefined;
@ -24,6 +24,9 @@ function SettingsCtrl($rootScope, $scope, $state, $location, $window, $http) {
$scope.Baud = settings.SerialOutputs['/dev/serialout0'].Baud;
$scope.visible_serialout = true;
}
$scope.DarkMode = settings.DarkMode;
$scope.UAT_Enabled = settings.UAT_Enabled;
$scope.ES_Enabled = settings.ES_Enabled;
$scope.Ping_Enabled = settings.Ping_Enabled;
@ -47,8 +50,12 @@ function SettingsCtrl($rootScope, $scope, $state, $location, $window, $http) {
$scope.WiFiPassphrase = settings.WiFiPassphrase;
$scope.WiFiSecurityEnabled = settings.WiFiSecurityEnabled;
$scope.WiFiChannel = settings.WiFiChannel;
$scope.WiFiSmartEnabled = settings.WiFiSmartEnabled;
$scope.Channels = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
// Update theme
$scope.$parent.updateTheme($scope.DarkMode);
}
function getSettings() {
@ -287,7 +294,8 @@ function SettingsCtrl($rootScope, $scope, $state, $location, $window, $http) {
"WiFiSSID" : $scope.WiFiSSID,
"WiFiSecurityEnabled" : $scope.WiFiSecurityEnabled,
"WiFiPassphrase" : $scope.WiFiPassphrase,
"WiFiChannel" : parseInt($scope.WiFiChannel)
"WiFiChannel" : parseInt($scope.WiFiChannel),
"WiFiSmartEnabled": $scope.WiFiSmartEnabled
};
// console.log(angular.toJson(newsettings));

Wyświetl plik

@ -56,6 +56,21 @@
</div>
</div>
</div>
<!-- App Theme -->
<div class="panel-group col-sm-12">
<div class="panel panel-default">
<div class="panel-heading">Theme</div>
<div class="panel-body">
<!-- Dark Mode -->
<div class="form-group">
<label class="control-label col-xs-7">Dark Mode</label>
<div class="col-xs-5">
<ui-switch ng-model='DarkMode' settings-change></ui-switch>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- End Left Col -->
<!-- Begin Right Col -->
@ -134,6 +149,12 @@
<select id="WiFiChannel" class="input-small col-sm-2 form-control-sm"
ng-model="WiFiChannel" ng-options="x for x in Channels"></select>
</div>
<div class="form-group reset-flow">
<label class="control-label col-xs-7">Smart WiFi</label>
<div class="col-xs-5">
<ui-switch ng-model="WiFiSmartEnabled" settings-change></ui-switch>
</div>
</div>
<div class="form-group reset-flow">
<button class="btn btn-primary btn-block" ng-click="updateWiFi()">Submit WiFi Changes</button>
</div>
@ -383,6 +404,7 @@
<p>WiFi Security: <b>{{WiFiSecurityEnabled}}</b></p>
<p>WiFi Passphrase: <b>{{WiFiPassphrase}}</b></p>
<p>WiFi Channel: <b>{{WiFiChannel}}</b></p>
<p>Smart mode: <b>{{WiFiSmartEnabled}}</b></p>
<p>Your Stratux's WiFi services are now restarting to apply the new settings. This could take up to 30 seconds.<br/>
You might have to reconnect to your new WiFi SSID. </p>
</div>

Wyświetl plik

@ -1,6 +1,6 @@
<div class="col-sm-12">
<div class="text-center">
<a ng-click="VersionClick()" class="btn btn-hidden"<strong>Version: <span>{{Version}} ({{Build}})</span></strong></a>
<a ng-click="VersionClick()" class="btn btn-hidden"><strong>Version: <span>{{Version}} ({{Build}})</span></strong></a>
</div>
<div class="panel panel-default">
<div class="panel-heading">
@ -56,10 +56,10 @@
</div>
<div class="row" ng-class="{'section_invisible': !visible_uat}">
<div class="col-sm-12">
<span align="center" style="background-color: #f7f7f7" class="col-xs-3">Towers</span>
<span align="center" style="background-color: #f7f7f7" class="col-xs-3">METARS</span>
<span align="center" style="background-color: #f7f7f7" class="col-xs-3">TAFS</span>
<span align="center" style="background-color: #f7f7f7" class="col-xs-3">NEXRAD</span>
<span align="center" class="col-xs-3 row-header">Towers</span>
<span align="center" class="col-xs-3 row-header">METARS</span>
<span align="center" class="col-xs-3 row-header">TAFS</span>
<span align="center" class="col-xs-3 row-header">NEXRAD</span>
</div>
</div>
<div class="row" ng-class="{'section_invisible': !visible_uat}">
@ -72,10 +72,10 @@
</div>
<div class="row" ng-class="{'section_invisible': !visible_uat}">
<div class="col-sm-12">
<span align="center" style="background-color: #f7f7f7" class="col-xs-3">PIREP</span>
<span align="center" style="background-color: #f7f7f7" class="col-xs-3">SIGMET</span>
<span align="center" style="background-color: #f7f7f7" class="col-xs-3">NOTAMS</span>
<span align="center" style="background-color: #f7f7f7" class="col-xs-3">Other</span>
<span align="center" class="col-xs-3 row-header">PIREP</span>
<span align="center" class="col-xs-3 row-header">SIGMET</span>
<span align="center" class="col-xs-3 row-header">NOTAMS</span>
<span align="center" class="col-xs-3 row-header">Other</span>
</div>
</div>
<div class="row" ng-class="{'section_invisible': !visible_uat}">