Parser and printer for type 20 and TCAS info
This commit is contained in:
parent
cf8f429900
commit
b05bea9618
@ -72,7 +72,7 @@ class modes_flightgear(modes_parse.modes_parse):
|
||||
if complete:
|
||||
print "FG update: %s" % (self.callsigns[icao24][0])
|
||||
msg = fg_posmsg(self.callsigns[icao24][0],
|
||||
None,#TODO FIX should populate ac type; this isn't pressing bc it appears nobody populates this field
|
||||
self.callsigns[icao24][1],
|
||||
self.positions[icao24][0],
|
||||
self.positions[icao24][1],
|
||||
self.positions[icao24][2],
|
||||
@ -133,14 +133,14 @@ modelmap = { None: 'Aircraft/777-200/Models/777-200ER.xml'
|
||||
}
|
||||
|
||||
class fg_posmsg(fg_header):
|
||||
def __init__(self, callsign, model, lat, lon, alt, hdg, vel, vs, turnrate):
|
||||
def __init__(self, callsign, modelname, lat, lon, alt, hdg, vel, vs, turnrate):
|
||||
#from the above, calculate valid FGFS mp vals
|
||||
#this is the translation layer between ADS-B and FGFS
|
||||
fg_header.__init__(self)
|
||||
self.callsign = callsign
|
||||
if self.callsign is None:
|
||||
self.callsign = "UNKNOWN"
|
||||
self.modelname = model
|
||||
self.modelname = modelname
|
||||
if self.modelname not in modelmap:
|
||||
#this should keep people on their toes when strange aircraft types are seen
|
||||
self.model = 'Aircraft/santa/Models/santa.xml'
|
||||
|
@ -72,38 +72,9 @@ class data_field:
|
||||
#return the bits as a number
|
||||
return bits
|
||||
|
||||
#type MB (extended squitter types 20,21) subfields
|
||||
class mb_reply(data_field):
|
||||
fields = { "acs": (45,20), "ais": (41,48), "ara": (41,14), "bcs": (65,16),
|
||||
"bds": (33,8), "bds1": (33,4), "bds2": (37,4), "cfs": (41,4),
|
||||
"ecs": (81,8), "mte": (60,1), "rac": (55,4), "rat": (59,1),
|
||||
"tid": (33,26), "tida": (63,13), "tidb": (83,6), "tidr": (76,7),
|
||||
"tti": (61,2)
|
||||
}
|
||||
offset = 33 #fields offset by 33 to match documentation
|
||||
|
||||
#types are based on bds1 subfield
|
||||
types = { 0: ["bds", "bds1", "bds2"], #TODO
|
||||
1: ["bds", "bds1", "bds2", "cfs", "acs", "bcs"],
|
||||
2: ["bds", "bds1", "bds2", "ais"],
|
||||
3: ["bds", "bds1", "bds2", "ara", "rac", "rat",
|
||||
"mte", "tti", "tida", "tidr", "tidb"]
|
||||
}
|
||||
|
||||
def get_type(self):
|
||||
bds1 = self.get_bits(self.fields["bds1"])
|
||||
bds2 = self.get_bits(self.fields["bds2"])
|
||||
if bds1 not in (0,1,2,3) or bds2 not in (0,):
|
||||
raise NoHandlerError
|
||||
return int(bds1)
|
||||
|
||||
def get_numbits(self):
|
||||
return 56
|
||||
|
||||
class bds09_reply(data_field):
|
||||
offset = 6
|
||||
types = {
|
||||
#BDS0,9 subtype 0
|
||||
types = { #BDS0,9 subtype 0
|
||||
0: {"sub": (6,3), "dew": (10,1), "vew": (11,11), "dns": (22,1),
|
||||
"vns": (23,11), "str": (34,1), "tr": (35,6), "dvr": (41,1),
|
||||
"vr": (42,9)},
|
||||
@ -164,8 +135,47 @@ class me_reply(data_field):
|
||||
def get_numbits(self):
|
||||
return 56
|
||||
|
||||
#resolves the TCAS reply types from TTI info
|
||||
class tcas_reply(data_field):
|
||||
offset = 61
|
||||
types = { 0: {"tti": (61,2)}, #UNKNOWN
|
||||
1: {"tti": (61,2), "tid": (63,26)},
|
||||
2: {"tti": (61,2), "tida": (63,13), "tidr": (76,7), "tidb": (83,6)}
|
||||
}
|
||||
def get_type(self):
|
||||
return self.get_bits(61,2)
|
||||
|
||||
def get_numbits(self):
|
||||
return 28
|
||||
|
||||
#extended squitter types 20,21 MB subfield
|
||||
class mb_reply(data_field):
|
||||
offset = 33 #fields offset by 33 to match documentation
|
||||
#types are based on bds1 subfield
|
||||
types = { 0: {"bds1": (33,4), "bds2": (37,4)}, #TODO
|
||||
1: {"bds1": (33,4), "bds2": (37,4), "cfs": (41,4), "acs": (45,20), "bcs": (65,16), "ecs": (81,8)},
|
||||
2: {"bds1": (33,4), "bds2": (37,4), "ais": (41,48)},
|
||||
3: {"bds1": (33,4), "bds2": (37,4), "ara": (41,14), "rac": (55,4), "rat": (59,1),
|
||||
"mte": (60,1), "tcas": (61, 28, tcas_reply)}
|
||||
}
|
||||
|
||||
def get_type(self):
|
||||
bds1 = self.get_bits(33,4)
|
||||
bds2 = self.get_bits(37,4)
|
||||
if bds1 not in (0,1,2,3) or bds2 not in (0,):
|
||||
raise NoHandlerError
|
||||
return int(bds1)
|
||||
|
||||
def get_numbits(self):
|
||||
return 56
|
||||
|
||||
# #type MV (extended squitter type 16) subfields
|
||||
# mv_fields = { "ara": (41,14), "mte": (60,1), "rac": (55,4), "rat": (59,1),
|
||||
# "vds": (33,8), "vds1": (33,4), "vds2": (37,4)
|
||||
# }
|
||||
|
||||
#the whole Mode S packet type
|
||||
class modes_reply(data_field):
|
||||
#bitfield definitions according to Mode S spec for each packet type
|
||||
types = { 0: {"df": (1,5), "vs": (6,1), "cc": (7,1), "sl": (9,3), "ri": (14,4), "ac": (20,13), "ap": (33,24)},
|
||||
4: {"df": (1,5), "fs": (6,3), "dr": (9,5), "um": (14,6), "ac": (20,13), "ap": (33,24)},
|
||||
5: {"df": (1,5), "fs": (6,3), "dr": (9,5), "um": (14,6), "id": (20,13), "ap": (33,24)},
|
||||
@ -186,11 +196,6 @@ class modes_reply(data_field):
|
||||
def get_type(self):
|
||||
return self.get_bits(1,5)
|
||||
|
||||
# #type MV (extended squitter type 16) subfields
|
||||
# mv_fields = { "ara": (41,14), "mte": (60,1), "rac": (55,4), "rat": (59,1),
|
||||
# "vds": (33,8), "vds1": (33,4), "vds2": (37,4)
|
||||
# }
|
||||
|
||||
class modes_parse:
|
||||
def __init__(self, mypos):
|
||||
self.my_location = mypos
|
||||
@ -330,28 +335,42 @@ class modes_parse:
|
||||
"NO COMMUNICATIONS", "UNLAWFUL INTERFERENCE", "RESERVED", "RESERVED"]
|
||||
return eps_strings[data["me"]["eps"]]
|
||||
|
||||
# def parse20(self, shortdata, longdata):
|
||||
# [fs, dr, um, alt] = self.parse4(shortdata)
|
||||
# #BDS defines TCAS reply type and is the first 8 bits
|
||||
# #BDS1 is first four, BDS2 is bits 5-8
|
||||
# bds1 = longdata_bits(longdata, 33, 4)
|
||||
# bds2 = longdata_bits(longdata, 37, 4)
|
||||
# #bds2 != 0 defines extended TCAS capabilities, not in spec
|
||||
# return [fs, dr, um, alt, bds1, bds2]
|
||||
def parseMB_id(self, data): #bds1 == 2, bds2 == 0
|
||||
msg = ""
|
||||
for i in range(0, 8):
|
||||
msg += self.charmap( data["mb"]["ais"] >> (42-6*i) & 0x3F)
|
||||
return (msg)
|
||||
|
||||
# def parseMB_commB(self, longdata): #bds1, bds2 == 0
|
||||
# raise NoHandlerError
|
||||
def parseMB_TCAS_resolutions(self, data):
|
||||
#these are LSB because the ICAO are asshats
|
||||
ara_bits = {41: "CLIMB", 42: "DON'T DESCEND", 43: "DON'T DESCEND >500FPM", 44: "DON'T DESCEND >1000FPM",
|
||||
45: "DON'T DESCEND >2000FPM", 46: "DESCEND", 47: "DON'T CLIMB", 48: "DON'T CLIMB >500FPM",
|
||||
49: "DON'T CLIMB >1000FPM", 50: "DON'T CLIMB >2000FPM", 51: "TURN LEFT", 52: "TURN RIGHT",
|
||||
53: "DON'T TURN LEFT", 54: "DON'T TURN RIGHT"}
|
||||
rac_bits = {55: "DON'T DESCEND", 56: "DON'T CLIMB", 57: "DON'T TURN LEFT", 58: "DON'T TURN RIGHT"}
|
||||
ara = data["mb"]["ara"]
|
||||
#check to see which bits are set
|
||||
resolutions = ""
|
||||
for bit, name in ara_bits:
|
||||
if ara & (1 << (54-bit)):
|
||||
resolutions += " " + name
|
||||
complements = ""
|
||||
for bit, name in rac_bits:
|
||||
if rac & (1 << (58-bit)):
|
||||
complements += " " + name
|
||||
return (resolutions, complements)
|
||||
|
||||
# def parseMB_caps(self, longdata): #bds1 == 1, bds2 == 0
|
||||
# #cfs, acs, bcs
|
||||
# raise NoHandlerError
|
||||
#rat is 1 if resolution advisory terminated <18s ago
|
||||
#mte is 1 if multiple threats indicated
|
||||
#tti is threat type: 1 if ID, 2 if range/brg/alt
|
||||
#tida is threat altitude in Mode C format
|
||||
def parseMB_TCAS_threatid(self, data): #bds1==3, bds2==0, TTI==1
|
||||
#3: {"bds1": (33,4), "bds2": (37,4), "ara": (41,14), "rac": (55,4), "rat": (59,1),
|
||||
# "mte": (60,1), "tti": (61,2), "tida": (63,13), "tidr": (76,7), "tidb": (83,6)}
|
||||
(resolutions, complements) = self.parseMB_TCAS_resolutions(data)
|
||||
return (resolutions, complements, data["mb"]["rat"], data["mb"]["mte"], data["mb"]["tcas"]["tid"])
|
||||
|
||||
# def parseMB_id(self, longdata): #bds1 == 2, bds2 == 0
|
||||
# msg = ""
|
||||
# for i in range(0, 8):
|
||||
# msg += self.charmap( longdata >> (42-6*i) & 0x3F)
|
||||
# return (msg)
|
||||
|
||||
# def parseMB_TCASRA(self, longdata): #bds1 == 3, bds2 == 0
|
||||
#ara[41-54],rac[55-58],rat[59],mte[60],tti[61-62],tida[63-75],tidr[76-82],tidb[83-88]
|
||||
# raise NoHandlerError
|
||||
def parseMB_TCAS_threatloc(self, data): #bds1==3, bds2==0, TTI==2
|
||||
(resolutions, complements) = self.parseMB_TCAS_resolutions(data)
|
||||
threat_alt = decode_alt(data["mb"]["tcas"]["tida"], True)
|
||||
return (resolutions, complements, data["mb"]["rat"], data["mb"]["mte"], threat_alt, data["mb"]["tcas"]["tidr"], data["mb"]["tcas"]["tidb"])
|
||||
|
@ -174,3 +174,39 @@ class modes_output_print(modes_parse.modes_parse):
|
||||
retstr = "Type 17 subtype %i from %x not implemented" % (subtype, icao24)
|
||||
|
||||
return retstr
|
||||
|
||||
def print20(self, data, ecc):
|
||||
[fs, dr, um, alt] = self.parse4(data)
|
||||
mb_fields = data["mb"].get_fields()
|
||||
bds1 = mb_fields["bds1"]
|
||||
bds2 = mb_fields["bds2"]
|
||||
|
||||
if bds2 != 0:
|
||||
retstr = "No handler for BDS2 == %i from %x" % (bds2, ecc)
|
||||
|
||||
elif bds1 == 0:
|
||||
retstr = "No handler for BDS1 == 0 from %x" % ecc
|
||||
elif bds1 == 1:
|
||||
retstr = "Type 20 link capability report from %x: ACS: 0x%x, BCS: 0x%x, ECS: 0x%x, continues %i" \
|
||||
% (ecc, mb_fields["acs"], mb_fields["bcs"], mb_fields["ecs"], mb_fields["cfs"])
|
||||
elif bds1 == 2:
|
||||
retstr = "Type 20 identification from %x with text %s" % (ecc, self.parseMB_id(data))
|
||||
elif bds2 == 3:
|
||||
retstr = "TCAS report from %x: " % ecc
|
||||
tti = mb_fields["tcas"].get_type()
|
||||
if tti == 1:
|
||||
(resolutions, complements, rat, mte, threat_id) = self.parseMB_TCAS_threatid(data)
|
||||
retstr += "threat ID: %x advised: %s complement: %s" % (threat_id, resolutions, complements)
|
||||
elif tti == 2:
|
||||
(resolutions, complements, rat, mte, threat_alt, threat_range, threat_bearing) = self.parseMB_TCAS_threatloc(data)
|
||||
retstr += "range: %i bearing: %i alt: %i advised: %s complement: %s" % (threat_range, threat_bearing, threat_alt, resolutions, complements)
|
||||
else:
|
||||
retstr += " (no handler for TTI=%i)" % tti
|
||||
if mte == 1:
|
||||
retstr += " (multiple threats)"
|
||||
if rat == 1:
|
||||
retstr += " (resolved)"
|
||||
else:
|
||||
retstr = "No handler for BDS1 == %i from %x" % (bds1, ecc)
|
||||
|
||||
return retstr
|
||||
|
Loading…
Reference in New Issue
Block a user