From 33b04c292cb7ce1a3319c5e9ed6bdf70bce4f005 Mon Sep 17 00:00:00 2001 From: Nick Foster Date: Sun, 17 Oct 2010 19:45:19 -0700 Subject: [PATCH] Reorganized things quite a bit. Much cleaner output interface. Made a single registry of output plugins which gets populated on init with classes to output on a socket, print to screen, database, etc. Next step is to implement a SQLite database class. --- src/lib/air_modes_slicer.cc | 7 + src/python/cpr.py | 8 +- src/python/cpr.pyc | Bin 5836 -> 5836 bytes src/python/modes_parse.py | 254 ++++++++++++++++++------------------ src/python/modes_parse.pyc | Bin 5330 -> 5420 bytes src/python/modes_print.py | 207 ++++++++++++++--------------- src/python/modes_sbs1.py | 96 ++++++++++++++ src/python/uhd_modes.py | 225 ++++++++++++++++---------------- src/python/usrp_modes.py | 2 +- 9 files changed, 442 insertions(+), 357 deletions(-) create mode 100644 src/python/modes_sbs1.py diff --git a/src/lib/air_modes_slicer.cc b/src/lib/air_modes_slicer.cc index 18baf3d..c03d75d 100644 --- a/src/lib/air_modes_slicer.cc +++ b/src/lib/air_modes_slicer.cc @@ -145,8 +145,15 @@ int air_modes_slicer::work(int noutput_items, //the limitation on short packets means in practice a short packet has to be at least 6dB above the noise floor in order to be output. long packets can theoretically //be decoded at the 3dB SNR point. below that and the preamble detector won't fire. + + //in practice, this limitation causes you to see a HUGE number of type 11 packets which pass CRC through random luck. + //these packets necessarily have large numbers of low-confidence bits, so we toss them with an arbitrary limit of 10. + //that's a pretty dang low threshold so i don't think we'll drop many legit packets if(rx_packet.type == Short_Packet && rx_packet.message_type != 11 && rx_packet.numlowconf != 0) continue; + if(rx_packet.type == Short_Packet && rx_packet.message_type == 11 && rx_packet.numlowconf >= 10) continue; + + //if(rx_packet.numlowconf >= 24) continue; //don't even try, this is the maximum number of errors ECC could possibly correct //the above line should be part of ECC, and only checked if the message has parity errors diff --git a/src/python/cpr.py b/src/python/cpr.py index 3f2b892..838799e 100644 --- a/src/python/cpr.py +++ b/src/python/cpr.py @@ -6,11 +6,11 @@ import math, time latz = 15 nbits = 17 -#my_lat = 37.76225 #update these later! -#my_lon = -122.44254 +my_lat = 37.76225 #update these later! +my_lon = -122.44254 #ER -my_lat = 37.40889176297184 -my_lon = -122.07765340805054 +#my_lat = 37.40889176297184 +#my_lon = -122.07765340805054 def nz(ctype): diff --git a/src/python/cpr.pyc b/src/python/cpr.pyc index 9e746771c4acb1bf07d7d1a725c85320b79d39a2..9b1ed44d354cc0a95fa40f6cb44fd3e07116463a 100644 GIT binary patch delta 63 zcmX@3dq$W2;wN4%@7T=~+0XJTZYau__|VBA{r@Si$w6~AK0YTZ&B(^c#>UCa$pgg9 RoZOrooSd9&K-z*c6af345)}Xd delta 63 zcmX@3dq$W2;wN4%JLxGC+0XK?Ke25>*cK;;bOr_nw;wGVAD> 26 & 0x1) #ground sensor -- airborne when 0 - cc = bool(shortdata >> 25 & 0x1) #crosslink capability, binary - sl = shortdata >> 21 & 0x07 #operating sensitivity of onboard TCAS system. 0 means no TCAS sensitivity reported, 1-7 give TCAS sensitivity - ri = shortdata >> 15 & 0x0F #speed coding: 0 = no onboard TCAS, 1 = NA, 2 = TCAS w/inhib res, 3 = TCAS w/vert only, 4 = TCAS w/vert+horiz, 5-7 = NA, 8 = no max A/S avail, + vs = bool(shortdata >> 26 & 0x1) #ground sensor -- airborne when 0 + cc = bool(shortdata >> 25 & 0x1) #crosslink capability, binary + sl = shortdata >> 21 & 0x07 #operating sensitivity of onboard TCAS system. 0 means no TCAS sensitivity reported, 1-7 give TCAS sensitivity + ri = shortdata >> 15 & 0x0F #speed coding: 0 = no onboard TCAS, 1 = NA, 2 = TCAS w/inhib res, 3 = TCAS w/vert only, 4 = TCAS w/vert+horiz, 5-7 = NA, 8 = no max A/S avail, #9 = A/S <= 75kt, 10 = A/S (75-150]kt, 11 = (150-300]kt, 12 = (300-600]kt, 13 = (600-1200]kt, 14 = >1200kt, 15 = NA - altitude = decode_alt(shortdata & 0x1FFF, True) #bit 13 is set for type 0 + altitude = decode_alt(shortdata & 0x1FFF, True) #bit 13 is set for type 0 - return [vs, cc, sl, ri, altitude] + return [vs, cc, sl, ri, altitude] -def parse4(shortdata, parity, ecc): + def parse4(self, shortdata, parity, ecc): # shortdata = long(shortdata, 16) - 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, + 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 + um = shortdata >> 13 & 0x3F #transponder status readouts, no decoding information available - altitude = decode_alt(shortdata & 0x1FFF, True) + altitude = decode_alt(shortdata & 0x1FFF, True) - return [fs, dr, um, altitude] + return [fs, dr, um, altitude] -def parse5(shortdata, parity, ecc): + def parse5(self, shortdata, parity, ecc): # shortdata = long(shortdata, 16) - 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, + 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 + um = shortdata >> 13 & 0x3F #transponder status readouts, no decoding information available - return [fs, dr, um] + return [fs, dr, um] -def parse11(shortdata, parity, ecc): + def parse11(self, shortdata, parity, ecc): # shortdata = long(shortdata, 16) - interrogator = ecc & 0x0F + interrogator = ecc & 0x0F - ca = shortdata >> 13 & 0x3F #capability - icao24 = shortdata & 0xFFFFFF + ca = shortdata >> 13 & 0x3F #capability + icao24 = shortdata & 0xFFFFFF + + return [icao24, interrogator, ca] - return [icao24, interrogator, ca] - -#def parse17(shortdata, longdata, parity, ecc): +#def parse17(self, shortdata, longdata, parity, ecc): # shortdata = long(shortdata, 16) # longdata = long(longdata, 16) # parity = long(parity, 16) @@ -101,147 +102,140 @@ def parse11(shortdata, parity, ecc): # return retstr -def parseBDS08(shortdata, longdata, parity, ecc): - icao24 = shortdata & 0xFFFFFF + def parseBDS08(self, shortdata, longdata, parity, ecc): + icao24 = shortdata & 0xFFFFFF - msg = "" - for i in range(0, 8): - msg += charmap( longdata >> (42-6*i) & 0x3F) + msg = "" + for i in range(0, 8): + msg += self.charmap( longdata >> (42-6*i) & 0x3F) #retstr = "Type 17 subtype 04 (ident) from " + "%x" % icao24 + " with data " + msg - return msg + return msg -def charmap(d): - if d > 0 and d < 27: - retval = chr(ord("A")+d-1) - elif d == 32: - retval = " " - elif d > 47 and d < 58: - retval = chr(ord("0")+d-48) - else: - retval = " " - - return retval + def charmap(self, d): + if d > 0 and d < 27: + retval = chr(ord("A")+d-1) + elif d == 32: + retval = " " + elif d > 47 and d < 58: + retval = chr(ord("0")+d-48) + else: + retval = " " + return retval #lkplist is the last known position, for emitter-centered decoding. evenlist and oddlist are the last #received encoded position data for each reporting type. all dictionaries indexed by ICAO number. -lkplist = {} -evenlist = {} -oddlist = {} -evenlist_ground = {} -oddlist_ground = {} + _lkplist = {} + _evenlist = {} + _oddlist = {} + _evenlist_ground = {} + _oddlist_ground = {} #the above dictionaries are all in the format [lat, lon, time]. -def parseBDS05(shortdata, longdata, parity, ecc): - icao24 = shortdata & 0xFFFFFF + def parseBDS05(self, shortdata, longdata, parity, ecc): + icao24 = shortdata & 0xFFFFFF - encoded_lon = longdata & 0x1FFFF - encoded_lat = (longdata >> 17) & 0x1FFFF - cpr_format = (longdata >> 34) & 1 + encoded_lon = longdata & 0x1FFFF + encoded_lat = (longdata >> 17) & 0x1FFFF + cpr_format = (longdata >> 34) & 1 - enc_alt = (longdata >> 36) & 0x0FFF + enc_alt = (longdata >> 36) & 0x0FFF - altitude = decode_alt(enc_alt, False) + altitude = decode_alt(enc_alt, False) - [decoded_lat, decoded_lon, rnge, bearing] = cpr_decode(icao24, encoded_lat, encoded_lon, cpr_format, evenlist, oddlist, lkplist, 0, longdata) + [decoded_lat, decoded_lon, rnge, bearing] = cpr_decode(icao24, encoded_lat, encoded_lon, cpr_format, self._evenlist, self._oddlist, self._lkplist, 0, longdata) - return [altitude, decoded_lat, decoded_lon, rnge, bearing] + return [altitude, decoded_lat, decoded_lon, rnge, bearing] #welp turns out it looks like there's only 17 bits in the BDS0,6 ground packet after all. fuck. -def parseBDS06(shortdata, longdata, parity, ecc): - icao24 = shortdata & 0xFFFFFF + def parseBDS06(self, shortdata, longdata, parity, ecc): + icao24 = shortdata & 0xFFFFFF - encoded_lon = longdata & 0x1FFFF - encoded_lat = (longdata >> 17) & 0x1FFFF - cpr_format = (longdata >> 34) & 1 + encoded_lon = longdata & 0x1FFFF + encoded_lat = (longdata >> 17) & 0x1FFFF + cpr_format = (longdata >> 34) & 1 # enc_alt = (longdata >> 36) & 0x0FFF - altitude = 0 + altitude = 0 - [decoded_lat, decoded_lon, rnge, bearing] = cpr_decode(icao24, encoded_lat, encoded_lon, cpr_format, evenlist_ground, oddlist_ground, lkplist, 1, longdata) + [decoded_lat, decoded_lon, rnge, bearing] = cpr_decode(icao24, encoded_lat, encoded_lon, cpr_format, self._evenlist_ground, self._oddlist_ground, self._lkplist, 1, longdata) - return [altitude, decoded_lat, decoded_lon, rnge, bearing] + return [altitude, decoded_lat, decoded_lon, rnge, bearing] + def parseBDS09_0(self, shortdata, longdata, parity, ecc): + icao24 = shortdata & 0xFFFFFF + vert_spd = ((longdata >> 6) & 0x1FF) * 32 + ud = bool((longdata >> 15) & 1) + if ud: + vert_spd = 0 - vert_spd + turn_rate = (longdata >> 16) & 0x3F + turn_rate = turn_rate * 15/62 + rl = bool((longdata >> 22) & 1) + if rl: + turn_rate = 0 - turn_rate + ns_vel = (longdata >> 23) & 0x7FF - 1 + ns = bool((longdata >> 34) & 1) + ew_vel = (longdata >> 35) & 0x7FF - 1 + ew = bool((longdata >> 46) & 1) + subtype = (longdata >> 48) & 0x07 -def parseBDS09_0(shortdata, longdata, parity, ecc): - icao24 = shortdata & 0xFFFFFF - vert_spd = ((longdata >> 6) & 0x1FF) * 32 - ud = bool((longdata >> 15) & 1) - if ud: - vert_spd = 0 - vert_spd - turn_rate = (longdata >> 16) & 0x3F - turn_rate = turn_rate * 15/62 - rl = bool((longdata >> 22) & 1) - if rl: - turn_rate = 0 - turn_rate - ns_vel = (longdata >> 23) & 0x7FF - 1 - ns = bool((longdata >> 34) & 1) - ew_vel = (longdata >> 35) & 0x7FF - 1 - ew = bool((longdata >> 46) & 1) - subtype = (longdata >> 48) & 0x07 - - velocity = math.hypot(ns_vel, ew_vel) - if ew: - ew_vel = 0 - ew_vel - if ns: - ns_vel = 0 - ns_vel - heading = math.atan2(ew_vel, ns_vel) * (180.0 / math.pi) - if heading < 0: - heading += 360 + velocity = math.hypot(ns_vel, ew_vel) + if ew: + ew_vel = 0 - ew_vel + if ns: + ns_vel = 0 - ns_vel + heading = math.atan2(ew_vel, ns_vel) * (180.0 / math.pi) + if heading < 0: + heading += 360 #retstr = "Type 17 subtype 09-0 (track report) from " + "%x" % icao24 + " with velocity " + "%.0f" % velocity + "kt heading " + "%.0f" % heading + " VS " + "%.0f" % vert_spd - return [velocity, heading, vert_spd] + return [velocity, heading, vert_spd] -def parseBDS09_1(shortdata, longdata, parity, ecc): - icao24 = shortdata & 0xFFFFFF - alt_geo_diff = longdata & 0x7F - 1 - above_below = bool((longdata >> 7) & 1) - if above_below: - alt_geo_diff = 0 - alt_geo_diff; - vert_spd = float((longdata >> 10) & 0x1FF - 1) - ud = bool((longdata >> 19) & 1) - if ud: - vert_spd = 0 - vert_spd - vert_src = bool((longdata >> 20) & 1) - ns_vel = float((longdata >> 21) & 0x3FF - 1) - ns = bool((longdata >> 31) & 1) - ew_vel = float((longdata >> 32) & 0x3FF - 1) - ew = bool((longdata >> 42) & 1) - subtype = (longdata >> 48) & 0x07 + def parseBDS09_1(self, shortdata, longdata, parity, ecc): + icao24 = shortdata & 0xFFFFFF + alt_geo_diff = longdata & 0x7F - 1 + above_below = bool((longdata >> 7) & 1) + if above_below: + alt_geo_diff = 0 - alt_geo_diff; + vert_spd = float((longdata >> 10) & 0x1FF - 1) + ud = bool((longdata >> 19) & 1) + if ud: + vert_spd = 0 - vert_spd + vert_src = bool((longdata >> 20) & 1) + ns_vel = float((longdata >> 21) & 0x3FF - 1) + ns = bool((longdata >> 31) & 1) + ew_vel = float((longdata >> 32) & 0x3FF - 1) + ew = bool((longdata >> 42) & 1) + subtype = (longdata >> 48) & 0x07 - if subtype == 0x02: - ns_vel *= 4 - ew_vel *= 4 + if subtype == 0x02: + ns_vel *= 4 + ew_vel *= 4 - vert_spd *= 64 - alt_geo_diff *= 25 + vert_spd *= 64 + alt_geo_diff *= 25 - velocity = math.hypot(ns_vel, ew_vel) - if ew: - ew_vel = 0 - ew_vel + velocity = math.hypot(ns_vel, ew_vel) + if ew: + ew_vel = 0 - ew_vel - if ns_vel == 0: - heading = 0 - else: - heading = math.atan(float(ew_vel) / float(ns_vel)) * (180.0 / math.pi) - if ns: - heading = 180 - heading - if heading < 0: - heading += 360 - - #retstr = "Type 17 subtype 09-1 (track report) from " + "%x" % icao24 + " with velocity " + "%.0f" % velocity + "kt heading " + "%.0f" % heading + " VS " + "%.0f" % vert_spd - - return [velocity, heading, vert_spd] - -def parse20(shortdata, longdata, parity, ecc): - return "Message 20 not yet implemented" + if ns_vel == 0: + heading = 0 + else: + heading = math.atan(float(ew_vel) / float(ns_vel)) * (180.0 / math.pi) + if ns: + heading = 180 - heading + if heading < 0: + heading += 360 + #retstr = "Type 17 subtype 09-1 (track report) from " + "%x" % icao24 + " with velocity " + "%.0f" % velocity + "kt heading " + "%.0f" % heading + " VS " + "%.0f" % vert_spd + return [velocity, heading, vert_spd] diff --git a/src/python/modes_parse.pyc b/src/python/modes_parse.pyc index d786a0f22eff9423645cf232b2179d1abfb57c88..59623ce9eb4504f8c6229295520d7ef21dff402c 100644 GIT binary patch literal 5420 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 diff --git a/src/python/modes_print.py b/src/python/modes_print.py index 7d74c13..680f8f2 100644 --- a/src/python/modes_print.py +++ b/src/python/modes_print.py @@ -1,142 +1,135 @@ #!/usr/bin/env python import time, os, sys from string import split, join -from modes_parse import * +import modes_parse +import math -def modes_print(message): +class modes_output_print(modes_parse.modes_parse): + def parse(self, message): + [msgtype, shortdata, longdata, parity, ecc, reference] = message.split() - #a mode S parser for all message types. first, split the input into data fields - [msgtype, shortdata, longdata, parity, ecc, reference] = message.split() + shortdata = long(shortdata, 16) + longdata = long(longdata, 16) + parity = long(parity, 16) + ecc = long(ecc, 16) + reference = float(reference) - shortdata = long(shortdata, 16) - longdata = long(longdata, 16) - parity = long(parity, 16) - ecc = long(ecc, 16) - reference = float(reference) + msgtype = int(msgtype) - msgtype = int(msgtype) + output = str("") - output = str("") + if msgtype == 0: + output = self.print0(shortdata, parity, ecc) + elif msgtype == 4: + output = self.print4(shortdata, parity, ecc) + elif msgtype == 5: + output = self.print5(shortdata, parity, ecc) + elif msgtype == 11: + output = self.print11(shortdata, parity, ecc) + elif msgtype == 17: + output = self.print17(shortdata, longdata, parity, ecc) + else: + output = "No handler for message type " + str(msgtype) + " from " + str(ecc) - if msgtype == 0: - output = print0(shortdata, parity, ecc) - elif msgtype == 4: - output = print4(shortdata, parity, ecc) - elif msgtype == 5: - output = print5(shortdata, parity, ecc) - elif msgtype == 11: - output = print11(shortdata, parity, ecc) - elif msgtype == 17: - output = print17(shortdata, longdata, parity, ecc) - elif msgtype == 20: - output = parse20(shortdata, longdata, parity, ecc) - else: - output = "No handler for message type " + str(msgtype) + " from " + str(ecc) + output = "(%.0f) " % (10.0*math.log10(float(reference))) + output - output = "(%.0f) " % (10.0*math.log10(float(reference))) + output + print output - return output - -def print0(shortdata, parity, ecc): - [vs, cc, sl, ri, altitude] = parse0(shortdata, parity, ecc) + def print0(self, shortdata, parity, ecc): + [vs, cc, sl, ri, altitude] = self.parse0(shortdata, parity, ecc) - retstr = "Type 0 (short A-A surveillance) from " + "%x" % ecc + " at " + str(altitude) + "ft" - # the ri values below 9 are used for other things. might want to print those someday. - if ri == 9: - retstr = retstr + " (speed <75kt)" - elif ri > 9: - retstr = retstr + " (speed " + str(75 * (1 << (ri-10))) + "-" + str(75 * (1 << (ri-9))) + "kt)" + retstr = "Type 0 (short A-A surveillance) from " + "%x" % ecc + " at " + str(altitude) + "ft" + # the ri values below 9 are used for other things. might want to print those someday. + if ri == 9: + retstr = retstr + " (speed <75kt)" + elif ri > 9: + retstr = retstr + " (speed " + str(75 * (1 << (ri-10))) + "-" + str(75 * (1 << (ri-9))) + "kt)" - if vs is True: - retstr = retstr + " (aircraft is on the ground)" + if vs is True: + retstr = retstr + " (aircraft is on the ground)" - return retstr + return retstr -def print4(shortdata, parity, ecc): + def print4(self, shortdata, parity, ecc): - [fs, dr, um, altitude] = parse4(shortdata, parity, ecc) + [fs, dr, um, altitude] = self.parse4(shortdata, parity, ecc) - retstr = "Type 4 (short surveillance altitude reply) from " + "%x" % ecc + " at " + str(altitude) + "ft" + retstr = "Type 4 (short surveillance altitude reply) from " + "%x" % ecc + " at " + str(altitude) + "ft" - if fs == 1: - retstr = retstr + " (aircraft is on the ground)" - elif fs == 2: - retstr = retstr + " (AIRBORNE ALERT)" - elif fs == 3: - retstr = retstr + " (GROUND ALERT)" - elif fs == 4: - retstr = retstr + " (SPI ALERT)" - elif fs == 5: - retstr = retstr + " (SPI)" + if fs == 1: + retstr = retstr + " (aircraft is on the ground)" + elif fs == 2: + retstr = retstr + " (AIRBORNE ALERT)" + elif fs == 3: + retstr = retstr + " (GROUND ALERT)" + elif fs == 4: + retstr = retstr + " (SPI ALERT)" + elif fs == 5: + retstr = retstr + " (SPI)" - return retstr + return retstr -def print5(shortdata, parity, ecc): - [fs, dr, um] = parse5(shortdata, parity, ecc) + def print5(self, shortdata, parity, ecc): + [fs, dr, um] = self.parse5(shortdata, parity, ecc) - 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(shortdata & 0x1FFF) - if fs == 1: - retstr = retstr + " (aircraft is on the ground)" - elif fs == 2: - retstr = retstr + " (AIRBORNE ALERT)" - elif fs == 3: - retstr = retstr + " (GROUND ALERT)" - elif fs == 4: - retstr = retstr + " (SPI ALERT)" - elif fs == 5: - retstr = retstr + " (SPI)" + if fs == 1: + retstr = retstr + " (aircraft is on the ground)" + elif fs == 2: + retstr = retstr + " (AIRBORNE ALERT)" + elif fs == 3: + retstr = retstr + " (GROUND ALERT)" + elif fs == 4: + retstr = retstr + " (SPI ALERT)" + elif fs == 5: + retstr = retstr + " (SPI)" - return retstr + return retstr -def print11(shortdata, parity, ecc): - [icao24, interrogator, ca] = parse11(shortdata, parity, ecc) + def print11(self, shortdata, parity, ecc): + [icao24, interrogator, ca] = self.parse11(shortdata, parity, ecc) - retstr = "Type 11 (all call reply) from " + "%x" % icao24 + " in reply to interrogator " + str(interrogator) - return retstr + retstr = "Type 11 (all call reply) from " + "%x" % icao24 + " in reply to interrogator " + str(interrogator) + return retstr -def print17(shortdata, longdata, parity, ecc): - icao24 = shortdata & 0xFFFFFF - subtype = (longdata >> 51) & 0x1F; + def print17(self, shortdata, longdata, parity, ecc): + icao24 = shortdata & 0xFFFFFF + subtype = (longdata >> 51) & 0x1F; - if subtype == 4: - msg = parseBDS08(shortdata, longdata, parity, ecc) - retstr = "Type 17 subtype 04 (ident) from " + "%x" % icao24 + " with data " + msg + if subtype == 4: + msg = self.parseBDS08(shortdata, longdata, parity, ecc) + retstr = "Type 17 subtype 04 (ident) from " + "%x" % icao24 + " with data " + msg - elif subtype >= 5 and subtype <= 8: - [altitude, decoded_lat, decoded_lon, rnge, bearing] = parseBDS06(shortdata, longdata, parity, ecc) - if decoded_lat==0: #no unambiguously valid position available - retstr = "" - else: - #retstr = "INSERT INTO plane_positions (icao, seen, alt, lat, lon) VALUES ('" + "%x" % icao24 + "', now(), " + str(altitude) + ", " + "%.6f" % decoded_lat + ", " + "%.6f" % decoded_lon + ")" - retstr = "Type 17 subtype 06 (surface report) from " + "%x" % icao24 + " at (" + "%.6f" % decoded_lat + ", " + "%.6f" % decoded_lon + ") (" + "%.2f" % rnge + " @ " + "%.0f" % bearing + ")" + elif subtype >= 5 and subtype <= 8: + [altitude, decoded_lat, decoded_lon, rnge, bearing] = self.parseBDS06(shortdata, longdata, parity, ecc) + if decoded_lat==0: #no unambiguously valid position available + retstr = "" + else: + retstr = "Type 17 subtype 06 (surface report) from " + "%x" % icao24 + " at (" + "%.6f" % decoded_lat + ", " + "%.6f" % decoded_lon + ") (" + "%.2f" % rnge + " @ " + "%.0f" % bearing + ")" - elif subtype >= 9 and subtype <= 18: - [altitude, decoded_lat, decoded_lon, rnge, bearing] = parseBDS05(shortdata, longdata, parity, ecc) + elif subtype >= 9 and subtype <= 18: + [altitude, decoded_lat, decoded_lon, rnge, bearing] = self.parseBDS05(shortdata, longdata, parity, ecc) - retstr = "Type 17 subtype 05 (position report) from " + "%x" % icao24 + " at (" + "%.6f" % decoded_lat + ", " + "%.6f" % decoded_lon + ") (" + "%.2f" % rnge + " @ " + "%.0f" % bearing + ") at " + str(altitude) + "ft" + retstr = "Type 17 subtype 05 (position report) from " + "%x" % icao24 + " at (" + "%.6f" % decoded_lat + ", " + "%.6f" % decoded_lon + ") (" + "%.2f" % rnge + " @ " + "%.0f" % bearing + ") at " + str(altitude) + "ft" -# this is a trigger to capture the bizarre BDS0,5 squitters you keep seeing on the map with latitudes all over the place -# if icao24 == 0xa1ede9: -# print "Buggy squitter with shortdata %s longdata %s parity %s ecc %s" % (str(shortdata), str(longdata), str(parity), str(ecc),) - - elif subtype == 19: - subsubtype = (longdata >> 48) & 0x07 - if subsubtype == 0: - [velocity, heading, vert_spd] = parseBDS09_0(shortdata, longdata, parity, ecc) - retstr = "Type 17 subtype 09-0 (track report) from " + "%x" % icao24 + " with velocity " + "%.0f" % velocity + "kt heading " + "%.0f" % heading + " VS " + "%.0f" % vert_spd - - elif subsubtype == 1: - [velocity, heading, vert_spd] = parseBDS09_1(shortdata, longdata, parity, ecc) - retstr = "Type 17 subtype 09-1 (track report) from " + "%x" % icao24 + " with velocity " + "%.0f" % velocity + "kt heading " + "%.0f" % heading + " VS " + "%.0f" % vert_spd - - else: - retstr = "BDS09 subtype " + str(subsubtype) + " not implemented" - else: - retstr = "Type 17, subtype " + str(subtype) + " not implemented" - - return retstr +# this is a trigger to capture the bizarre BDS0,5 squitters you keep seeing on the map with latitudes all over the place +# if icao24 == 0xa1ede9: +# print "Buggy squitter with shortdata %s longdata %s parity %s ecc %s" % (str(shortdata), str(longdata), str(parity), str(ecc),) + elif subtype == 19: + subsubtype = (longdata >> 48) & 0x07 + if subsubtype == 0: + [velocity, heading, vert_spd] = self.parseBDS09_0(shortdata, longdata, parity, ecc) + retstr = "Type 17 subtype 09-0 (track report) from " + "%x" % icao24 + " with velocity " + "%.0f" % velocity + "kt heading " + "%.0f" % heading + " VS " + "%.0f" % vert_spd + elif subsubtype == 1: + [velocity, heading, vert_spd] = self.parseBDS09_1(shortdata, longdata, parity, ecc) + retstr = "Type 17 subtype 09-1 (track report) from " + "%x" % icao24 + " with velocity " + "%.0f" % velocity + "kt heading " + "%.0f" % heading + " VS " + "%.0f" % vert_spd + else: + retstr = "BDS09 subtype " + str(subsubtype) + " not implemented" + else: + retstr = "Type 17, subtype " + str(subtype) + " not implemented" + return retstr diff --git a/src/python/modes_sbs1.py b/src/python/modes_sbs1.py new file mode 100644 index 0000000..00deb06 --- /dev/null +++ b/src/python/modes_sbs1.py @@ -0,0 +1,96 @@ +import time, os, sys, socket +from string import split, join +import modes_parse +from datetime import * + +class modes_output_sbs1(modes_parse.modes_parse): + def __init__(self): + self._s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self._s.bind(('', 30003)) + self._s.listen(1) + self._s.setblocking(0) #nonblocking + self._conns = [] #list of active connections + + def output(self, msg): + sbs1_msg = self.parse(msg) + if sbs1_msg is not None: + for conn in self._conns[:]: #iterate over a copy of the list + try: + conn.send(sbs1_msg) + except socket.error: + self._conns.remove(conn) + print "Connections: ", len(self._conns) + + def add_pending_conns(self): + try: + conn, addr = self._s.accept() + self._conns.append(conn) + print "Connections: ", len(self._conns) + except socket.error: + pass + + def __del__(self): + self._s.close() + + def parse(self, message): + #assembles a SBS-1-style output string from the received message + #this version ignores anything that isn't Type 17 for now, because we just don't care + + [msgtype, shortdata, longdata, parity, ecc, reference] = message.split() + + shortdata = long(shortdata, 16) + longdata = long(longdata, 16) + parity = long(parity, 16) + ecc = long(ecc, 16) +# reference = float(reference) + + msgtype = int(msgtype) + + outmsg = None + + if msgtype == 17: + outmsg = self.pp17(shortdata, longdata, parity, ecc) + + return outmsg + + def pp17(self, shortdata, longdata, parity, ecc): + icao24 = shortdata & 0xFFFFFF + subtype = (longdata >> 51) & 0x1F + + retstr = None + timenow = datetime.now() + datestr = timenow.strftime("%Y/%m/%d") + timestr = timenow.strftime("%H:%M:%S.000") #we'll get better timestamps later, hopefully with actual VRT time in them + + if subtype == 4: + msg = self.parseBDS08(shortdata, longdata, parity, ecc) + retstr = "MSG,1,0,0,%X,0,%s,%s,%s,%s,%s,,,,,,,,,,,\n" % (icao24, datestr, timestr, datestr, timestr, msg) + + elif subtype >= 5 and subtype <= 8: + [altitude, decoded_lat, decoded_lon, rnge, bearing] = self.parseBDS06(shortdata, longdata, parity, ecc) + if decoded_lat is None: #no unambiguously valid position available + retstr = None + else: + retstr = "MSG,3,0,0,%X,0,%s,%s,%s,%s,,%i,,,%.5f,%.5f,,,,0,0,0\n" % (icao24, datestr, timestr, datestr, timestr, altitude, decoded_lat, 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, parity, ecc) + if decoded_lat is None: #no unambiguously valid position available + retstr = None + else: + retstr = "MSG,3,0,0,%X,0,%s,%s,%s,%s,,%i,,,%.5f,%.5f,,,,0,0,0\n" % (icao24, datestr, timestr, datestr, timestr, altitude, decoded_lat, decoded_lon) + + elif subtype == 19: + subsubtype = (longdata >> 48) & 0x07 + if subsubtype == 0: + [velocity, heading, vert_spd] = self.parseBDS09_0(shortdata, longdata, parity, ecc) + retstr = "MSG,4,0,0,%X,0,%s,%s,%s,%s,,,%.1f,%.1f,,,%i,,,,,\n" % (icao24, datestr, timestr, datestr, timestr, velocity, heading, vert_spd) + + elif subsubtype == 1: + [velocity, heading, vert_spd] = self.parseBDS09_1(shortdata, longdata, parity, ecc) + retstr = "MSG,4,0,0,%X,0,%s,%s,%s,%s,,,%.1f,%.1f,,,%i,,,,,\n" % (icao24, datestr, timestr, datestr, timestr, velocity, heading, vert_spd) + + #else: + #print "debug (modes_sbs1): unknown subtype %i with data %x %x %x\n" % (subtype, shortdata, longdata, parity,) + + return retstr diff --git a/src/python/uhd_modes.py b/src/python/uhd_modes.py index 966af10..0d7f104 100755 --- a/src/python/uhd_modes.py +++ b/src/python/uhd_modes.py @@ -7,11 +7,10 @@ from optparse import OptionParser import time, os, sys from string import split, join from usrpm import usrp_dbid -from modes_print import modes_print +from modes_print import modes_output_print from modes_sql import modes_sql +from modes_sbs1 import modes_output_sbs1 import gnuradio.gr.gr_threading as _threading -import MySQLdb - class top_block_runner(_threading.Thread): def __init__(self, tb): @@ -26,144 +25,140 @@ class top_block_runner(_threading.Thread): self.done = True -""" - -The following are optional command line parameters: - --R SUBDEV Daughter board specification, defaults to first found --f FREQ USRP receive frequency (1090 MHz Default) --g GAIN Daughterboard gain setting. Defaults to mid-range. --r RATE USRP sample rate --t THRESH Receiver valid pulse threshold --a Output all frames. Defaults only output frames - -Once the program is running, ctrl-break (Ctrl-C) stops operation. -""" - class adsb_rx_block (gr.top_block): - def __init__(self, options, args, queue): - gr.top_block.__init__(self) + def __init__(self, options, args, queue): + gr.top_block.__init__(self) - self.options = options - self.args = args + self.options = options + self.args = args - if options.filename is None: - self.u = uhd.simple_source("", uhd.io_type_t.COMPLEX_FLOAT32) + if options.filename is None: + self.u = uhd.simple_source("", uhd.io_type_t.COMPLEX_FLOAT32) - if(options.rx_subdev_spec is None): - options.rx_subdev_spec = "" - self.u.set_subdev_spec(options.rx_subdev_spec) + if(options.rx_subdev_spec is None): + options.rx_subdev_spec = "" + self.u.set_subdev_spec(options.rx_subdev_spec) - rate = options.rate - self.u.set_samp_rate(rate) - rate = int(self.u.get_samp_rate()) #retrieve actual + rate = options.rate + self.u.set_samp_rate(rate) + rate = int(self.u.get_samp_rate()) #retrieve actual - if options.gain is None: #set to halfway - g = self.u.get_gain_range() - options.gain = (g[0]+g[1]) / 2.0 + if options.gain is None: #set to halfway + g = self.u.get_gain_range() + options.gain = (g.min+g.max) / 2.0 - if not(self.tune(options.freq)): - print "Failed to set initial frequency" + if not(self.tune(options.freq)): + print "Failed to set initial frequency" - print "Setting gain to %i" % (options.gain,) - self.u.set_gain(options.gain) -# self.subdev.set_bw(self.options.bandwidth) #only for DBSRX + print "Setting gain to %i" % (options.gain,) + self.u.set_gain(options.gain) - else: - rate = options.rate - self.u = gr.file_source(gr.sizeof_gr_complex, options.filename) + else: + rate = options.rate + self.u = gr.file_source(gr.sizeof_gr_complex, options.filename) - print "Rate is %i" % (rate,) - print "Gain is %i" % (self.u.get_gain(),) - pass_all = 0 - if options.output_all : - pass_all = 1 + print "Rate is %i" % (rate,) + print "Gain is %i" % (self.u.get_gain(),) + pass_all = 0 + if options.output_all : + pass_all = 1 - self.demod = gr.complex_to_mag() - self.avg = gr.moving_average_ff(100, 1.0/100, 400); - self.preamble = air.modes_preamble(rate, options.threshold) - self.framer = air.modes_framer(rate) - self.slicer = air.modes_slicer(rate, queue) + self.demod = gr.complex_to_mag() + self.avg = gr.moving_average_ff(100, 1.0/100, 400); + self.preamble = air.modes_preamble(rate, options.threshold) + self.framer = air.modes_framer(rate) + self.slicer = air.modes_slicer(rate, queue) -# if options.rate < 16: - #there's a really nasty spur at 1088 caused by a multiple of the USRP xtal. if you use a decimation of 16, it gets filtered out by the CIC. if not, it really fucks with you unless you filter it out. -# filter_coeffs = gr.firdes.band_reject(1.0, rate, 1.7e6, 2.3e6, 0.5e6, gr.firdes.WIN_HAMMING) -# self.filt = gr.fir_filter_ccf(1, filter_coeffs) -# self.connect(self.u, self.filt) -# else: - self.filt = self.u - - self.connect(self.filt, self.demod) - self.connect(self.demod, self.avg) - self.connect(self.demod, (self.preamble, 0)) - self.connect(self.avg, (self.preamble, 1)) - self.connect(self.demod, (self.framer, 0)) - self.connect(self.preamble, (self.framer, 1)) - self.connect(self.demod, (self.slicer, 0)) - self.connect(self.framer, (self.slicer, 1)) - - def tune(self, freq): - result = self.u.set_center_freq(freq) - return result + self.connect(self.u, self.demod) + self.connect(self.demod, self.avg) + self.connect(self.demod, (self.preamble, 0)) + self.connect(self.avg, (self.preamble, 1)) + self.connect(self.demod, (self.framer, 0)) + self.connect(self.preamble, (self.framer, 1)) + self.connect(self.demod, (self.slicer, 0)) + self.connect(self.framer, (self.slicer, 1)) + def tune(self, freq): + result = self.u.set_center_freq(freq) + return result + +def post_to_sql(db, query): + if query is not None: + c = db.cursor() + c.execute(query) if __name__ == '__main__': - usage = "%prog: [options] output filename" - parser = OptionParser(option_class=eng_option, usage=usage) - parser.add_option("-R", "--rx-subdev-spec", type="subdev", - help="select USRP Rx side A or B", metavar="SUBDEV") - parser.add_option("-f", "--freq", type="eng_float", default=1090e6, + usage = "%prog: [options] output filename" + parser = OptionParser(option_class=eng_option, usage=usage) + parser.add_option("-R", "--rx-subdev-spec", type="string", + help="select USRP Rx side A or B", metavar="SUBDEV") + parser.add_option("-f", "--freq", type="eng_float", default=1090e6, help="set receive frequency in Hz [default=%default]", metavar="FREQ") - parser.add_option("-g", "--gain", type="int", default=None, + parser.add_option("-g", "--gain", type="int", default=None, help="set RF gain", metavar="dB") - parser.add_option("-r", "--rate", type="int", default=4000000, + parser.add_option("-r", "--rate", type="int", default=4000000, help="set ADC sample rate [default=%default]") - parser.add_option("-T", "--threshold", type="eng_float", default=3.0, + parser.add_option("-T", "--threshold", type="eng_float", default=3.0, help="set pulse detection threshold above noise in dB [default=%default]") - parser.add_option("-a","--output-all", action="store_true", default=False, + parser.add_option("-a","--output-all", action="store_true", default=False, help="output all frames") - parser.add_option("-b","--bandwidth", type="eng_float", default=5e6, - help="set DBSRX front-end bandwidth in Hz [default=5e6]") - parser.add_option("-F","--filename", type="string", default=None, - help="read data from file instead of USRP") - parser.add_option("-D","--database", action="store_true", default=False, - help="send to database instead of printing to screen") - (options, args) = parser.parse_args() -# if len(args) != 1: -# parser.print_help() -# sys.exit(1) + parser.add_option("-b","--bandwidth", type="eng_float", default=5e6, + help="set DBSRX baseband bandwidth in Hz [default=%default]") + parser.add_option("-F","--filename", type="string", default=None, + help="read data from file instead of USRP") + parser.add_option("-D","--database", action="store_true", default=False, + help="send to database instead of printing to screen") + parser.add_option("-P","--sbs1", action="store_true", default=False, + help="open an SBS-1-compatible server on port 30003") + parser.add_option("-n","--no-print", action="store_true", default=False, + help="disable printing decoded packets to stdout") + (options, args) = parser.parse_args() -# filename = args[0] - queue = gr.msg_queue() + queue = gr.msg_queue() + + outputs = [] #registry of plugin output functions + updates = [] #registry of plugin update functions - if options.database is True: - db = MySQLdb.connect(host="localhost", user="planes", passwd="planes", db="planes") + if options.database is True: + import pysqlite3 + #db = pysqlite3.connect(:memory:) + #here we have to initialize the database with the correct tables and relations + + if options.sbs1 is True: + sbs1port = modes_output_sbs1() + outputs.append(sbs1port.output) + updates.append(sbs1port.add_pending_conns) + + if options.no_print is not True: + outputs.append(modes_output_print().parse) - fg = adsb_rx_block(options, args, queue) - runner = top_block_runner(fg) + fg = adsb_rx_block(options, args, queue) + runner = top_block_runner(fg) - while 1: - try: - if queue.empty_p() == 0 : - while queue.empty_p() == 0 : - msg = queue.delete_head() #blocking read - if options.database is False: - print modes_print(msg.to_string()) - else: - query = modes_sql(msg.to_string()) - if query is not None: - c = db.cursor() - c.execute(query) + while 1: + try: + #the update registry is really for the SBS1 plugin -- we're looking for new TCP connections. + #i think we have to do this here rather than in the output handler because otherwise connections will stack up + #until the next output + for update in updates: + update() + + #main message handler + if queue.empty_p() == 0 : + while queue.empty_p() == 0 : + msg = queue.delete_head() #blocking read - elif runner.done: - break - else: - time.sleep(0.1) + for out in outputs: + out(msg.to_string()) - except KeyboardInterrupt: - fg.stop() - runner = None - break + elif runner.done: + raise KeyboardInterrupt + else: + time.sleep(0.1) + except KeyboardInterrupt: + fg.stop() + runner = None + break diff --git a/src/python/usrp_modes.py b/src/python/usrp_modes.py index 9cdf29d..3c87ce4 100755 --- a/src/python/usrp_modes.py +++ b/src/python/usrp_modes.py @@ -79,7 +79,7 @@ class adsb_rx_block (gr.top_block): print "Setting gain to %i" % (options.gain,) self.subdev.set_gain(options.gain) - self.subdev.set_bw(self.options.bandwidth) #only for DBSRX + #self.subdev.set_bw(self.options.bandwidth) #only for DBSRX rate = self.u.adc_rate() / options.decim