kopia lustrzana https://github.com/cyoung/stratux
269 wiersze
7.2 KiB
Go
269 wiersze
7.2 KiB
Go
/*
|
|
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 {
|
|
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()
|
|
}
|