Completely rewrote parser, everything is broken
This commit is contained in:
parent
0494eb5b18
commit
ba153e52ed
@ -167,7 +167,7 @@ int air_modes_slicer::work(int noutput_items,
|
||||
}
|
||||
if(zeroes) {continue;} //toss it
|
||||
|
||||
rx_packet.message_type = (rx_packet.data[0] >> 3) & 0x1F; //get the message type for the parser to conveniently use, and to make decisions on ECC methods
|
||||
rx_packet.message_type = (rx_packet.data[0] >> 3) & 0x1F; //get the message type to make decisions on ECC methods
|
||||
|
||||
if(rx_packet.type == Short_Packet && rx_packet.message_type != 11 && rx_packet.numlowconf > 0) {continue;}
|
||||
if(rx_packet.message_type == 11 && rx_packet.numlowconf >= 10) {continue;}
|
||||
@ -179,36 +179,11 @@ int air_modes_slicer::work(int noutput_items,
|
||||
//crc for the other short packets is usually nonzero, so they can't really be trusted that far
|
||||
if(rx_packet.crc && (rx_packet.message_type == 11 || rx_packet.message_type == 17)) {continue;}
|
||||
|
||||
//we no longer attempt to brute force error correct via syndrome. it really only gets you 1% additional returns,
|
||||
//at the expense of a lot of CPU time and complexity
|
||||
|
||||
//we'll replicate some data by sending the message type as the first field, followed by the first 8+24=32 bits of the packet, followed by
|
||||
//56 long packet data bits if applicable (zero-padded if not), followed by crc
|
||||
|
||||
d_payload.str("");
|
||||
d_payload << std::dec << std::setw(2) << std::setfill('0') << rx_packet.message_type << std::hex << " ";
|
||||
for(int m = 0; m < 4; m++) {
|
||||
for(int m = 0; m < 14; m++) {
|
||||
d_payload << std::setw(2) << std::setfill('0') << unsigned(rx_packet.data[m]);
|
||||
}
|
||||
d_payload << " ";
|
||||
if(packet_length == 112) {
|
||||
for(int m = 4; m < 11; m++) {
|
||||
d_payload << std::setw(2) << std::setfill('0') << unsigned(rx_packet.data[m]);
|
||||
}
|
||||
d_payload << " ";
|
||||
for(int m = 11; m < 14; m++) {
|
||||
d_payload << std::setw(2) << std::setfill('0') << unsigned(rx_packet.data[m]);
|
||||
}
|
||||
} else {
|
||||
for(int m = 4; m < 11; m++) {
|
||||
d_payload << std::setw(2) << std::setfill('0') << unsigned(0);
|
||||
}
|
||||
d_payload << " ";
|
||||
for(int m = 4; m < 7; m++) {
|
||||
d_payload << std::setw(2) << std::setfill('0') << unsigned(rx_packet.data[m]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
d_payload << " " << std::setw(6) << rx_packet.crc << " " << std::dec << rx_packet.reference_level
|
||||
<< " " << std::setprecision(10) << std::setw(10) << rx_packet.timestamp;
|
||||
gr_message_sptr msg = gr_make_message_from_string(std::string(d_payload.str()));
|
||||
|
@ -40,3 +40,8 @@ class CPRNoPositionError(ADSBError):
|
||||
|
||||
class CPRBoundaryStraddleError(CPRNoPositionError):
|
||||
pass
|
||||
|
||||
class FieldNotInPacket(ParserError):
|
||||
def __init__(self, item):
|
||||
self.item = item
|
||||
|
||||
|
@ -17,8 +17,7 @@
|
||||
# along with gr-air-modes; see the file COPYING. If not, write to
|
||||
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
#
|
||||
|
||||
#
|
||||
|
||||
import time, os, sys
|
||||
from string import split, join
|
||||
@ -27,6 +26,73 @@ import cpr
|
||||
import math
|
||||
from modes_exceptions import *
|
||||
|
||||
#this implements a packet class which can retrieve its own fields.
|
||||
class modes_data:
|
||||
def __init__(self, data):
|
||||
self.data = data
|
||||
#this depends on packet type so we initialize it here
|
||||
#there's probably a cleaner way to do it.
|
||||
self.parity_fields = {
|
||||
"ap": (33+(self.get_numbits()-56),24),
|
||||
"pi": (33+(self.get_numbits()-56),24)
|
||||
}
|
||||
|
||||
#bitfield definitions according to Mode S spec
|
||||
#(start bit, num bits)
|
||||
fields = { "df": (1,5), "vs": (6,1), "fs": (6,3), "cc": (7,1),
|
||||
"sl": (9,3), "ri": (14,4), "ac": (20,13), "dr": (9,5),
|
||||
"um": (14,6), "id": (20,13), "ca": (6,3), "aa": (9,24),
|
||||
"mv": (33,56), "me": (33,56), "mb": (33,56), "ke": (6,1),
|
||||
"nd": (7,4), "md": (11,80)
|
||||
}
|
||||
|
||||
#fields in each packet type (DF value)
|
||||
types = { 0: ["df", "vs", "cc", "sl", "ri", "ac", "ap"],
|
||||
4: ["df", "fs", "dr", "um", "ac", "ap"],
|
||||
5: ["df", "fs", "dr", "um", "id", "ap"],
|
||||
11: ["df", "ca", "aa", "pi"],
|
||||
16: ["df", "vs", "sl", "ri", "ac", "mv", "ap"],
|
||||
17: ["df", "ca", "aa", "me", "pi"],
|
||||
20: ["df", "fs", "dr", "um", "ac", "mb", "ap"],
|
||||
21: ["df", "fs", "dr", "um", "id", "mb", "ap"],
|
||||
24: ["df", "ke", "nd", "md", "ap"]
|
||||
}
|
||||
|
||||
#packets which are 112 bits long
|
||||
long_types = [16, 17, 20, 21, 24]
|
||||
|
||||
#get a particular field from the data
|
||||
def __getitem__(self, fieldname):
|
||||
if fieldname in modes_data.types[self.get_bits(modes_data.fields["df"])]: #verify it exists in this packet type
|
||||
if fieldname in self.parity_fields:
|
||||
return self.get_bits(self.parity_fields[fieldname])
|
||||
else:
|
||||
return self.get_bits(modes_data.fields[fieldname])
|
||||
else:
|
||||
raise FieldNotInPacket(fieldname)
|
||||
|
||||
#grab all the fields in the packet as a dict
|
||||
def get_fields(self):
|
||||
return {field: self[field] for field in modes_data.types[self["df"]]}
|
||||
|
||||
#tell me if i'm an extended squitter or a normal Mode S reply
|
||||
def is_long(self):
|
||||
#can't use packet type because we use is_long() to get items, and
|
||||
#this causes endless recursion
|
||||
#return self["df"] in modes_data.long_types
|
||||
return self.data > (1 << 56)
|
||||
|
||||
#how many bits are in the packet?
|
||||
def get_numbits(self):
|
||||
return 112 if self.is_long() else 56
|
||||
|
||||
#retrieve bits from data given the offset and number of bits.
|
||||
#the offset is both left-justified (LSB) and starts at 1, to
|
||||
#correspond to the Mode S spec. Blame them.
|
||||
def get_bits(self, arg):
|
||||
(offset, num) = arg
|
||||
return (self.data >> (self.get_numbits() - offset - num + 1)) & ((1 << num) - 1)
|
||||
|
||||
class modes_parse:
|
||||
def __init__(self, mypos):
|
||||
self.my_location = mypos
|
||||
@ -54,14 +120,14 @@ class modes_parse:
|
||||
return [fs, dr, um, altitude]
|
||||
|
||||
|
||||
|
||||
def parse5(self, shortdata):
|
||||
fs = shortdata >> 24 & 0x07 #flight status: 0 is airborne normal, 1 is ground normal, 2 is airborne alert, 3 is ground alert, 4 is alert SPI, 5 is normal SPI
|
||||
dr = shortdata >> 19 & 0x1F #downlink request: 0 means no req, bit 0 is Comm-B msg rdy bit, bit 1 is TCAS info msg rdy, bit 2 is Comm-B bcast #1 msg rdy, bit2+bit0 is Comm-B bcast #2 msg rdy,
|
||||
#bit2+bit1 is TCAS info and Comm-B bcast #1 msg rdy, bit2+bit1+bit0 is TCAS info and Comm-B bcast #2 msg rdy, 8-15 N/A, 16-31 req to send N-15 segments
|
||||
um = shortdata >> 13 & 0x3F #transponder status readouts, no decoding information available
|
||||
ident = shortdata & 0x1FFF
|
||||
|
||||
return [fs, dr, um]
|
||||
return [fs, dr, um, ident]
|
||||
|
||||
def parse11(self, shortdata, ecc):
|
||||
interrogator = ecc & 0x0F
|
||||
@ -222,3 +288,28 @@ class modes_parse:
|
||||
|
||||
return [velocity, heading, vert_spd]
|
||||
|
||||
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_commB(self, longdata): #bds1, bds2 == 0
|
||||
raise NoHandlerError
|
||||
|
||||
def parseMB_caps(self, longdata): #bds1 == 1, bds2 == 0
|
||||
#cfs, acs, bcs
|
||||
raise NoHandlerError
|
||||
|
||||
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
|
||||
|
@ -30,15 +30,15 @@ class modes_output_print(modes_parse.modes_parse):
|
||||
modes_parse.modes_parse.__init__(self, mypos)
|
||||
|
||||
def parse(self, message):
|
||||
[msgtype, shortdata, longdata, parity, ecc, reference, timestamp] = message.split()
|
||||
shortdata = long(shortdata, 16)
|
||||
longdata = long(longdata, 16)
|
||||
parity = long(parity, 16)
|
||||
[data, ecc, reference, timestamp] = message.split()
|
||||
|
||||
#TODO FIXME HALP
|
||||
data = modes_data(long(data, 16))
|
||||
ecc = long(ecc, 16)
|
||||
reference = float(reference)
|
||||
timestamp = float(timestamp)
|
||||
|
||||
msgtype = int(msgtype)
|
||||
msgtype = data["df"]
|
||||
|
||||
#TODO this is suspect
|
||||
if reference == 0.0:
|
||||
@ -49,15 +49,15 @@ class modes_output_print(modes_parse.modes_parse):
|
||||
|
||||
try:
|
||||
if msgtype == 0:
|
||||
output += self.print0(shortdata, ecc)
|
||||
output += self.print0(data, ecc)
|
||||
elif msgtype == 4:
|
||||
output += self.print4(shortdata, ecc)
|
||||
output += self.print4(data, ecc)
|
||||
elif msgtype == 5:
|
||||
output += self.print5(shortdata, ecc)
|
||||
output += self.print5(data, ecc)
|
||||
elif msgtype == 11:
|
||||
output += self.print11(shortdata, ecc)
|
||||
output += self.print11(data, ecc)
|
||||
elif msgtype == 17:
|
||||
output += self.print17(shortdata, longdata)
|
||||
output += self.print17(data)
|
||||
print output
|
||||
except NoHandlerError as e:
|
||||
output += "No handler for message type " + str(e.msgtype) + " from %x" % ecc
|
||||
@ -102,9 +102,9 @@ class modes_output_print(modes_parse.modes_parse):
|
||||
return retstr
|
||||
|
||||
def print5(self, shortdata, ecc):
|
||||
[fs, dr, um] = self.parse5(shortdata)
|
||||
[fs, dr, um, ident] = self.parse5(shortdata)
|
||||
|
||||
retstr = "Type 5 (short surveillance ident reply) from " + "%x" % ecc + " with ident " + str(shortdata & 0x1FFF)
|
||||
retstr = "Type 5 (short surveillance ident reply) from " + "%x" % ecc + " with ident " + str(ident)
|
||||
|
||||
if fs == 1:
|
||||
retstr = retstr + " (aircraft is on the ground)"
|
||||
|
Loading…
Reference in New Issue
Block a user