kopia lustrzana https://github.com/cyoung/stratux
rodzic
3e972b3753
commit
0dc32f23e1
|
@ -1,6 +1,7 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"../uatparse"
|
||||||
"bufio"
|
"bufio"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
@ -73,10 +74,12 @@ var gpsReplayfp *os.File
|
||||||
var ahrsReplayfp *os.File
|
var ahrsReplayfp *os.File
|
||||||
|
|
||||||
type msg struct {
|
type msg struct {
|
||||||
MessageClass uint
|
MessageClass uint
|
||||||
TimeReceived time.Time
|
TimeReceived time.Time
|
||||||
Data []byte
|
Data []byte
|
||||||
Product uint32
|
Product uint32
|
||||||
|
Signal_strength int
|
||||||
|
ADSBTowerID string // Index in the 'ADSBTowers' map, if this is a parseable uplink message.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Raw inputs.
|
// Raw inputs.
|
||||||
|
@ -85,6 +88,18 @@ var MsgLog []msg
|
||||||
// Time gen_gdl90 was started.
|
// Time gen_gdl90 was started.
|
||||||
var timeStarted time.Time
|
var timeStarted time.Time
|
||||||
|
|
||||||
|
type ADSBTower struct {
|
||||||
|
Lat float64
|
||||||
|
Lng float64
|
||||||
|
Signal_strength_last_minute int
|
||||||
|
signal_power_last_minute int64 // Over total messages.
|
||||||
|
Signal_strength_max int
|
||||||
|
Messages_last_minute uint64
|
||||||
|
Messages_total uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
var ADSBTowers map[string]ADSBTower // Running list of all towers seen. (lat,lng) -> ADSBTower
|
||||||
|
|
||||||
// Construct the CRC table. Adapted from FAA ref above.
|
// Construct the CRC table. Adapted from FAA ref above.
|
||||||
func crcInit() {
|
func crcInit() {
|
||||||
var i uint16
|
var i uint16
|
||||||
|
@ -315,12 +330,30 @@ func updateMessageStats() {
|
||||||
UAT_messages_last_minute := uint(0)
|
UAT_messages_last_minute := uint(0)
|
||||||
ES_messages_last_minute := uint(0)
|
ES_messages_last_minute := uint(0)
|
||||||
products_last_minute := make(map[string]uint32)
|
products_last_minute := make(map[string]uint32)
|
||||||
|
|
||||||
|
// Clear out ADSBTowers stats.
|
||||||
|
for t, tinf := range ADSBTowers {
|
||||||
|
tinf.Messages_last_minute = 0
|
||||||
|
tinf.Signal_strength_last_minute = 0
|
||||||
|
ADSBTowers[t] = tinf
|
||||||
|
}
|
||||||
|
|
||||||
for i := 0; i < m; i++ {
|
for i := 0; i < m; i++ {
|
||||||
if time.Now().Sub(MsgLog[i].TimeReceived).Minutes() < 1 {
|
if time.Now().Sub(MsgLog[i].TimeReceived).Minutes() < 1 {
|
||||||
t = append(t, MsgLog[i])
|
t = append(t, MsgLog[i])
|
||||||
if MsgLog[i].MessageClass == MSGCLASS_UAT {
|
if MsgLog[i].MessageClass == MSGCLASS_UAT {
|
||||||
UAT_messages_last_minute++
|
UAT_messages_last_minute++
|
||||||
products_last_minute[getProductNameFromId(int(MsgLog[i].Product))]++
|
products_last_minute[getProductNameFromId(int(MsgLog[i].Product))]++
|
||||||
|
if len(MsgLog[i].ADSBTowerID) > 0 { // Update tower stats.
|
||||||
|
tid := MsgLog[i].ADSBTowerID
|
||||||
|
twr := ADSBTowers[tid]
|
||||||
|
twr.Messages_last_minute++
|
||||||
|
twr.signal_power_last_minute += int64(MsgLog[i].Signal_strength)
|
||||||
|
if MsgLog[i].Signal_strength > twr.Signal_strength_max { // Update alltime max signal strength.
|
||||||
|
twr.Signal_strength_max = MsgLog[i].Signal_strength
|
||||||
|
}
|
||||||
|
ADSBTowers[tid] = twr
|
||||||
|
}
|
||||||
} else if MsgLog[i].MessageClass == MSGCLASS_ES {
|
} else if MsgLog[i].MessageClass == MSGCLASS_ES {
|
||||||
ES_messages_last_minute++
|
ES_messages_last_minute++
|
||||||
}
|
}
|
||||||
|
@ -339,6 +372,16 @@ func updateMessageStats() {
|
||||||
globalStatus.ES_messages_max = ES_messages_last_minute
|
globalStatus.ES_messages_max = ES_messages_last_minute
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update average signal strength over last minute for all ADSB towers.
|
||||||
|
for t, tinf := range ADSBTowers {
|
||||||
|
if tinf.Messages_last_minute == 0 {
|
||||||
|
tinf.Signal_strength_last_minute = 0
|
||||||
|
} else {
|
||||||
|
tinf.Signal_strength_last_minute = int(tinf.signal_power_last_minute / int64(tinf.Messages_last_minute))
|
||||||
|
}
|
||||||
|
ADSBTowers[t] = tinf
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateStatus() {
|
func updateStatus() {
|
||||||
|
@ -407,12 +450,15 @@ func parseInput(buf string) ([]byte, uint16) {
|
||||||
parseDownlinkReport(s)
|
parseDownlinkReport(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var thisSignalStrength int
|
||||||
|
|
||||||
if isUplink && len(x) >= 3 {
|
if isUplink && len(x) >= 3 {
|
||||||
// See if we can parse out the signal strength.
|
// See if we can parse out the signal strength.
|
||||||
ss := x[2]
|
ss := x[2]
|
||||||
if strings.HasPrefix(ss, "ss=") {
|
if strings.HasPrefix(ss, "ss=") {
|
||||||
ssStr := ss[3:]
|
ssStr := ss[3:]
|
||||||
if ssInt, err := strconv.Atoi(ssStr); err == nil {
|
if ssInt, err := strconv.Atoi(ssStr); err == nil {
|
||||||
|
thisSignalStrength = ssInt
|
||||||
if ssInt > maxSignalStrength {
|
if ssInt > maxSignalStrength {
|
||||||
maxSignalStrength = ssInt
|
maxSignalStrength = ssInt
|
||||||
}
|
}
|
||||||
|
@ -427,7 +473,7 @@ func parseInput(buf string) ([]byte, uint16) {
|
||||||
return nil, 0
|
return nil, 0
|
||||||
}
|
}
|
||||||
|
|
||||||
if msglen == UPLINK_FRAME_DATA_BYTES {
|
if isUplink && msglen == UPLINK_FRAME_DATA_BYTES {
|
||||||
msgtype = MSGTYPE_UPLINK
|
msgtype = MSGTYPE_UPLINK
|
||||||
} else if msglen == 34 {
|
} else if msglen == 34 {
|
||||||
msgtype = MSGTYPE_LONG_REPORT
|
msgtype = MSGTYPE_LONG_REPORT
|
||||||
|
@ -449,7 +495,26 @@ func parseInput(buf string) ([]byte, uint16) {
|
||||||
thisMsg.MessageClass = MSGCLASS_UAT
|
thisMsg.MessageClass = MSGCLASS_UAT
|
||||||
thisMsg.TimeReceived = time.Now()
|
thisMsg.TimeReceived = time.Now()
|
||||||
thisMsg.Data = frame
|
thisMsg.Data = frame
|
||||||
thisMsg.Product = 9999
|
thisMsg.Product = 9999 //FIXME.
|
||||||
|
thisMsg.Signal_strength = thisSignalStrength
|
||||||
|
if msgtype == MSGTYPE_UPLINK {
|
||||||
|
// Parse the UAT message.
|
||||||
|
uatMsg, err := uatparse.New(buf)
|
||||||
|
if err == nil {
|
||||||
|
uatMsg.DecodeUplink()
|
||||||
|
towerid := fmt.Sprintf("(%f,%f)", uatMsg.Lat, uatMsg.Lon)
|
||||||
|
thisMsg.ADSBTowerID = towerid
|
||||||
|
if _, ok := ADSBTowers[towerid]; !ok { // First time we've seen the tower. Start tracking.
|
||||||
|
var newTower ADSBTower
|
||||||
|
newTower.Lat = uatMsg.Lat
|
||||||
|
newTower.Lng = uatMsg.Lon
|
||||||
|
ADSBTowers[towerid] = newTower
|
||||||
|
}
|
||||||
|
twr := ADSBTowers[towerid]
|
||||||
|
twr.Messages_total++
|
||||||
|
ADSBTowers[towerid] = twr
|
||||||
|
}
|
||||||
|
}
|
||||||
if isUplink && msgtype == MSGTYPE_UPLINK && len(x) > 11 { //FIXME: Need to pull out FIS-B frames from within the uplink packet.
|
if isUplink && msgtype == MSGTYPE_UPLINK && len(x) > 11 { //FIXME: Need to pull out FIS-B frames from within the uplink packet.
|
||||||
thisMsg.Product = ((uint32(frame[10]) & 0x1f) << 6) | (uint32(frame[11]) >> 2)
|
thisMsg.Product = ((uint32(frame[10]) & 0x1f) << 6) | (uint32(frame[11]) >> 2)
|
||||||
}
|
}
|
||||||
|
@ -647,6 +712,7 @@ func main() {
|
||||||
|
|
||||||
log.Printf("Stratux %s (%s) starting.\n", stratuxVersion, stratuxBuild)
|
log.Printf("Stratux %s (%s) starting.\n", stratuxVersion, stratuxBuild)
|
||||||
|
|
||||||
|
ADSBTowers = make(map[string]ADSBTower)
|
||||||
MsgLog = make([]msg, 0)
|
MsgLog = make([]msg, 0)
|
||||||
|
|
||||||
crcInit() // Initialize CRC16 table.
|
crcInit() // Initialize CRC16 table.
|
||||||
|
|
|
@ -92,6 +92,12 @@ func handleSituationRequest(w http.ResponseWriter, r *http.Request) {
|
||||||
fmt.Fprintf(w, "%s\n", situationJSON)
|
fmt.Fprintf(w, "%s\n", situationJSON)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AJAX call - /getTowers. Responds with all ADS-B ground towers that have sent messages that we were able to parse, along with its stats.
|
||||||
|
func handleTowersRequest(w http.ResponseWriter, r *http.Request) {
|
||||||
|
towersJSON, _ := json.Marshal(&ADSBTowers)
|
||||||
|
fmt.Fprintf(w, "%s\n", towersJSON)
|
||||||
|
}
|
||||||
|
|
||||||
func managementInterface() {
|
func managementInterface() {
|
||||||
http.Handle("/", http.FileServer(http.Dir("/var/www")))
|
http.Handle("/", http.FileServer(http.Dir("/var/www")))
|
||||||
http.Handle("/logs/", http.StripPrefix("/logs/", http.FileServer(http.Dir("/var/log"))))
|
http.Handle("/logs/", http.StripPrefix("/logs/", http.FileServer(http.Dir("/var/log"))))
|
||||||
|
@ -104,6 +110,7 @@ func managementInterface() {
|
||||||
|
|
||||||
http.HandleFunc("/getTraffic", handleTrafficRequest)
|
http.HandleFunc("/getTraffic", handleTrafficRequest)
|
||||||
http.HandleFunc("/getSituation", handleSituationRequest)
|
http.HandleFunc("/getSituation", handleSituationRequest)
|
||||||
|
http.HandleFunc("/getTowers", handleTowersRequest)
|
||||||
|
|
||||||
err := http.ListenAndServe(managementAddr, nil)
|
err := http.ListenAndServe(managementAddr, nil)
|
||||||
|
|
||||||
|
|
Ładowanie…
Reference in New Issue