Dump traffic list to log each second

pull/285/head
AvSquirrel 2016-02-23 05:51:52 +00:00
rodzic 2360f90861
commit 62fec20bee
1 zmienionych plików z 115 dodań i 103 usunięć

Wyświetl plik

@ -69,42 +69,42 @@ const (
// Assign next type to UAT messages with address qualifier == 2 // Assign next type to UAT messages with address qualifier == 2
// (code corresponds to and UAT GBT targets with Mode S addresses.. // (code corresponds to and UAT GBT targets with Mode S addresses..
// for we'll treat them as ADS-R in the UI. Might be able to assign as TYPE_ADSR if we see a proper emitter category and NIC > 7. // for we'll treat them as ADS-R in the UI. Might be able to assign as TYPE_ADSR if we see a proper emitter category and NIC > 7.
TARGET_TYPE_TISB_S = 4 TARGET_TYPE_TISB_S = 4
) )
type TrafficInfo struct { type TrafficInfo struct {
Icao_addr uint32 Icao_addr uint32
Tail string Tail string
Emitter_category uint8 // Formatted using GDL90 standard, e.g. in a Mode ES report, A7 becomes 0x07, B0 becomes 0x08, etc. Emitter_category uint8 // Formatted using GDL90 standard, e.g. in a Mode ES report, A7 becomes 0x07, B0 becomes 0x08, etc.
OnGround bool // Air-ground status. On-ground is "true". OnGround bool // Air-ground status. On-ground is "true".
Addr_type uint8 // UAT address qualifier. Used by GDL90 format, so translations for ES TIS-B/ADS-R are needed. Addr_type uint8 // UAT address qualifier. Used by GDL90 format, so translations for ES TIS-B/ADS-R are needed.
TargetType uint8 // types decribed in const above TargetType uint8 // types decribed in const above
SignalLevel int32 // Arbitrary signal level reported by dump1090 and dump978. SignalLevel int32 // Arbitrary signal level reported by dump1090 and dump978.
Position_valid bool // set when position report received. Unset after n seconds? (To-do) Position_valid bool // set when position report received. Unset after n seconds? (To-do)
Lat float32 // decimal degrees, north positive Lat float32 // decimal degrees, north positive
Lng float32 // decimal degrees, east positive Lng float32 // decimal degrees, east positive
Alt int32 // Pressure altitude, feet Alt int32 // Pressure altitude, feet
GnssDiffFromBaroAlt int32 // GNSS altitude above WGS84 datum. Reported in TC 20-22 messages GnssDiffFromBaroAlt int32 // GNSS altitude above WGS84 datum. Reported in TC 20-22 messages
AltIsGNSS bool // Pressure alt = 0; GNSS alt = 1 AltIsGNSS bool // Pressure alt = 0; GNSS alt = 1
NIC int // Navigation Integrity Category. NIC int // Navigation Integrity Category.
NACp int // Navigation Accuracy Category for Position. NACp int // Navigation Accuracy Category for Position.
Track uint16 // degrees true Track uint16 // degrees true
Speed uint16 // knots Speed uint16 // knots
Speed_valid bool // set when speed report received. Speed_valid bool // set when speed report received.
Vvel int16 // feet per minute Vvel int16 // feet per minute
Timestamp time.Time // timestamp of traffic message, UTC Timestamp time.Time // timestamp of traffic message, UTC
// Parameters starting at 'Age' are calculated after message receipt. // Parameters starting at 'Age' are calculated after message receipt.
// Mode S transmits position and track in separate messages, and altitude can also be // Mode S transmits position and track in separate messages, and altitude can also be
// received from interrogations. // received from interrogations.
Age float64 // seconds ago traffic last seen Age float64 // seconds ago traffic last seen
Last_seen time.Time // time of last position update, relative to Stratux startup. Used for timing out expired data. Last_seen time.Time // time of last position update, relative to Stratux startup. Used for timing out expired data.
Last_alt time.Time // time of last altitude update, relative to Stratux startup Last_alt time.Time // time of last altitude update, relative to Stratux startup
Last_speed time.Time // time of last velocity / track update, relative to Stratux startup Last_speed time.Time // time of last velocity / track update, relative to Stratux startup
Last_source uint8 // last SDR on which this target was observed Last_source uint8 // last SDR on which this target was observed
ExtrapolatedPosition bool // TO-DO: True if Stratux is "coasting" the target from last known position. ExtrapolatedPosition bool // TO-DO: True if Stratux is "coasting" the target from last known position.
Bearing float64 // TO-DO: Bearing in degrees true to traffic from ownship Bearing float64 // TO-DO: Bearing in degrees true to traffic from ownship
Distance float64 // TO-DO: Distance to traffic from ownship Distance float64 // TO-DO: Distance to traffic from ownship
} }
type dump1090Data struct { type dump1090Data struct {
@ -116,7 +116,7 @@ type dump1090Data struct {
SBS_MsgType int // type of SBS message (used in "old" 1090 parsing) SBS_MsgType int // type of SBS message (used in "old" 1090 parsing)
SignalLevel int // 0-255 SignalLevel int // 0-255
Tail *string Tail *string
Squawk *int // 12-bit squawk code in octal format Squawk *int // 12-bit squawk code in octal format
Emitter_category *int Emitter_category *int
OnGround *bool OnGround *bool
Lat *float32 Lat *float32
@ -124,13 +124,13 @@ type dump1090Data struct {
Position_valid bool Position_valid bool
NACp *int NACp *int
Alt *int Alt *int
AltIsGNSS bool // AltIsGNSS bool //
GnssDiffFromBaroAlt *int16 // GNSS height above baro altitude in feet; valid range is -3125 to 3125. +/- 3138 indicates larger difference. GnssDiffFromBaroAlt *int16 // GNSS height above baro altitude in feet; valid range is -3125 to 3125. +/- 3138 indicates larger difference.
Vvel *int16 Vvel *int16
Speed_valid bool Speed_valid bool
Speed *uint16 Speed *uint16
Track *uint16 Track *uint16
Timestamp time.Time // time traffic last seen, UTC Timestamp time.Time // time traffic last seen, UTC
} }
var traffic map[uint32]TrafficInfo var traffic map[uint32]TrafficInfo
@ -150,7 +150,19 @@ func sendTrafficUpdates() {
defer trafficMutex.Unlock() defer trafficMutex.Unlock()
cleanupOldEntries() cleanupOldEntries()
var msg []byte var msg []byte
log.Printf("List of all aircraft being tracked:\n")
log.Printf("===================================\n")
for icao, ti := range traffic { // TO-DO: Limit number of aircraft in traffic message. ForeFlight 7.5 chokes at ~1000-2000 messages depending on iDevice RAM. Practical limit likely around ~500 aircraft without filtering. for icao, ti := range traffic { // TO-DO: Limit number of aircraft in traffic message. ForeFlight 7.5 chokes at ~1000-2000 messages depending on iDevice RAM. Practical limit likely around ~500 aircraft without filtering.
// DEBUG: Print the list of all tracked targets to the log each second
s_out, err := json.Marshal(ti)
if err != nil {
log.Printf("Error generating output: %s\n", err.Error())
} else {
log.Printf("%X => %s\n", ti.Icao_addr, string(s_out))
}
// end of debug block
ti.Age = stratuxClock.Since(ti.Last_seen).Seconds() ti.Age = stratuxClock.Since(ti.Last_seen).Seconds()
traffic[icao] = ti traffic[icao] = ti
//log.Printf("Traffic age of %X is %f seconds\n",icao,ti.Age) //log.Printf("Traffic age of %X is %f seconds\n",icao,ti.Age)
@ -237,7 +249,7 @@ func makeTrafficReportMsg(ti TrafficInfo) []byte {
// Define tt type / validity // Define tt type / validity
if ti.Speed_valid { if ti.Speed_valid {
msg[12] = msg[12] | 0x01 // assume true track msg[12] = msg[12] | 0x01 // assume true track
} }
if ti.ExtrapolatedPosition { if ti.ExtrapolatedPosition {
@ -249,7 +261,7 @@ func makeTrafficReportMsg(ti TrafficInfo) []byte {
} }
// Position containment / navigational accuracy // Position containment / navigational accuracy
msg[13] = ((byte(ti.NIC) << 4) & 0xF0) | ((byte(ti.NACp) & 0x0F)) msg[13] = ((byte(ti.NIC) << 4) & 0xF0) | (byte(ti.NACp) & 0x0F)
// Horizontal velocity (speed). // Horizontal velocity (speed).
@ -346,7 +358,7 @@ func parseDownlinkReport(s string, signalLevel int32) {
ti.NIC = int(frame[11] & 0x0F) ti.NIC = int(frame[11] & 0x0F)
if ((msg_type == 1) || (msg_type == 3)) { // Since NACp is passed with normal UATreports, no need to use our ES hack. if (msg_type == 1) || (msg_type == 3) { // Since NACp is passed with normal UATreports, no need to use our ES hack.
ti.NACp = int((frame[25] >> 4) & 0x0F) ti.NACp = int((frame[25] >> 4) & 0x0F)
} }
@ -360,7 +372,7 @@ func parseDownlinkReport(s string, signalLevel int32) {
ti.TargetType = TARGET_TYPE_ADSR ti.TargetType = TARGET_TYPE_ADSR
} else if ti.Addr_type == 2 { } else if ti.Addr_type == 2 {
ti.TargetType = TARGET_TYPE_TISB_S ti.TargetType = TARGET_TYPE_TISB_S
if ((ti.NIC >= 7) && (ti.Emitter_category > 0)) { // If NIC is sufficiently and emitter type is transmitted, we'll assume it's ADS-R. if (ti.NIC >= 7) && (ti.Emitter_category > 0) { // If NIC is sufficiently and emitter type is transmitted, we'll assume it's ADS-R.
ti.TargetType = TARGET_TYPE_ADSR ti.TargetType = TARGET_TYPE_ADSR
} }
} }
@ -560,7 +572,7 @@ func esListen() {
ti = val ti = val
log.Printf("Existing target %X imported for ES update\n", icao) log.Printf("Existing target %X imported for ES update\n", icao)
} else { } else {
log.Printf("New target %X created for ES update\n",newTi.Icao_addr) log.Printf("New target %X created for ES update\n", newTi.Icao_addr)
ti.Last_seen = stratuxClock.Time // need to initialize to current stratuxClock so it doesn't get cut before we have a chance to populate a position message ti.Last_seen = stratuxClock.Time // need to initialize to current stratuxClock so it doesn't get cut before we have a chance to populate a position message
ti.Icao_addr = icao ti.Icao_addr = icao
ti.ExtrapolatedPosition = false ti.ExtrapolatedPosition = false
@ -571,33 +583,33 @@ func esListen() {
// generate human readable summary of message types for debug // generate human readable summary of message types for debug
// TO-DO: Use for ES message statistics? // TO-DO: Use for ES message statistics?
/* /*
var s1 string var s1 string
if newTi.DF == 17 { if newTi.DF == 17 {
s1 = "ADS-B" s1 = "ADS-B"
} }
if newTi.DF == 18 { if newTi.DF == 18 {
s1 = "ADS-R / TIS-B" s1 = "ADS-R / TIS-B"
} }
if newTi.DF == 4 || newTi.DF == 20 { if newTi.DF == 4 || newTi.DF == 20 {
s1 = "Surveillance, Alt. Reply" s1 = "Surveillance, Alt. Reply"
} }
if newTi.DF == 5 || newTi.DF == 21 { if newTi.DF == 5 || newTi.DF == 21 {
s1 = "Surveillance, Ident. Reply" s1 = "Surveillance, Ident. Reply"
} }
if newTi.DF == 11 { if newTi.DF == 11 {
s1 = "All-call Reply" s1 = "All-call Reply"
} }
if newTi.DF == 0 { if newTi.DF == 0 {
s1 = "Short Air-Air Surv." s1 = "Short Air-Air Surv."
} }
if newTi.DF == 16 { if newTi.DF == 16 {
s1 = "Long Air-Air Surv." s1 = "Long Air-Air Surv."
} }
*/ */
//log.Printf("Mode S message from icao=%X, DF=%02d, CA=%02d, TC=%02d (%s)\n", ti.Icao_addr, newTi.DF, newTi.CA, newTi.TypeCode, s1) //log.Printf("Mode S message from icao=%X, DF=%02d, CA=%02d, TC=%02d (%s)\n", ti.Icao_addr, newTi.DF, newTi.CA, newTi.TypeCode, s1)
@ -673,7 +685,7 @@ func esListen() {
ti.Speed_valid = true ti.Speed_valid = true
ti.Last_speed = stratuxClock.Time // only update "last seen" data on position updates ti.Last_speed = stratuxClock.Time // only update "last seen" data on position updates
} }
} else if (((newTi.DF == 17) || (newTi.DF == 18)) && (newTi.TypeCode == 19)) { // invalid speed on velocity message only } else if ((newTi.DF == 17) || (newTi.DF == 18)) && (newTi.TypeCode == 19) { // invalid speed on velocity message only
ti.Speed_valid = false ti.Speed_valid = false
} }
@ -712,7 +724,7 @@ func esListen() {
} }
ti.NIC = nic ti.NIC = nic
if ((ti.NACp < 7) && (ti.NACp < ti.NIC)) { if (ti.NACp < 7) && (ti.NACp < ti.NIC) {
ti.NACp = ti.NIC // initialize to NIC, since NIC is sent with every position report, and not all emitters report NACp. ti.NACp = ti.NIC // initialize to NIC, since NIC is sent with every position report, and not all emitters report NACp.
} }
} }
@ -722,7 +734,7 @@ func esListen() {
} }
if newTi.Emitter_category != nil { if newTi.Emitter_category != nil {
ti.Emitter_category = uint8(*newTi.Emitter_category) // validate dump1090 on live traffic ti.Emitter_category = uint8(*newTi.Emitter_category) // validate dump1090 on live traffic
} }
// Set the target type. DF=18 messages are sent by ground station, so we look at CA // Set the target type. DF=18 messages are sent by ground station, so we look at CA
@ -734,10 +746,10 @@ func esListen() {
if newTi.CA == 6 { if newTi.CA == 6 {
ti.TargetType = TARGET_TYPE_ADSR ti.TargetType = TARGET_TYPE_ADSR
ti.Addr_type = 2 ti.Addr_type = 2
} else if (newTi.CA == 2) { // 2 = TIS-B with ICAO address, 5 = TIS-B without ICAO address } else if newTi.CA == 2 { // 2 = TIS-B with ICAO address, 5 = TIS-B without ICAO address
ti.TargetType = TARGET_TYPE_TISB ti.TargetType = TARGET_TYPE_TISB
ti.Addr_type = 2 ti.Addr_type = 2
} else if (newTi.CA == 5) { } else if newTi.CA == 5 {
ti.TargetType = TARGET_TYPE_TISB ti.TargetType = TARGET_TYPE_TISB
ti.Addr_type = 3 ti.Addr_type = 3
} }
@ -761,12 +773,12 @@ func esListen() {
ti.Timestamp = newTi.Timestamp // only update "last seen" data on position updates ti.Timestamp = newTi.Timestamp // only update "last seen" data on position updates
ti.Last_source = TRAFFIC_SOURCE_1090ES ti.Last_source = TRAFFIC_SOURCE_1090ES
/* /*
s_out, err := json.Marshal(ti) s_out, err := json.Marshal(ti)
if err != nil { if err != nil {
log.Printf("Error generating output: %s\n", err.Error()) log.Printf("Error generating output: %s\n", err.Error())
} else { } else {
log.Printf("%X (DF%d) => %s\n", ti.Icao_addr, newTi.DF, string(s_out)) log.Printf("%X (DF%d) => %s\n", ti.Icao_addr, newTi.DF, string(s_out))
} }
*/ */
traffic[ti.Icao_addr] = ti // Update information on this ICAO code. traffic[ti.Icao_addr] = ti // Update information on this ICAO code.