New parser works. TCAS untested. Extra info in print. Fixed ground_track printing error. Surface reports suppressed due to possible CPR bug. Not all code paths tested.
This commit is contained in:
parent
b05bea9618
commit
28824cb0b2
@ -29,11 +29,10 @@ from modes_exceptions import *
|
||||
latz = 15
|
||||
|
||||
def nbits(surface):
|
||||
return 17
|
||||
# if surface == 1:
|
||||
# return 19
|
||||
# else:
|
||||
# return 17
|
||||
if surface == 1:
|
||||
return 19
|
||||
else:
|
||||
return 17
|
||||
|
||||
def nz(ctype):
|
||||
return 4 * latz - ctype
|
||||
@ -97,18 +96,14 @@ def cpr_resolve_local(my_location, encoded_location, ctype, surface):
|
||||
def cpr_resolve_global(evenpos, oddpos, mostrecent, surface):
|
||||
dlateven = dlat(0, surface)
|
||||
dlatodd = dlat(1, surface)
|
||||
if surface is True:
|
||||
scalar = float(2**19)
|
||||
else:
|
||||
scalar = float(2**17)
|
||||
|
||||
evenpos = [float(evenpos[0]), float(evenpos[1])]
|
||||
oddpos = [float(oddpos[0]), float(oddpos[1])]
|
||||
|
||||
j = math.floor(((nz(1)*evenpos[0] - nz(0)*oddpos[0])/scalar) + 0.5) #latitude index
|
||||
j = math.floor(((nz(1)*evenpos[0] - nz(0)*oddpos[0])/2**17) + 0.5) #latitude index
|
||||
|
||||
rlateven = dlateven * ((j % nz(0))+evenpos[0]/scalar)
|
||||
rlatodd = dlatodd * ((j % nz(1))+ oddpos[0]/scalar)
|
||||
rlateven = dlateven * ((j % nz(0))+evenpos[0]/2**17)
|
||||
rlatodd = dlatodd * ((j % nz(1))+ oddpos[0]/2**17)
|
||||
|
||||
#limit to -90, 90
|
||||
if rlateven > 270.0:
|
||||
@ -131,14 +126,14 @@ def cpr_resolve_global(evenpos, oddpos, mostrecent, surface):
|
||||
nlthing = nl(rlat)
|
||||
ni = max(nlthing - mostrecent, 1)
|
||||
|
||||
m = math.floor(((evenpos[1]*(nlthing-1)-oddpos[1]*(nlthing))/scalar)+0.5) #longitude index
|
||||
m = math.floor(((evenpos[1]*(nlthing-1)-oddpos[1]*(nlthing))/2**17)+0.5) #longitude index
|
||||
|
||||
if mostrecent == 0:
|
||||
enclon = evenpos[1]
|
||||
else:
|
||||
enclon = oddpos[1]
|
||||
|
||||
rlon = dl * (((ni+m) % ni)+enclon/2**nbits(surface))
|
||||
rlon = dl * (((ni+m) % ni)+enclon/2**17)
|
||||
|
||||
if rlon > 180:
|
||||
rlon = rlon - 360.0
|
||||
@ -172,8 +167,6 @@ def range_bearing(loc_a, loc_b):
|
||||
bearing += 360.0
|
||||
|
||||
rnge = math.hypot(distance_East,distance_North)
|
||||
|
||||
|
||||
return [rnge, bearing]
|
||||
|
||||
class cpr_decoder:
|
||||
@ -203,32 +196,30 @@ class cpr_decoder:
|
||||
|
||||
#okay, let's traverse the lists and weed out those entries that are older than 15 minutes, as they're unlikely to be useful.
|
||||
self.weed_poslists()
|
||||
|
||||
if surface==1:
|
||||
validrange = 45
|
||||
else:
|
||||
validrange = 180
|
||||
|
||||
if icao24 in self.lkplist:
|
||||
#do emitter-centered local decoding
|
||||
[decoded_lat, decoded_lon] = cpr_resolve_local(self.lkplist[icao24][0:2], [encoded_lat, encoded_lon], cpr_format, surface)
|
||||
self.lkplist[icao24] = [decoded_lat, decoded_lon, time.time()] #update the local position for next time
|
||||
|
||||
elif ((icao24 in self.evenlist) and (icao24 in self.oddlist) and abs(self.evenlist[icao24][2] - self.oddlist[icao24][2]) < 10):
|
||||
elif (icao24 in self.evenlist) \
|
||||
and (icao24 in self.oddlist) \
|
||||
and (abs(self.evenlist[icao24][2] - self.oddlist[icao24][2]) < 10) \
|
||||
and (surface == 0):
|
||||
newer = (self.oddlist[icao24][2] - self.evenlist[icao24][2]) > 0 #figure out which report is newer
|
||||
[decoded_lat, decoded_lon] = cpr_resolve_global(self.evenlist[icao24][0:2], self.oddlist[icao24][0:2], newer, surface) #do a global decode
|
||||
[decoded_lat, decoded_lon] = cpr_resolve_global(self.evenlist[icao24][0:2], self.oddlist[icao24][0:2], newer, surface) #do a global decode
|
||||
self.lkplist[icao24] = [decoded_lat, decoded_lon, time.time()]
|
||||
else:
|
||||
raise CPRNoPositionError
|
||||
|
||||
#so we really can't guarantee that local decoding will work unless you are POSITIVE that you can't hear more than 180nm out.
|
||||
#this will USUALLY work, but you can't guarantee it!
|
||||
# elif self.my_location is not None: #if we have a location, use it
|
||||
# [local_lat, local_lon] = cpr_resolve_local(self.my_location, [encoded_lat, encoded_lon], cpr_format, surface) #try local decoding
|
||||
# [rnge, bearing] = range_bearing(self.my_location, [local_lat, local_lon])
|
||||
# if rnge < validrange: #if the local decoding can be guaranteed valid
|
||||
# self.lkplist[icao24] = [local_lat, local_lon, time.time()] #update the local position for next time
|
||||
# [decoded_lat, decoded_lon] = [local_lat, local_lon]
|
||||
#elif surface == 1 and self.my_location is not None:
|
||||
# [local_lat, local_lon] = cpr_resolve_local(self.my_location, [encoded_lat, encoded_lon], cpr_format, surface) #try local decoding
|
||||
# [rnge, bearing] = range_bearing(self.my_location, [local_lat, local_lon])
|
||||
# if rnge < validrange: #if the local decoding can be guaranteed valid
|
||||
# self.lkplist[icao24] = [local_lat, local_lon, time.time()] #update the local position for next time
|
||||
# [decoded_lat, decoded_lon] = [local_lat, local_lon]
|
||||
else:
|
||||
raise CPRNoPositionError
|
||||
|
||||
if self.my_location is not None:
|
||||
[rnge, bearing] = range_bearing(self.my_location, [decoded_lat, decoded_lon])
|
||||
|
@ -41,8 +41,8 @@ class modes_flightgear(modes_parse.modes_parse):
|
||||
self.callsigns[icao24] = [ident, actype]
|
||||
|
||||
elif 5 <= subtype <= 8: #BDS0,6 pos
|
||||
[altitude, decoded_lat, decoded_lon, rnge, bearing] = self.parseBDS06(data)
|
||||
self.positions[icao24] = [decoded_lat, decoded_lon, altitude]
|
||||
[ground_track, decoded_lat, decoded_lon, rnge, bearing] = self.parseBDS06(data)
|
||||
self.positions[icao24] = [decoded_lat, decoded_lon, 0]
|
||||
self.update(icao24)
|
||||
|
||||
elif 9 <= subtype <= 18: #BDS0,5 pos
|
||||
|
@ -130,7 +130,7 @@ class me_reply(data_field):
|
||||
elif ftc == 28:
|
||||
return 0x61
|
||||
else:
|
||||
return NoHandlerError
|
||||
return NoHandlerError(ftc)
|
||||
|
||||
def get_numbits(self):
|
||||
return 56
|
||||
@ -163,7 +163,7 @@ class mb_reply(data_field):
|
||||
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
|
||||
raise NoHandlerError(bds1)
|
||||
return int(bds1)
|
||||
|
||||
def get_numbits(self):
|
||||
@ -263,9 +263,9 @@ class modes_parse:
|
||||
encoded_lon = data["me"]["lon"]
|
||||
encoded_lat = data["me"]["lat"]
|
||||
cpr_format = data["me"]["cpr"]
|
||||
altitude = decode_alt(data["me"]["alt"], False)
|
||||
ground_track = data["me"]["gtk"] * 360. / 128
|
||||
[decoded_lat, decoded_lon, rnge, bearing] = self.cpr.decode(icao24, encoded_lat, encoded_lon, cpr_format, 1)
|
||||
return [altitude, decoded_lat, decoded_lon, rnge, bearing]
|
||||
return [ground_track, decoded_lat, decoded_lon, rnge, bearing]
|
||||
|
||||
def parseBDS09_0(self, data):
|
||||
#0: ["sub", "dew", "vew", "dns", "vns", "str", "tr", "svr", "vr"],
|
||||
|
@ -60,7 +60,7 @@ class modes_output_print(modes_parse.modes_parse):
|
||||
output += "No handler for message type %i from %x (but it's in modes_parse)" % (msgtype, ecc)
|
||||
print output
|
||||
except NoHandlerError as e:
|
||||
output += "No handler for message type %i from %x" % (msgtype, ecc)
|
||||
output += "No handler for message type %s from %x" % (e.msgtype, ecc)
|
||||
print output
|
||||
except MetricAltError:
|
||||
pass
|
||||
@ -71,7 +71,6 @@ class modes_output_print(modes_parse.modes_parse):
|
||||
[vs, cc, sl, ri, altitude] = self.parse0(shortdata)
|
||||
|
||||
retstr = "Type 0 (short A-A surveillance) from %x at %ift" % (ecc, altitude)
|
||||
# the ri values below 9 are used for other things. might want to print those someday.
|
||||
if ri == 0:
|
||||
retstr += " (No TCAS)"
|
||||
elif ri == 2:
|
||||
@ -129,7 +128,7 @@ class modes_output_print(modes_parse.modes_parse):
|
||||
|
||||
def print11(self, data, ecc):
|
||||
[icao24, interrogator, ca] = self.parse11(data, ecc)
|
||||
retstr = "Type 11 (all call reply) from %x in reply to interrogator %i" % (icao24, interrogator)
|
||||
retstr = "Type 11 (all call reply) from %x in reply to interrogator %i with capability level %i" % (icao24, interrogator, ca+1)
|
||||
return retstr
|
||||
|
||||
def print17(self, data):
|
||||
@ -143,8 +142,8 @@ class modes_output_print(modes_parse.modes_parse):
|
||||
retstr = "Type 17 subtype 04 (ident) from %x type %s ident %s" % (icao24, typestring, msg)
|
||||
|
||||
elif subtype >= 5 and subtype <= 8:
|
||||
[altitude, decoded_lat, decoded_lon, rnge, bearing] = self.parseBDS06(data)
|
||||
retstr = "Type 17 subtype 06 (surface report) from %x at (%.6f, %.6f)" % (icao24, decoded_lat, decoded_lon)
|
||||
[ground_track, decoded_lat, decoded_lon, rnge, bearing] = self.parseBDS06(data)
|
||||
retstr = "Type 17 subtype 06 (surface report) from %x at (%.6f, %.6f) ground track %i" % (icao24, decoded_lat, decoded_lon, ground_track)
|
||||
if rnge is not None and bearing is not None:
|
||||
retstr += " (%.2f @ %.0f)" % (rnge, bearing)
|
||||
|
||||
|
@ -103,25 +103,23 @@ class modes_output_sbs1(modes_parse.modes_parse):
|
||||
def parse(self, message):
|
||||
#assembles a SBS-1-style output string from the received message
|
||||
|
||||
[msgtype, shortdata, longdata, parity, ecc, reference, timestamp] = message.split()
|
||||
[data, ecc, reference, timestamp] = message.split()
|
||||
|
||||
shortdata = long(shortdata, 16)
|
||||
longdata = long(longdata, 16)
|
||||
parity = long(parity, 16)
|
||||
data = modes_parse.modes_reply(long(data, 16))
|
||||
ecc = long(ecc, 16)
|
||||
msgtype = int(msgtype)
|
||||
msgtype = data["df"]
|
||||
outmsg = None
|
||||
|
||||
if msgtype == 0:
|
||||
outmsg = self.pp0(shortdata, ecc)
|
||||
outmsg = self.pp0(data, ecc)
|
||||
elif msgtype == 4:
|
||||
outmsg = self.pp4(shortdata, ecc)
|
||||
outmsg = self.pp4(data, ecc)
|
||||
elif msgtype == 5:
|
||||
outmsg = self.pp5(shortdata, ecc)
|
||||
outmsg = self.pp5(data, ecc)
|
||||
elif msgtype == 11:
|
||||
outmsg = self.pp11(shortdata, ecc)
|
||||
outmsg = self.pp11(data, ecc)
|
||||
elif msgtype == 17:
|
||||
outmsg = self.pp17(shortdata, longdata)
|
||||
outmsg = self.pp17(data)
|
||||
else:
|
||||
raise NoHandlerError(msgtype)
|
||||
return outmsg
|
||||
@ -147,7 +145,7 @@ class modes_output_sbs1(modes_parse.modes_parse):
|
||||
def pp5(self, shortdata, ecc):
|
||||
# I'm not sure what to do with the identiifcation shortdata & 0x1FFF
|
||||
[datestr, timestr] = self.current_time()
|
||||
[fs, dr, um] = self.parse5(shortdata)
|
||||
[fs, dr, um, ident] = self.parse5(shortdata)
|
||||
aircraft_id = self.get_aircraft_id(ecc)
|
||||
retstr = "MSG,6,0,%i,%06X,%i,%s,%s,%s,%s,,,,,,,,," % (aircraft_id, ecc, aircraft_id+100, datestr, timestr, datestr, timestr)
|
||||
return retstr + self.decode_fs(fs) + "\n"
|
||||
@ -158,10 +156,10 @@ class modes_output_sbs1(modes_parse.modes_parse):
|
||||
aircraft_id = self.get_aircraft_id(icao24)
|
||||
return "MSG,8,0,%i,%06X,%i,%s,%s,%s,%s,,,,,,,,,,,,\n" % (aircraft_id, icao24, aircraft_id+100, datestr, timestr, datestr, timestr)
|
||||
|
||||
def pp17(self, shortdata, longdata):
|
||||
icao24 = shortdata & 0xFFFFFF
|
||||
def pp17(self, data):
|
||||
icao24 = data["aa"]
|
||||
aircraft_id = self.get_aircraft_id(icao24)
|
||||
subtype = (longdata >> 51) & 0x1F
|
||||
subtype = data["me"]["ftc"]
|
||||
|
||||
retstr = None
|
||||
#we'll get better timestamps later, hopefully with actual VRT time
|
||||
@ -170,23 +168,22 @@ class modes_output_sbs1(modes_parse.modes_parse):
|
||||
|
||||
if subtype >= 1 and subtype <= 4:
|
||||
# Aircraft Identification
|
||||
(msg, typestring) = self.parseBDS08(shortdata, longdata)
|
||||
(msg, typestring) = self.parseBDS08(data)
|
||||
retstr = "MSG,1,0,%i,%06X,%i,%s,%s,%s,%s,%s,,,,,,,,,,,\n" % (aircraft_id, icao24, aircraft_id+100, datestr, timestr, datestr, timestr, msg)
|
||||
|
||||
elif subtype >= 5 and subtype <= 8:
|
||||
# Surface position measurement
|
||||
[altitude, decoded_lat, decoded_lon, rnge, bearing] = self.parseBDS06(shortdata, longdata)
|
||||
[ground_track, decoded_lat, decoded_lon, rnge, bearing] = self.parseBDS06(data)
|
||||
altitude = 0
|
||||
if decoded_lat is None: #no unambiguously valid position available
|
||||
retstr = None
|
||||
else:
|
||||
retstr = "MSG,2,0,%i,%06X,%i,%s,%s,%s,%s,,%i,,,%.5f,%.5f,,,,0,0,0\n" % (aircraft_id, icao24, aircraft_id+100, datestr, timestr, datestr, timestr, altitude, decoded_lat, decoded_lon)
|
||||
|
||||
elif subtype >= 9 and subtype <= 18 and subtype != 15:
|
||||
elif subtype >= 9 and subtype <= 18:
|
||||
# Airborne position measurements
|
||||
# WRONG (rnge, bearing), is this still true?
|
||||
# i'm eliminating type 15 records because they don't appear to be
|
||||
# valid position reports.
|
||||
[altitude, decoded_lat, decoded_lon, rnge, bearing] = self.parseBDS05(shortdata, longdata)
|
||||
[altitude, decoded_lat, decoded_lon, rnge, bearing] = self.parseBDS05(data)
|
||||
if decoded_lat is None: #no unambiguously valid position available
|
||||
retstr = None
|
||||
else:
|
||||
@ -195,13 +192,13 @@ class modes_output_sbs1(modes_parse.modes_parse):
|
||||
elif subtype == 19:
|
||||
# Airborne velocity measurements
|
||||
# WRONG (heading, vert_spd), Is this still true?
|
||||
subsubtype = (longdata >> 48) & 0x07
|
||||
subsubtype = data["me"]["bds09"]["sub"]
|
||||
if subsubtype == 0:
|
||||
[velocity, heading, vert_spd] = self.parseBDS09_0(shortdata, longdata)
|
||||
[velocity, heading, vert_spd] = self.parseBDS09_0(data)
|
||||
retstr = "MSG,4,0,%i,%06X,%i,%s,%s,%s,%s,,,%.1f,%.1f,,,%i,,,,,\n" % (aircraft_id, icao24, aircraft_id+100, datestr, timestr, datestr, timestr, velocity, heading, vert_spd)
|
||||
|
||||
elif subsubtype == 1:
|
||||
[velocity, heading, vert_spd] = self.parseBDS09_1(shortdata, longdata)
|
||||
elif 1 <= subsubtype <= 2:
|
||||
[velocity, heading, vert_spd] = self.parseBDS09_1(data)
|
||||
retstr = "MSG,4,0,%i,%06X,%i,%s,%s,%s,%s,,,%.1f,%.1f,,,%i,,,,,\n" % (aircraft_id, icao24, aircraft_id+100, datestr, timestr, datestr, timestr, velocity, heading, vert_spd)
|
||||
|
||||
return retstr
|
||||
|
@ -72,59 +72,53 @@ class modes_output_sql(modes_parse.modes_parse):
|
||||
def make_insert_query(self, message):
|
||||
#assembles a SQL query tailored to our database
|
||||
#this version ignores anything that isn't Type 17 for now, because we just don't care
|
||||
[msgtype, shortdata, longdata, parity, ecc, reference, timestamp] = message.split()
|
||||
[data, ecc, reference, timestamp] = message.split()
|
||||
|
||||
shortdata = long(shortdata, 16)
|
||||
longdata = long(longdata, 16)
|
||||
parity = long(parity, 16)
|
||||
data = modes_parse.modes_reply(long(data, 16))
|
||||
ecc = long(ecc, 16)
|
||||
# reference = float(reference)
|
||||
|
||||
msgtype = int(msgtype)
|
||||
|
||||
query = None
|
||||
|
||||
msgtype = data["df"]
|
||||
if msgtype == 17:
|
||||
query = self.sql17(shortdata, longdata)
|
||||
query = self.sql17(data)
|
||||
|
||||
return query
|
||||
|
||||
def sql17(self, shortdata, longdata):
|
||||
icao24 = shortdata & 0xFFFFFF
|
||||
subtype = (longdata >> 51) & 0x1F
|
||||
def sql17(self, data):
|
||||
icao24 = data["aa"]
|
||||
subtype = data["me"]["ftc"]
|
||||
|
||||
retstr = None
|
||||
|
||||
if subtype == 4:
|
||||
(msg, typename) = self.parseBDS08(shortdata, longdata)
|
||||
(msg, typename) = self.parseBDS08(data)
|
||||
retstr = "INSERT OR REPLACE INTO ident (icao, ident) VALUES (" + "%i" % icao24 + ", '" + msg + "')"
|
||||
|
||||
elif subtype >= 5 and subtype <= 8:
|
||||
[altitude, decoded_lat, decoded_lon, rnge, bearing] = self.parseBDS06(shortdata, longdata)
|
||||
[ground_track, decoded_lat, decoded_lon, rnge, bearing] = self.parseBDS06(data)
|
||||
altitude = 0
|
||||
if decoded_lat is None: #no unambiguously valid position available
|
||||
retstr = None
|
||||
else:
|
||||
retstr = "INSERT INTO positions (icao, seen, alt, lat, lon) VALUES (" + "%i" % icao24 + ", datetime('now'), " + str(altitude) + ", " + "%.6f" % decoded_lat + ", " + "%.6f" % decoded_lon + ")"
|
||||
|
||||
elif subtype >= 9 and subtype <= 18 and subtype != 15: #i'm eliminating type 15 records because they don't appear to be valid position reports.
|
||||
[altitude, decoded_lat, decoded_lon, rnge, bearing] = self.parseBDS05(shortdata, longdata)
|
||||
[altitude, decoded_lat, decoded_lon, rnge, bearing] = self.parseBDS05(data)
|
||||
if decoded_lat is None: #no unambiguously valid position available
|
||||
retstr = None
|
||||
else:
|
||||
retstr = "INSERT INTO positions (icao, seen, alt, lat, lon) VALUES (" + "%i" % icao24 + ", datetime('now'), " + str(altitude) + ", " + "%.6f" % decoded_lat + ", " + "%.6f" % decoded_lon + ")"
|
||||
|
||||
elif subtype == 19:
|
||||
subsubtype = (longdata >> 48) & 0x07
|
||||
subsubtype = data["me"]["bds09"]["sub"]
|
||||
if subsubtype == 0:
|
||||
[velocity, heading, vert_spd] = self.parseBDS09_0(shortdata, longdata)
|
||||
[velocity, heading, vert_spd] = self.parseBDS09_0(data)
|
||||
retstr = "INSERT INTO vectors (icao, seen, speed, heading, vertical) VALUES (" + "%i" % icao24 + ", datetime('now'), " + "%.0f" % velocity + ", " + "%.0f" % heading + ", " + "%.0f" % vert_spd + ")";
|
||||
|
||||
elif subsubtype == 1:
|
||||
[velocity, heading, vert_spd] = self.parseBDS09_1(shortdata, longdata)
|
||||
elif 1 <= subsubtype <= 2:
|
||||
[velocity, heading, vert_spd] = self.parseBDS09_1(data)
|
||||
retstr = "INSERT INTO vectors (icao, seen, speed, heading, vertical) VALUES (" + "%i" % icao24 + ", datetime('now'), " + "%.0f" % velocity + ", " + "%.0f" % heading + ", " + "%.0f" % vert_spd + ")";
|
||||
|
||||
return retstr
|
||||
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user