kopia lustrzana https://github.com/cyoung/stratux
commit
3843350432
2
Makefile
2
Makefile
|
@ -14,7 +14,7 @@ all:
|
|||
|
||||
xgen_gdl90:
|
||||
go get -t -d -v ./main ./test ./linux-mpu9150/mpu ./godump978 ./mpu6050 ./uatparse
|
||||
go build $(BUILDINFO) -p 4 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 main/datalog.go main/equations.go
|
||||
go build $(BUILDINFO) -p 4 main/gen_gdl90.go main/traffic.go main/ry835ai.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
|
||||
|
||||
xdump1090:
|
||||
git submodule update --init
|
||||
|
|
|
@ -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"
|
||||
|
|
@ -50,6 +50,8 @@ 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
|
||||
#ping udev
|
||||
cp -f 99-uavionix.rules mnt/etc/udev/rules.d
|
||||
|
||||
#isc-dhcp-server config
|
||||
cp -f isc-dhcp-server mnt/etc/default/isc-dhcp-server
|
||||
|
|
|
@ -436,6 +436,11 @@ func makeStratuxStatus() []byte {
|
|||
msg[13] = msg[13] | (1 << 6)
|
||||
}
|
||||
|
||||
// Ping provides ES and UAT
|
||||
if globalSettings.Ping_Enabled {
|
||||
msg[13] = msg[13] | (1 << 5) | (1 << 6)
|
||||
}
|
||||
|
||||
// Valid/Enabled: GPS Enabled portion.
|
||||
if globalSettings.GPS_Enabled {
|
||||
msg[13] = msg[13] | (1 << 7)
|
||||
|
@ -834,6 +839,9 @@ func parseInput(buf string) ([]byte, uint16) {
|
|||
|
||||
if isUplink && msglen == UPLINK_FRAME_DATA_BYTES {
|
||||
msgtype = MSGTYPE_UPLINK
|
||||
} else if msglen == 48 {
|
||||
// With Reed Solomon appended
|
||||
msgtype = MSGTYPE_LONG_REPORT
|
||||
} else if msglen == 34 {
|
||||
msgtype = MSGTYPE_LONG_REPORT
|
||||
} else if msglen == 18 {
|
||||
|
@ -969,6 +977,7 @@ func getProductNameFromId(product_id int) string {
|
|||
type settings struct {
|
||||
UAT_Enabled bool
|
||||
ES_Enabled bool
|
||||
Ping_Enabled bool
|
||||
GPS_Enabled bool
|
||||
NetworkOutputs []networkConnection
|
||||
AHRS_Enabled bool
|
||||
|
@ -992,6 +1001,7 @@ type status struct {
|
|||
UAT_messages_max uint
|
||||
ES_messages_last_minute uint
|
||||
ES_messages_max uint
|
||||
Ping_connected bool
|
||||
GPS_satellites_locked uint16
|
||||
GPS_satellites_seen uint16
|
||||
GPS_satellites_tracked uint16
|
||||
|
@ -1197,6 +1207,7 @@ var sigs = make(chan os.Signal, 1) // Signal catch channel (shutdown).
|
|||
func gracefulShutdown() {
|
||||
// Shut down SDRs.
|
||||
sdrKill()
|
||||
pingKill()
|
||||
|
||||
// Shut down data logging.
|
||||
if dataLogStarted {
|
||||
|
@ -1267,6 +1278,7 @@ func main() {
|
|||
crcInit() // Initialize CRC16 table.
|
||||
|
||||
sdrInit()
|
||||
pingInit()
|
||||
initTraffic()
|
||||
|
||||
// Read settings.
|
||||
|
|
|
@ -212,6 +212,8 @@ func handleSettingsSetRequest(w http.ResponseWriter, r *http.Request) {
|
|||
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":
|
||||
|
|
|
@ -0,0 +1,270 @@
|
|||
/*
|
||||
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"
|
||||
"strings"
|
||||
"log"
|
||||
"os"
|
||||
"sync"
|
||||
//"sync/atomic"
|
||||
"time"
|
||||
"net"
|
||||
"os/exec"
|
||||
|
||||
// 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/ttyUSB0"); err == nil {
|
||||
device = "/dev/ttyUSB0"
|
||||
} else 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()
|
||||
}
|
12
main/sdr.go
12
main/sdr.go
|
@ -487,14 +487,18 @@ 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
|
||||
}
|
||||
|
||||
|
|
|
@ -573,7 +573,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
|
||||
}
|
||||
|
@ -584,7 +584,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")
|
||||
|
|
|
@ -115,6 +115,7 @@ 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,
|
||||
"NetworkOutputs": [
|
||||
{
|
||||
|
@ -177,4 +178,4 @@ 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}
|
||||
```
|
||||
```
|
||||
|
|
|
@ -6,7 +6,7 @@ function SettingsCtrl($rootScope, $scope, $state, $location, $window, $http) {
|
|||
|
||||
$scope.$parent.helppage = 'plates/settings-help.html';
|
||||
|
||||
var toggles = ['UAT_Enabled', 'ES_Enabled', 'GPS_Enabled', 'AHRS_Enabled', 'DisplayTrafficSource', 'DEBUG', 'ReplayLog'];
|
||||
var toggles = ['UAT_Enabled', 'ES_Enabled', 'Ping_Enabled', 'GPS_Enabled', 'AHRS_Enabled', 'DisplayTrafficSource', 'DEBUG', 'ReplayLog'];
|
||||
var settings = {};
|
||||
for (i = 0; i < toggles.length; i++) {
|
||||
settings[toggles[i]] = undefined;
|
||||
|
@ -19,6 +19,7 @@ function SettingsCtrl($rootScope, $scope, $state, $location, $window, $http) {
|
|||
$scope.rawSettings = angular.toJson(data, true);
|
||||
$scope.UAT_Enabled = settings.UAT_Enabled;
|
||||
$scope.ES_Enabled = settings.ES_Enabled;
|
||||
$scope.Ping_Enabled = settings.Ping_Enabled;
|
||||
$scope.GPS_Enabled = settings.GPS_Enabled;
|
||||
$scope.AHRS_Enabled = settings.AHRS_Enabled;
|
||||
$scope.DisplayTrafficSource = settings.DisplayTrafficSource;
|
||||
|
@ -178,4 +179,4 @@ function SettingsCtrl($rootScope, $scope, $state, $location, $window, $http) {
|
|||
});
|
||||
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -44,6 +44,7 @@ function StatusCtrl($rootScope, $scope, $state, $http, $interval) {
|
|||
$scope.Version = status.Version;
|
||||
$scope.Build = status.Build.substr(0, 10);
|
||||
$scope.Devices = status.Devices;
|
||||
$scope.Ping_connected = status.Ping_connected;
|
||||
$scope.Connected_Users = status.Connected_Users;
|
||||
$scope.UAT_messages_last_minute = status.UAT_messages_last_minute;
|
||||
// $scope.UAT_products_last_minute = JSON.stringify(status.UAT_products_last_minute);
|
||||
|
@ -102,6 +103,11 @@ function StatusCtrl($rootScope, $scope, $state, $http, $interval) {
|
|||
settings = angular.fromJson(response.data);
|
||||
$scope.visible_uat = settings.UAT_Enabled;
|
||||
$scope.visible_es = settings.ES_Enabled;
|
||||
$scope.visible_ping = settings.Ping_Enabled;
|
||||
if (settings.Ping_Enabled) {
|
||||
$scope.visible_uat = true;
|
||||
$scope.visible_es = true;
|
||||
}
|
||||
$scope.visible_gps = settings.GPS_Enabled;
|
||||
$scope.visible_ahrs = settings.AHRS_Enabled;
|
||||
}, function (response) {
|
||||
|
|
|
@ -16,6 +16,12 @@
|
|||
<ui-switch ng-model='ES_Enabled' settings-change></ui-switch>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-xs-7">Ping ADS-B</label>
|
||||
<div class="col-xs-5">
|
||||
<ui-switch ng-model='Ping_Enabled' settings-change></ui-switch>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-xs-7">GPS</label>
|
||||
<div class="col-xs-5">
|
||||
|
|
|
@ -25,10 +25,17 @@
|
|||
<strong class="col-xs-5">Recent Clients:</strong>
|
||||
<span class="col-xs-7">{{Connected_Users}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-6 label_adj">
|
||||
<strong class="col-xs-5">SDR devices:</strong>
|
||||
<span class="col-xs-7">{{Devices}}</span>
|
||||
</div>
|
||||
<div class="col-sm-6 label_adj" ng-class="{'section_invisible': !visible_ping}">
|
||||
<strong class="col-xs-5">Ping device:</strong>
|
||||
<span ng-show="Ping_connected == true" class="label label-success">Connected</span>
|
||||
<span ng-hide="Ping_connected == true" class="label label-danger">Disconnected</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="separator"></div>
|
||||
<div class="row">
|
||||
|
|
Ładowanie…
Reference in New Issue