Improved support for Ublox NMEA parsing, extended support for T-Beam based OGN Tracker, including GPS config and configuration of the tracker via Stratux web interface (experimental)

pull/827/merge^2
Adrian Batzill 2020-12-05 18:35:52 +01:00
rodzic 000afd0f82
commit 719d87feb4
8 zmienionych plików z 297 dodań i 67 usunięć

Wyświetl plik

@ -41,9 +41,9 @@ SUBSYSTEMS=="usb", ATTRS{interface}=="Stratux Serialout NMEA", SYMLINK+="serialo
# SoftRF.
# SoftRF Standalone (NodeMCU or DoIt ESP32 devkit with CP2102 chip)
SUBSYSTEM=="tty", SUBSYSTEMS=="usb", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", ATTRS{product}=="DIY SoftRF", SYMLINK+="flarm"
SUBSYSTEM=="tty", SUBSYSTEMS=="usb", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", ATTRS{product}=="DIY SoftRF", SYMLINK+="serialin"
# TTGO T-Beam (ESP32 with OTP CP2104 chip)
SUBSYSTEM=="tty", SUBSYSTEMS=="usb", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", ATTRS{product}=="CP2104 USB to UART Bridge Controller", SYMLINK+="flarm"
SUBSYSTEM=="tty", SUBSYSTEMS=="usb", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", ATTRS{product}=="CP2104 USB to UART Bridge Controller", SYMLINK+="serialin"
# TTGO dongle edition (0483:5740 STMicroelectronics Virtual COM Port)
SUBSYSTEM=="tty", SUBSYSTEMS=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="5740", SYMLINK+="softrf_dongle"

Wyświetl plik

