Completely rewrote parser, everything is broken

This commit is contained in:
Nick Foster 2012-06-21 09:42:58 -07:00
parent 0494eb5b18
commit ba153e52ed
4 changed files with 115 additions and 44 deletions

View File

@ -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,35 +179,10 @@ 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;

View File

@ -40,3 +40,8 @@ class CPRNoPositionError(ADSBError):
class CPRBoundaryStraddleError(CPRNoPositionError):
pass
class FieldNotInPacket(ParserError):
def __init__(self, item):
self.item = item

View File

@ -19,7 +19,6 @@
# Boston, MA 02110-1301, USA.
#
import time, os, sys
from string import split, join
from altitude import decode_alt
@ -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

View File

@ -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)"