@ -97,7 +97,8 @@ const (
GPS_TYPE_UBX6 = 0x06
GPS_TYPE_PROLIFIC = 0x02
GPS_TYPE_UART = 0x01
GPS_TYPE_FLARM = 0x0A
GPS_TYPE_SERIAL = 0x0A
GPS_TYPE_OGNTRACKER = 0x03
GPS_TYPE_SOFTRF_DONGLE = 0x0B
GPS_TYPE_NETWORK = 0x0C
GPS_PROTOCOL_NMEA = 0x10
@ -1185,7 +1186,11 @@ type settings struct {
EstimateBearinglessDist bool
RadarLimits int
RadarRange int
OGNAddr string
OGNAddrType int
OGNAcftType int
OGNPilot string
}
type status struct {

Wyświetl plik

@ -140,6 +140,8 @@ var readyToInitGPS bool //TODO: replace with channel control to terminate gorout
var Satellites map[string]SatelliteInfo
var ognTrackerConfigured = false;
/*
u-blox5_Referenzmanual.pdf
Platform settings
@ -201,6 +203,7 @@ func makeNMEACmd(cmd string) []byte {
return []byte(fmt.Sprintf("$%s*%02x\x0d\x0a", cmd, chk_sum))
}
func initGPSSerial() bool {
var device string
if (globalStatus.GPS_detected_type & 0x0f) == GPS_TYPE_NETWORK {
@ -209,6 +212,7 @@ func initGPSSerial() bool {
// Possible baud rates for this device. We will try to auto detect the correct one
baudrates := []int{int(9600)}
isSirfIV := bool(false)
ognTrackerConfigured = false;
globalStatus.GPS_detected_type = 0 // reset detected type on each initialization
if _, err := os.Stat("/dev/ublox9"); err == nil { // u-blox 8 (RY83xAI over USB).
@ -230,9 +234,9 @@ func initGPSSerial() bool {
baudrates[0] = 4800
device = "/dev/prolific0"
globalStatus.GPS_detected_type = GPS_TYPE_PROLIFIC
} else if _, err := os.Stat("/dev/flarm"); err == nil {
device = "/dev/flarm"
globalStatus.GPS_detected_type = GPS_TYPE_FLARM
} else if _, err := os.Stat("/dev/serialin"); err == nil {
device = "/dev/serialin"
globalStatus.GPS_detected_type = GPS_TYPE_SERIAL
// OGN Tracker uses 115200, SoftRF 38400
baudrates = []int{115200, 38400, 9600}
} else if _, err := os.Stat("/dev/softrf_dongle"); err == nil {
@ -304,11 +308,9 @@ func initGPSSerial() bool {
// sampling rates.
// load default configuration | clearMask | | saveMask | | loadMask | deviceMask
p.Write(makeUBXCFG(0x06, 0x09, 13, []byte{0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x17}))
p.Write(makeUBXCFG(0x06, 0x09, 13, []byte{0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x03}))
time.Sleep(100* time.Millisecond) // pause and wait for the GPS to finish configuring itself before closing / reopening the port
// UBX-CFG-NMEA (change NMEA protocol version to 4.1)
p.Write(makeUBXCFG(0x06, 0x17, 20, []byte{0x00, 0x41, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}))
if globalStatus.GPS_detected_type == GPS_TYPE_UBX9 {
if globalSettings.DEBUG {
@ -323,27 +325,7 @@ func initGPSSerial() bool {
}
// There are Ublox8 chips that only support GPS+GLO, so we first enable these to hopefully get an ACK
// Then we do the same with GAL and get an NACK for those chips, but ACK for the ones that support GAL as well
cfgGnss := []byte{0x00, 0x00, 0x20, 0x05}
gps := []byte{0x00, 0x08, 0x10, 0x00, 0x01, 0x00, 0x01, 0x01} // enable GPS with 8-16 tracking channels
sbas := []byte{0x01, 0x02, 0x03, 0x00, 0x00, 0x00, 0x01, 0x01} // disable SBAS
beidou := []byte{0x03, 0x04, 0x10, 0x00, 0x00, 0x00, 0x01, 0x01} // disable BEIDOU
qzss := []byte{0x05, 0x01, 0x03, 0x00, 0x01, 0x00, 0x01, 0x01} // enable QZSS 0-3 tracking channels. Ublox recommends enabling when GPS is enabled
glonass := []byte{0x06, 0x08, 0x0E, 0x00, 0x01, 0x00, 0x01, 0x01} // enable GLONASS with 8-14 tracking channels
galileo := []byte{0x02, 0x04, 0x0A, 0x00, 0x01, 0x00, 0x01, 0x01} // enable Galileo with 4-10 tracking channels, ublox 8 does only support up to 10
cfgGnss = append(cfgGnss, gps...)
cfgGnss = append(cfgGnss, sbas...)
cfgGnss = append(cfgGnss, beidou...)
cfgGnss = append(cfgGnss, qzss...)
cfgGnss = append(cfgGnss, glonass...)
p.Write(makeUBXCFG(0x06, 0x3E, uint16(len(cfgGnss)), cfgGnss)) // Succeeds on all chips supporting GPS+GLO
cfgGnss[3] = 0x06
cfgGnss = append(cfgGnss, galileo...)
p.Write(makeUBXCFG(0x06, 0x3E, uint16(len(cfgGnss)), cfgGnss)) // Succeeds only on chips that support GPS+GLO+GAL
p.Write(makeUBXCFG(0x06, 0x16, 8, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})) // SBAS off
p.Write(makeUBXCFG(0x06, 0x08, 6, []byte{0x64, 0x00, 0x01, 0x00, 0x01, 0x00})) // 100ms & 1 cycle -> 10Hz (UBX-CFG-RATE payload bytes: little endian!)
writeUblox8ConfigCommands(10, p)
} else if (globalStatus.GPS_detected_type == GPS_TYPE_UBX7) || (globalStatus.GPS_detected_type == GPS_TYPE_UBX6) {
if globalSettings.DEBUG {
log.Printf("ublox 6 or 7 detected\n")
@ -367,13 +349,7 @@ func initGPSSerial() bool {
p.Write(makeUBXCFG(0x06, 0x08, 6, []byte{0x64, 0x00, 0x01, 0x00, 0x01, 0x00})) // 100ms & 1 cycle -> 10Hz (UBX-CFG-RATE payload bytes: little endian!)
}
// UBX-CFG-PMS
p.Write(makeUBXCFG(0x06, 0x86, 8, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})) // Full Power Mode
// p.Write(makeUBXCFG(0x06, 0x86, 8, []byte{0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})) // Balanced Power Mode
// UBX-CFG-NAV5 |mask1...| dyn
p.Write(makeUBXCFG(0x06, 0x24, 36, []byte{0x01, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})) // Dynamic platform model: airborne with <1g acceleration
writeUbloxGenericCommands(p)
// UBX-CFG-MSG (NMEA Standard Messages) msg msg Ports 1-6 (every 10th message over UART1, every message over USB)
// Class ID DDC UART1 UART2 USB I2C Res
p.Write(makeUBXCFG(0x06, 0x01, 8, []byte{0xF0, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x00})) // GGA - Global positioning system fix data
@ -397,6 +373,7 @@ func initGPSSerial() bool {
p.Write(makeUBXCFG(0x06, 0x01, 8, []byte{0xF1, 0x03, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00})) // Ublox - Satellite Status
p.Write(makeUBXCFG(0x06, 0x01, 8, []byte{0xF1, 0x04, 0x00, 0x0A, 0x00, 0x0A, 0x00, 0x00})) // Ublox - Time of Day and Clock Information
// Reconfigure serial port.
cfg := make([]byte, 20)
cfg[0] = 0x01 // portID.
@ -404,6 +381,7 @@ func initGPSSerial() bool {
cfg[2] = 0x00 // res1.
cfg[3] = 0x00 // res1.
// [ 7 ] [ 6 ] [ 5 ] [ 4 ]
// 0000 0000 0000 0000 0000 10x0 1100 0000
// UART mode. 0 stop bits, no parity, 8 data bits. Little endian order.
@ -435,6 +413,8 @@ func initGPSSerial() bool {
// UBX-CFG-PRT (Port Configuration for UART)
p.Write(makeUBXCFG(0x06, 0x00, 20, cfg))
// time.Sleep(100* time.Millisecond) // pause and wait for the GPS to finish configuring itself before closing / reopening the port
baudrates[0] = 38400
@ -499,6 +479,87 @@ func detectOpenSerialPort(device string, baudrates []int) (*(serial.Port), error
}
}
// Navrate only supports "5" or "10" for now
func writeUblox8ConfigCommands(navrate uint16, p *serial.Port) {
cfgGnss := []byte{0x00, 0x00, 0x20, 0x05}
gps := []byte{0x00, 0x08, 0x10, 0x00, 0x01, 0x00, 0x01, 0x01} // enable GPS with 8-16 tracking channels
sbas := []byte{0x01, 0x02, 0x03, 0x00, 0x00, 0x00, 0x01, 0x01} // disable SBAS
beidou := []byte{0x03, 0x04, 0x10, 0x00, 0x00, 0x00, 0x01, 0x01} // disable BEIDOU
qzss := []byte{0x05, 0x01, 0x03, 0x00, 0x01, 0x00, 0x01, 0x01} // enable QZSS 0-3 tracking channels. Ublox recommends enabling when GPS is enabled
glonass := []byte{0x06, 0x08, 0x0E, 0x00, 0x01, 0x00, 0x01, 0x01} // enable GLONASS with 8-14 tracking channels
galileo := []byte{0x02, 0x04, 0x0A, 0x00, 0x01, 0x00, 0x01, 0x01} // enable Galileo with 4-10 tracking channels, ublox 8 does only support up to 10
cfgGnss = append(cfgGnss, gps...)
cfgGnss = append(cfgGnss, sbas...)
cfgGnss = append(cfgGnss, beidou...)
cfgGnss = append(cfgGnss, qzss...)
cfgGnss = append(cfgGnss, glonass...)
p.Write(makeUBXCFG(0x06, 0x3E, uint16(len(cfgGnss)), cfgGnss)) // Succeeds on all chips supporting GPS+GLO
cfgGnss[3] = 0x06
cfgGnss = append(cfgGnss, galileo...)
p.Write(makeUBXCFG(0x06, 0x3E, uint16(len(cfgGnss)), cfgGnss)) // Succeeds only on chips that support GPS+GLO+GAL
p.Write(makeUBXCFG(0x06, 0x16, 8, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})) // SBAS off
if navrate == 10 {
p.Write(makeUBXCFG(0x06, 0x08, 6, []byte{0x64, 0x00, 0x01, 0x00, 0x00, 0x00})) // 100ms & 1 cycle -> 10Hz (UBX-CFG-RATE payload bytes: little endian!)
} else if navrate == 5 {
p.Write(makeUBXCFG(0x06, 0x08, 6, []byte{0xC8, 0x00, 0x01, 0x00, 0x00, 0x00})) // 200ms & 1 cycle -> 10Hz (UBX-CFG-RATE payload bytes: little endian!)
}
}
func writeUbloxGenericCommands(p *serial.Port) {
// UBX-CFG-NMEA (change NMEA protocol version to 4.0 extended)
p.Write(makeUBXCFG(0x06, 0x17, 20, []byte{0x00, 0x40, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}))
// UBX-CFG-PMS
p.Write(makeUBXCFG(0x06, 0x86, 8, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})) // Full Power Mode
// p.Write(makeUBXCFG(0x06, 0x86, 8, []byte{0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})) // Balanced Power Mode
// UBX-CFG-NAV5 |mask1...| dyn
p.Write(makeUBXCFG(0x06, 0x24, 36, []byte{0x01, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})) // Dynamic platform model: airborne with <1g acceleration
}
func ensureOgnTrackerConfigured() {
if ognTrackerConfigured || serialPort == nil {
return
}
ognTrackerConfigured = true
serialPort.Write([]byte("$POGNS\r\n")) // query current configuration
writeUblox8ConfigCommands(10, serialPort)
writeUbloxGenericCommands(serialPort)
// UBX-CFG-MSG (NMEA Standard Messages) msg msg Ports 1-6 (every 10th message over UART1, every message over USB)
// Class ID DDC UART1 UART2 USB I2C Res
serialPort.Write(makeUBXCFG(0x06, 0x01, 8, []byte{0xF0, 0x00, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00})) // GGA - Global positioning system fix data
serialPort.Write(makeUBXCFG(0x06, 0x01, 8, []byte{0xF0, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00})) // GLL - Latitude and longitude, with time of position fix and status
serialPort.Write(makeUBXCFG(0x06, 0x01, 8, []byte{0xF0, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00})) // GSA - GNSS DOP and Active Satellites
serialPort.Write(makeUBXCFG(0x06, 0x01, 8, []byte{0xF0, 0x03, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00})) // GSV - GNSS Satellites in View
serialPort.Write(makeUBXCFG(0x06, 0x01, 8, []byte{0xF0, 0x04, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00})) // RMC - Recommended Minimum data
serialPort.Write(makeUBXCFG(0x06, 0x01, 8, []byte{0xF0, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00})) // VGT - Course over ground and Ground speed
serialPort.Write(makeUBXCFG(0x06, 0x01, 8, []byte{0xF0, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})) // GRS - GNSS Range Residuals
serialPort.Write(makeUBXCFG(0x06, 0x01, 8, []byte{0xF0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})) // GST - GNSS Pseudo Range Error Statistics
serialPort.Write(makeUBXCFG(0x06, 0x01, 8, []byte{0xF0, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})) // ZDA - Time and Date
serialPort.Write(makeUBXCFG(0x06, 0x01, 8, []byte{0xF0, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})) // GBS - GNSS Satellite Fault Detection
serialPort.Write(makeUBXCFG(0x06, 0x01, 8, []byte{0xF0, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})) // DTM - Datum Reference
serialPort.Write(makeUBXCFG(0x06, 0x01, 8, []byte{0xF0, 0x0D, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00})) // GNS - GNSS fix data
// p.Write(makeUBXCFG(0x06, 0x01, 8, []byte{0xF0, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})) // ???
serialPort.Write(makeUBXCFG(0x06, 0x01, 8, []byte{0xF0, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})) // VLW - Dual ground/water distance
// UBX-CFG-MSG (NMEA PUBX Messages) msg msg Ports 1-6
// Class ID DDC UART1 UART2 USB I2C Res
serialPort.Write(makeUBXCFG(0x06, 0x01, 8, []byte{0xF1, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00})) // Ublox - Lat/Long Position Data
serialPort.Write(makeUBXCFG(0x06, 0x01, 8, []byte{0xF1, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00})) // Ublox - Satellite Status
serialPort.Write(makeUBXCFG(0x06, 0x01, 8, []byte{0xF1, 0x04, 0x00, 0x0A, 0x00, 0x0A, 0x00, 0x00})) // Ublox - Time of Day and Clock Information
serialPort.Flush()
globalStatus.GPS_detected_type = GPS_TYPE_OGNTRACKER
}
// func validateNMEAChecksum determines if a string is a properly formatted NMEA sentence with a valid checksum.
//
// If the input string is valid, output is the input stripped of the "$" token and checksum, along with a boolean 'true'
@ -1737,25 +1798,25 @@ func processNMEALine(l string) (sentenceUsed bool) {
if sv <= 32 {
svType = SAT_TYPE_GPS
svStr = fmt.Sprintf("G%d", sv)
svStr = fmt.Sprintf("G%d", sv) // GPS 1-32
} else if sv <= 64 {
svType = SAT_TYPE_BEIDOU
svStr = fmt.Sprintf("B%d", sv-32)
svType = SAT_TYPE_SBAS
svStr = fmt.Sprintf("S%d", sv-32) // SBAS 33-64
} else if sv <= 96 {
svType = SAT_TYPE_GLONASS
svStr = fmt.Sprintf("R%d", sv-64)
} else if (sv >= 120) && (sv <= 158) {
svStr = fmt.Sprintf("R%d", sv-64) // GLONASS 65-96
} else if sv <= 158 {
svType = SAT_TYPE_SBAS
svStr = fmt.Sprintf("S%d", sv)
} else if sv <= 163 {
svType = SAT_TYPE_BEIDOU
svStr = fmt.Sprintf("B%d", sv-126)
} else if sv <= 193 {
svStr = fmt.Sprintf("S%d", sv-151) // SBAS 152-158
} else if sv <= 202 {
svType = SAT_TYPE_QZSS
svStr = fmt.Sprintf("Q%d", sv-192)
} else if sv >= 211 {
svStr = fmt.Sprintf("Q%d", sv-192) // QZSS 193-202
} else if sv <= 336 {
svType = SAT_TYPE_GALILEO
svStr = fmt.Sprintf("E%d", sv-210)
svStr = fmt.Sprintf("E%d", sv-300) // GALILEO 301-336
} else if sv <= 437 {
svType = SAT_TYPE_BEIDOU
svStr = fmt.Sprintf("B%d", sv-400) // BEIDOU 401-437
} else {
svType = SAT_TYPE_UNKNOWN
svStr = fmt.Sprintf("U%d", sv)
@ -1874,25 +1935,25 @@ func processNMEALine(l string) (sentenceUsed bool) {
if sv <= 32 {
svType = SAT_TYPE_GPS
svStr = fmt.Sprintf("G%d", sv)
svStr = fmt.Sprintf("G%d", sv) // GPS 1-32
} else if sv <= 64 {
svType = SAT_TYPE_BEIDOU
svStr = fmt.Sprintf("B%d", sv-32)
svType = SAT_TYPE_SBAS
svStr = fmt.Sprintf("S%d", sv-32) // SBAS 33-64
} else if sv <= 96 {
svType = SAT_TYPE_GLONASS
svStr = fmt.Sprintf("R%d", sv-64)
} else if (sv >= 120) && (sv <= 158) {
svStr = fmt.Sprintf("R%d", sv-64) // GLONASS 65-96
} else if sv <= 158 {
svType = SAT_TYPE_SBAS
svStr = fmt.Sprintf("S%d", sv)
} else if sv <= 163 {
svType = SAT_TYPE_BEIDOU
svStr = fmt.Sprintf("B%d", sv-126)
} else if sv <= 193 {
svStr = fmt.Sprintf("S%d", sv-151) // SBAS 152-158
} else if sv <= 202 {
svType = SAT_TYPE_QZSS
svStr = fmt.Sprintf("Q%d", sv-192)
} else if sv >= 211 {
svStr = fmt.Sprintf("Q%d", sv-192) // QZSS 193-202
} else if sv <= 336 {
svType = SAT_TYPE_GALILEO
svStr = fmt.Sprintf("E%d", sv-210)
svStr = fmt.Sprintf("E%d", sv-300) // GALILEO 301-336
} else if sv <= 437 {
svType = SAT_TYPE_BEIDOU
svStr = fmt.Sprintf("B%d", sv-400) // BEIDOU 401-437
} else {
svType = SAT_TYPE_UNKNOWN
svStr = fmt.Sprintf("U%d", sv)
@ -2000,10 +2061,40 @@ func processNMEALine(l string) (sentenceUsed bool) {
return true
}
// Only sent by OGN tracker. We use this to detect that OGN tracker is connected and configure it as needed
if x[0] == "POGNR" {
ensureOgnTrackerConfigured()
return true
}
if x[0] == "POGNS" {
// OGN tracker sent us its configuration
log.Printf("Received OGN Tracker configuration: " + strings.Join(x, ","))
for i := 1; i < len(x); i++ {
kv := strings.SplitN(x[i], "=", 2);
if len(kv) < 2 {
continue
}
if kv[0] == "Address" {
addr, _ := strconv.ParseUint(kv[1], 0, 32)
globalSettings.OGNAddr = strings.ToUpper(fmt.Sprintf("%x", addr))
} else if kv[0] == "AddrType" {
addrtype, _ := strconv.ParseInt(kv[1], 0, 8)
globalSettings.OGNAddrType = int(addrtype)
} else if kv[0] == "AcftType" {
acfttype, _ := strconv.ParseInt(kv[1], 0, 8)
globalSettings.OGNAcftType = int(acfttype)
} else if kv[0] == "Pilot" {
globalSettings.OGNPilot = kv[1]
}
}
}
// Only evaluate PGRMZ for SoftRF/Flarm, where we know that it is standard barometric pressure.
// might want to add more types if applicable.
// $PGRMZ,1089,f,3*2B
if x[0] == "PGRMZ" && ((globalStatus.GPS_detected_type & 0x0f) == GPS_TYPE_FLARM || (globalStatus.GPS_detected_type & 0x0f) == GPS_TYPE_SOFTRF_DONGLE) {
if x[0] == "PGRMZ" && ((globalStatus.GPS_detected_type & 0x0f) == GPS_TYPE_SERIAL || (globalStatus.GPS_detected_type & 0x0f) == GPS_TYPE_SOFTRF_DONGLE) {
if len(x) < 3 {
return false
}
@ -2037,6 +2128,19 @@ func processNMEALine(l string) (sentenceUsed bool) {
return false
}
func configureOgnTrackerFromSettings() {
if serialPort == nil {
return
}
cfg := fmt.Sprintf("$POGNS,Address=0x%s,AddrType=%d,AcftType=%d,Pilot=%s\r\n", globalSettings.OGNAddr, globalSettings.OGNAddrType, globalSettings.OGNAcftType, globalSettings.OGNPilot)
log.Printf("Configuring OGN Tracker: " + cfg)
serialPort.Write([]byte(cfg))
serialPort.Write([]byte("$POGNS\r\n")) // re-read settings from tracker
serialPort.Flush()
}
// Maps 1000ft bands to gnssBaroAltDiffs of known traffic.
// This will then be used to estimate our own baro altitude from GNSS if we don't have a pressure sensor connected...

Wyświetl plik

@ -293,6 +293,7 @@ func handleSettingsSetRequest(w http.ResponseWriter, r *http.Request) {
} else if err != nil {
log.Printf("handleSettingsSetRequest:error: %s\n", err.Error())
} else {
reconfigureOgnTracker := false
for key, val := range msg {
// log.Printf("handleSettingsSetRequest:json: testing for key:%s of type %s\n", key, reflect.TypeOf(val))
switch key {
@ -431,12 +432,29 @@ func handleSettingsSetRequest(w http.ResponseWriter, r *http.Request) {
globalSettings.SkyDemonAndroidHack = val.(bool)
case "EstimateBearinglessDist":
globalSettings.EstimateBearinglessDist = val.(bool)
case "OGNAddrType":
globalSettings.OGNAddrType = int(val.(float64))
reconfigureOgnTracker = true
case "OGNAddr":
globalSettings.OGNAddr = val.(string)
reconfigureOgnTracker = true
case "OGNAcftType":
globalSettings.OGNAcftType = int(val.(float64))
reconfigureOgnTracker = true
case "OGNPilot":
globalSettings.OGNPilot = val.(string)
reconfigureOgnTracker = true
default:
log.Printf("handleSettingsSetRequest:json: unrecognized key:%s\n", key)
}
}
saveSettings()
applyNetworkSettings(false)
if reconfigureOgnTracker {
configureOgnTrackerFromSettings()
}
}
}

Wyświetl plik

@ -185,6 +185,18 @@ func cleanupOldEntries() {
// If the ti is very close and at same altitude, it is considered to be us
// If it has no position information, we will not take it as ownship, but ignore its data (no mode-s detection for everything that is configured as ownship)
func isOwnshipTrafficInfo(ti TrafficInfo) (isOwnshipInfo bool, shouldIgnore bool) {
// First, check if this is our own OGN tracker
if (globalStatus.GPS_detected_type & 0x0f) == GPS_TYPE_OGNTRACKER {
ognTrackerCodeInt, _ := strconv.ParseUint(globalSettings.OGNAddr, 16, 32)
if uint32(ognTrackerCodeInt) == ti.Icao_addr {
isOwnshipInfo = true
shouldIgnore = true
return
}
}
codes := strings.Split(globalSettings.OwnshipModeS, ",")
shouldIgnore = false

Wyświetl plik

@ -16,6 +16,15 @@ function SettingsCtrl($rootScope, $scope, $state, $location, $window, $http) {
}
$scope.update_files = '';
$http.get(URL_STATUS_GET).then(function(response) {
var status = angular.fromJson(response.data);
var gpsHardwareCode = (status.GPS_detected_type & 0x0f);
if (gpsHardwareCode == 3)
$scope.hasOgnTracker = true;
else
$scope.hasOgnTracker = false;
});
function loadSettings(data) {
settings = angular.fromJson(data);
// consider using angular.extend()
@ -65,6 +74,11 @@ function SettingsCtrl($rootScope, $scope, $state, $location, $window, $http) {
$scope.Channels = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
$scope.OGNAddrType = settings.OGNAddrType.toString();
$scope.OGNAddr = settings.OGNAddr;
$scope.OGNAcftType = settings.OGNAcftType.toString();
$scope.OGNPilot = settings.OGNPilot;
// Update theme
$scope.$parent.updateTheme($scope.DarkMode);
}
@ -324,6 +338,22 @@ function SettingsCtrl($rootScope, $scope, $state, $location, $window, $http) {
$scope.Ui.turnOn("modalErrorWiFi");
}
};
$scope.updateOgnTrackerConfig = function(action) {
var newsettings = {
"OGNAddrType": parseInt($scope.OGNAddrType),
"OGNAddr": $scope.OGNAddr,
"OGNAcftType": parseInt($scope.OGNAcftType),
"OGNPilot": $scope.OGNPilot
};
setSettings(angular.toJson(newsettings));
// reload settings after a short time, to check if OGN tracker actually accepted the settings
setTimeout(function() {
getSettings();
}, 1000);
}
}
function isValidSSID(str) { return /^[a-zA-Z0-9()_-]{1,32}$/g.test(str); }

Wyświetl plik

@ -89,6 +89,9 @@ function StatusCtrl($rootScope, $scope, $state, $http, $interval) {
case 2:
tempGpsHardwareString = "Prolific USB-serial bridge";
break;
case 3:
tempGpsHardwareString = "OGN Tracker";
break;
case 6:
tempGpsHardwareString = "USB u-blox 6 GPS receiver";
break;
@ -102,7 +105,7 @@ function StatusCtrl($rootScope, $scope, $state, $http, $interval) {
tempGpsHardwareString = "USB u-blox 9 GNSS receiver";
break;
case 10:
tempGpsHardwareString = "FLARM";
tempGpsHardwareString = "USB Serial IN";
break;
case 11:
tempGpsHardwareString = "SoftRF Dongle";

Wyświetl plik

@ -54,7 +54,7 @@
</div>
<div class="form-group reset-flow">
<div class="col-xs-12">
<button class="btn btn-primary btn-block"ui-turn-on="modalShutdown">Shutdown</button>
<button class="btn btn-primary btn-block" ui-turn-on="modalShutdown">Shutdown</button>
</div>
</div>
</div>
@ -75,6 +75,64 @@
</div>
</div>
</div>
<!-- OGN Tracker config -->
<div class="panel-group col-sm-12" ng-show="hasOgnTracker"> <!-- TODO -->
<div class="panel panel-default">
<div class="panel-heading">OGN Tracker</div>
<div class="panel-body">
<form name="OGNTrackerSettings" novalidate>
<!-- Address Type -->
<div class="form-group reset-flow">
<label class="control-label col-xs-5">Tracker Address Type</label>
<select class="col-xs-7 custom-select" mode-input ng-model="OGNAddrType">
<option value="0" ng-selected="OGNAddrType=='0'">Random</option>
<option value="1" ng-selected="OGNAddrType=='1'">ICAO</option>
<option value="2" ng-selected="OGNAddrType=='2'">Flarm</option>
<option value="3" ng-selected="OGNAddrType=='3'">OGN</option>
</select>
</div>
<!-- Address -->
<div class="form-group reset-flow">
<label class="control-label col-xs-5">Tracker Address (Hex)</label>
<input class="col-xs-7" type="text" hex-input ng-model="OGNAddr" />
</div>
<!-- Aircraft Type -->
<div class="form-group reset-flow">
<label class="control-label col-xs-5">Aircraft type</label>
<select class="col-xs-7 custom-select" mode-input ng-model="OGNAcftType">
<option value="1" ng-selected="OGNAcftType=='1'">Glider/Motorglider</option>
<option value="2" ng-selected="OGNAcftType=='2'">Tow plane</option>
<option value="3" ng-selected="OGNAcftType=='3'">Helicopter</option>
<option value="4" ng-selected="OGNAcftType=='4'">Parachute</option>
<option value="5" ng-selected="OGNAcftType=='5'">Drop plane</option>
<option value="6" ng-selected="OGNAcftType=='6'">Hang glider</option>
<option value="7" ng-selected="OGNAcftType=='7'">Para glider</option>
<option value="8" ng-selected="OGNAcftType=='8'">Powered Aircraft</option>
<option value="9" ng-selected="OGNAcftType=='9'">Jet Aircraft</option>
<option value="10" ng-selected="OGNAcftType=='10'">UFO</option>
<option value="11" ng-selected="OGNAcftType=='11'">Balloon</option>
<option value="12" ng-selected="OGNAcftType=='12'">Airship</option>
<option value="13" ng-selected="OGNAcftType=='13'">UAV</option>
<option value="14" ng-selected="OGNAcftType=='14'">Ground support</option>
<option value="15" ng-selected="OGNAcftType=='15'">Static object</option>
</select>
</div>
<!-- Pilot name -->
<div class="form-group reset-flow">
<label class="control-label col-xs-5">Pilot Name</label>
<input class="col-xs-7" type="text" ng-model="OGNPilot" />
</div>
<div class="form-group reset-flow">
<button class="btn btn-primary btn-block" ng-click="updateOgnTrackerConfig()">Configure OGN Tracker</button>
</div>
</form>
</div>
</div>
</div>
</div>
<!-- End Left Col -->
<!-- Begin Right Col -->