Merge branch 'master' of https://github.com/bistromath/gr-air-modes into simple_state_server

This commit is contained in:
Phelps Williams 2016-04-28 18:12:27 -07:00
commit b4695038e3
15 changed files with 169 additions and 132 deletions

View File

@ -22,7 +22,7 @@
# Project setup # Project setup
######################################################################## ########################################################################
cmake_minimum_required(VERSION 2.6) cmake_minimum_required(VERSION 2.6)
project(gr-gr-air-modes CXX) project(gr-gr-air-modes CXX C)
set(gr-gr-air-modes_VERSION_MAJOR 0) set(gr-gr-air-modes_VERSION_MAJOR 0)
set(gr-gr-air-modes_VERSION_MINOR 0) set(gr-gr-air-modes_VERSION_MINOR 0)
enable_testing() enable_testing()
@ -49,6 +49,8 @@ endif()
######################################################################## ########################################################################
include(GrBoost) include(GrBoost)
find_package(PythonLibs 2)
######################################################################## ########################################################################
# Install directories # Install directories
######################################################################## ########################################################################
@ -69,12 +71,22 @@ set(GRC_BLOCKS_DIR ${GR_PKG_DATA_DIR}/grc/blocks)
######################################################################## ########################################################################
# Find gnuradio build dependencies # Find gnuradio build dependencies
######################################################################## ########################################################################
find_package(GnuradioRuntime) set(GR_REQUIRED_COMPONENTS RUNTIME)
find_package(Gnuradio "3.7.2" REQUIRED)
if(NOT GNURADIO_RUNTIME_FOUND) if(NOT GNURADIO_RUNTIME_FOUND)
message(FATAL_ERROR "GnuRadio Runtime required to compile gr-air-modes") message(FATAL_ERROR "GnuRadio Runtime required to compile gr-air-modes")
endif() endif()
########################################################################
# Find PyZMQ bindings
########################################################################
include(GrPython)
#GR_PYTHON_CHECK_MODULE("PyZMQ" "zmq" "int(zmq.__version__.split('.')[0]) >= 13" PYZMQ_FOUND)
#if(NOT PYZMQ_FOUND)
# message(FATAL_ERROR "Python ZMQ bindings not found.")
#endif()
######################################################################## ########################################################################
# Setup the include and linker paths # Setup the include and linker paths
######################################################################## ########################################################################

View File

@ -233,7 +233,9 @@ class mainwindow(QtGui.QMainWindow):
try: try:
import osmosdr import osmosdr
self.src = osmosdr.source("") self.src = osmosdr.source("")
self.rates = [rate.start() for rate in self.src.get_sample_rates() if (rate.start() % 2.e6) == 0] self.rates = [rate.start() for rate in self.src.get_sample_rates()
if ((rate.start() % 2.e6) == 0)
or (rate.start() < 4.e6 and ((rate.start()%0.2e6) == 0))]
self.antennas = ["RX"] self.antennas = ["RX"]
self.src = None self.src = None
self.ui.combo_ant.setEnabled(False) self.ui.combo_ant.setEnabled(False)
@ -263,10 +265,15 @@ class mainwindow(QtGui.QMainWindow):
#set up recommended sample rate #set up recommended sample rate
if len(self.rates) > 1: if len(self.rates) > 1:
recommended_rate = min(x for x in self.rates if x >= 4e6 and if max(self.rates) > 4.e6:
max(self.rates) % x == 0) recommended_rate = min(x for x in self.rates if x >= 4e6 and
max(self.rates) % x == 0)
else:
recommended_rate = max(self.rates)
if recommended_rate >= 8.e6: if recommended_rate >= 8.e6:
self.ui.check_pmf.setChecked(True) self.ui.check_pmf.setChecked(True)
else:
self.ui.check_pmf.setChecked(False)
self.ui.combo_rate.setCurrentIndex(self.rates.index(recommended_rate)) self.ui.combo_rate.setCurrentIndex(self.rates.index(recommended_rate))
################ action handlers #################### ################ action handlers ####################
@ -400,10 +407,10 @@ class mainwindow(QtGui.QMainWindow):
def on_quit(self): def on_quit(self):
if self.running is True: if self.running is True:
self._relay.close()
self._radio.close() self._radio.close()
self._relay = None
self._radio = None self._radio = None
self._relay.close()
self._relay = None
self._rps_timer = None self._rps_timer = None
try: try:
self.kmlgen.done = True self.kmlgen.done = True

View File

@ -1,56 +0,0 @@
# - Find zeromq libraries
# This module finds zeromq if it is installed and determines where the
# include files and libraries are. It also determines what the name of
# the library is. This code sets the following variables:
#
# ZEROMQ_FOUND - have the zeromq libs been found
# ZEROMQ_LIBRARIES - path to the zeromq library
# ZEROMQ_INCLUDE_DIRS - path to where zmq.h is found
# ZEROMQ_DEBUG_LIBRARIES - path to the debug library
#INCLUDE(CMakeFindFrameworks)
# Search for the zeromq framework on Apple.
#CMAKE_FIND_FRAMEWORKS(ZeroMQ)
IF(WIN32)
FIND_LIBRARY(ZEROMQ_DEBUG_LIBRARY
NAMES libzmq_d zmq_d
PATHS
${ZEROMQ_LIBRARIES}
)
ENDIF(WIN32)
FIND_LIBRARY(ZEROMQ_LIBRARY
NAMES libzmq zmq
PATHS
${ZEROMQ_LIBRARIES}
${NSCP_LIBRARYDIR}
)
# IF(ZeroMQ_FRAMEWORKS AND NOT ZEROMQ_INCLUDE_DIR)
# FOREACH(dir ${ZeroMQ_FRAMEWORKS})
# SET(ZEROMQ_FRAMEWORK_INCLUDES ${ZEROMQ_FRAMEWORK_INCLUDES}
# ${dir}/Versions/${_CURRENT_VERSION}/include/zeromq${_CURRENT_VERSION})
# ENDFOREACH(dir)
# ENDIF(ZeroMQ_FRAMEWORKS AND NOT ZEROMQ_INCLUDE_DIR)
FIND_PATH(ZEROMQ_INCLUDE_DIR
NAMES zmq.hpp
PATHS
# ${ZEROMQ_FRAMEWORK_INCLUDES}
${ZEROMQ_INCLUDE_DIRS}
${NSCP_INCLUDEDIR}
${ZEROMQ_INCLUDE_DIR}
)
MARK_AS_ADVANCED(
ZEROMQ_DEBUG_LIBRARY
ZEROMQ_LIBRARY
ZEROMQ_INCLUDE_DIR
)
SET(ZEROMQ_INCLUDE_DIRS "${ZEROMQ_INCLUDE_DIR}")
SET(ZEROMQ_LIBRARIES "${ZEROMQ_LIBRARY}")
SET(ZEROMQ_DEBUG_LIBRARIES "${ZEROMQ_DEBUG_LIBRARY}")
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(ZeroMQ DEFAULT_MSG ZEROMQ_LIBRARIES ZEROMQ_INCLUDE_DIRS)

View File

@ -37,11 +37,11 @@ class AIR_MODES_API preamble : virtual public gr::block
{ {
public: public:
typedef boost::shared_ptr<preamble> sptr; typedef boost::shared_ptr<preamble> sptr;
static sptr make(int channel_rate, float threshold_db); static sptr make(float channel_rate, float threshold_db);
virtual void set_rate(int channel_rate) = 0; virtual void set_rate(float channel_rate) = 0;
virtual void set_threshold(float threshold_db) = 0; virtual void set_threshold(float threshold_db) = 0;
virtual int get_rate(void) = 0; virtual float get_rate(void) = 0;
virtual float get_threshold(void) = 0; virtual float get_threshold(void) = 0;
}; };

View File

@ -34,11 +34,11 @@
namespace gr { namespace gr {
air_modes::preamble::sptr air_modes::preamble::make(int channel_rate, float threshold_db) { air_modes::preamble::sptr air_modes::preamble::make(float channel_rate, float threshold_db) {
return gnuradio::get_initial_sptr(new air_modes::preamble_impl(channel_rate, threshold_db)); return gnuradio::get_initial_sptr(new air_modes::preamble_impl(channel_rate, threshold_db));
} }
air_modes::preamble_impl::preamble_impl(int channel_rate, float threshold_db) : air_modes::preamble_impl::preamble_impl(float channel_rate, float threshold_db) :
gr::block ("preamble", gr::block ("preamble",
gr::io_signature::make2 (2, 2, sizeof(float), sizeof(float)), //stream 0 is received data, stream 1 is moving average for reference gr::io_signature::make2 (2, 2, sizeof(float), sizeof(float)), //stream 0 is received data, stream 1 is moving average for reference
gr::io_signature::make (1, 1, sizeof(float))) //the output soft symbols gr::io_signature::make (1, 1, sizeof(float))) //the output soft symbols
@ -53,11 +53,11 @@ air_modes::preamble_impl::preamble_impl(int channel_rate, float threshold_db) :
d_key = pmt::string_to_symbol("preamble_found"); d_key = pmt::string_to_symbol("preamble_found");
} }
void air_modes::preamble_impl::set_rate(int channel_rate) { void air_modes::preamble_impl::set_rate(float channel_rate) {
d_samples_per_chip = channel_rate / d_chip_rate; d_samples_per_chip = channel_rate / d_chip_rate;
d_samples_per_symbol = d_samples_per_chip * 2; d_samples_per_symbol = d_samples_per_chip * 2;
d_check_width = 120 * d_samples_per_symbol; d_check_width = 120 * d_samples_per_symbol;
d_secs_per_sample = 1.0/channel_rate; d_sample_rate = channel_rate;
set_output_multiple(1+d_check_width*2); set_output_multiple(1+d_check_width*2);
set_history(d_samples_per_symbol); set_history(d_samples_per_symbol);
} }
@ -71,8 +71,8 @@ float air_modes::preamble_impl::get_threshold(void) {
return d_threshold_db; return d_threshold_db;
} }
int air_modes::preamble_impl::get_rate(void) { float air_modes::preamble_impl::get_rate(void) {
return d_samples_per_chip * d_chip_rate; return d_sample_rate;
} }
static void integrate_and_dump(float *out, const float *in, int chips, int samps_per_chip) { static void integrate_and_dump(float *out, const float *in, int chips, int samps_per_chip) {
@ -97,19 +97,42 @@ static double correlate_preamble(const float *in, int samples_per_chip) {
return corr; return corr;
} }
//todo: make it return a pair of some kind, otherwise you can lose precision static pmt::pmt_t tag_to_timestamp(gr::tag_t tstamp, uint64_t abs_sample_cnt, int rate) {
static double tag_to_timestamp(gr::tag_t tstamp, uint64_t abs_sample_cnt, double secs_per_sample) { uint64_t last_whole_stamp;
uint64_t ts_sample, last_whole_stamp;
double last_frac_stamp; double last_frac_stamp;
pmt::pmt_t tstime = pmt::make_tuple(pmt::from_uint64(0), pmt::from_double(0));
if(tstamp.key == NULL
|| !pmt::is_symbol(tstamp.key)
|| pmt::symbol_to_string(tstamp.key) != "rx_time") {
last_whole_stamp = 0;
last_frac_stamp = 0;
} else {
last_whole_stamp = pmt::to_uint64(pmt::tuple_ref(tstamp.value, 0));
last_frac_stamp = pmt::to_double(pmt::tuple_ref(tstamp.value, 1));
}
if(tstamp.key == NULL || pmt::symbol_to_string(tstamp.key) != "rx_time") return 0; //the timestamp tag has tstamp.offset, the sample index of the timestamp tag
//also tstamp.value, a pmt pair with (uint64, double) representing int and
//fractional timestamp, respectively.
//this function also gets an abs_sample_cnt which represents the sample count to
//find a timestamp for. sps is obviously samples per second.
//
//so (abs_sample_cnt - tstamp.offset) is the delay we apply to the tag
// int((abs_sample_cnt - tstamp.offset)/sps) is the integer offset
// (abs_sample_cnt - tstamp.offset)/sps is the fractional offset
last_whole_stamp = pmt::to_uint64(pmt::tuple_ref(tstamp.value, 0)); uint64_t int_offset = int(abs_sample_cnt - tstamp.offset)/rate;
last_frac_stamp = pmt::to_double(pmt::tuple_ref(tstamp.value, 1)); double frac_offset = ((abs_sample_cnt - tstamp.offset) % rate) / double(rate);
ts_sample = tstamp.offset;
uint64_t abs_whole = last_whole_stamp + int_offset;
double abs_frac = last_frac_stamp + frac_offset;
if(abs_frac > 1.0f) {
abs_frac -= 1.0f;
abs_whole += 1;
}
tstime = pmt::make_tuple(pmt::from_uint64(abs_whole), pmt::from_double(abs_frac));
double tstime = double(abs_sample_cnt * secs_per_sample) + last_whole_stamp + last_frac_stamp;
if(0) std::cout << "HEY WE GOT A STAMP AT " << tstime << " TICKS AT SAMPLE " << ts_sample << " ABS SAMPLE CNT IS " << abs_sample_cnt << std::endl;
return tstime; return tstime;
} }
@ -124,7 +147,7 @@ int air_modes::preamble_impl::general_work(int noutput_items,
int mininputs = std::min(ninput_items[0], ninput_items[1]); //they should be matched but let's be safe int mininputs = std::min(ninput_items[0], ninput_items[1]); //they should be matched but let's be safe
//round number of input samples down to nearest d_samples_per_chip //round number of input samples down to nearest d_samples_per_chip
//we also subtract off d_samples_per_chip to allow the bit center finder some leeway //we also subtract off d_samples_per_chip to allow the bit center finder some leeway
const int ninputs = std::max(mininputs - (mininputs % d_samples_per_chip) - d_samples_per_chip, 0); const int ninputs = std::max(mininputs - (mininputs % int(d_samples_per_chip)) - int(d_samples_per_chip), 0);
if (ninputs <= 0) { consume_each(0); return 0; } if (ninputs <= 0) { consume_each(0); return 0; }
float *out = (float *) output_items[0]; float *out = (float *) output_items[0];
@ -194,22 +217,20 @@ int air_modes::preamble_impl::general_work(int noutput_items,
//all right i'm prepared to call this a preamble //all right i'm prepared to call this a preamble
for(int j=0; j<240; j++) { for(int j=0; j<240; j++) {
out[j] = in[i+j*d_samples_per_chip] - inavg[i]; out[j] = in[i+int(j*d_samples_per_chip)] - inavg[i];
} }
//get the timestamp of the preamble //get the timestamp of the preamble
double tstamp = tag_to_timestamp(d_timestamp, abs_sample_cnt + i, d_secs_per_sample); pmt::pmt_t tstamp = tag_to_timestamp(d_timestamp, abs_sample_cnt + i, d_sample_rate);
//now tag the preamble //now tag the preamble
add_item_tag(0, //stream ID add_item_tag(0, //stream ID
nitems_written(0), //sample nitems_written(0), //sample
d_key, //frame_info d_key, //frame_info
pmt::from_double(tstamp), tstamp,
d_me //block src id d_me //block src id
); );
//std::cout << "PREAMBLE" << std::endl;
//produce only one output per work call -- TODO this should probably change //produce only one output per work call -- TODO this should probably change
if(0) std::cout << "Preamble consumed " << i+240*d_samples_per_chip << "with i=" << i << ", returned 240" << std::endl; if(0) std::cout << "Preamble consumed " << i+240*d_samples_per_chip << "with i=" << i << ", returned 240" << std::endl;

View File

@ -15,26 +15,26 @@ private:
int d_check_width; int d_check_width;
int d_chip_rate; int d_chip_rate;
float d_preamble_length_us; float d_preamble_length_us;
int d_samples_per_chip; float d_samples_per_chip;
int d_samples_per_symbol; float d_samples_per_symbol;
float d_threshold_db; float d_threshold_db;
float d_threshold; float d_threshold;
pmt::pmt_t d_me, d_key;
gr::tag_t d_timestamp; gr::tag_t d_timestamp;
double d_secs_per_sample; pmt::pmt_t d_me, d_key;
int d_sample_rate;
public: public:
preamble_impl(int channel_rate, float threshold_db); preamble_impl(float channel_rate, float threshold_db);
int general_work (int noutput_items, int general_work (int noutput_items,
gr_vector_int &ninput_items, gr_vector_int &ninput_items,
gr_vector_const_void_star &input_items, gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items); gr_vector_void_star &output_items);
void set_rate(int channel_rate); void set_rate(float channel_rate);
void set_threshold(float threshold_db); void set_threshold(float threshold_db);
float get_threshold(void); float get_threshold(void);
int get_rate(void); float get_rate(void);
}; };
} //namespace air_modes } //namespace air_modes

View File

@ -158,8 +158,6 @@ int air_modes::slicer_impl::work(int noutput_items,
} }
} }
rx_packet.timestamp = pmt::to_double(tag_iter->value);
//here you might want to traverse the whole packet and if you find all 0's, just toss it. don't know why these packets turn up, but they pass ECC. //here you might want to traverse the whole packet and if you find all 0's, just toss it. don't know why these packets turn up, but they pass ECC.
bool zeroes = 1; bool zeroes = 1;
for(int m = 0; m < 14; m++) { for(int m = 0; m < 14; m++) {
@ -183,13 +181,15 @@ int air_modes::slicer_impl::work(int noutput_items,
//crc for the other short packets is usually nonzero, so they can't really be trusted that far //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;} if(rx_packet.crc && (rx_packet.message_type == 11 || rx_packet.message_type == 17)) {continue;}
pmt::pmt_t tstamp = tag_iter->value;
d_payload.str(""); d_payload.str("");
for(int m = 0; m < packet_length/8; m++) { for(int m = 0; m < packet_length/8; m++) {
d_payload << std::hex << std::setw(2) << std::setfill('0') << unsigned(rx_packet.data[m]); d_payload << std::hex << 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 d_payload << " " << std::setw(6) << rx_packet.crc << " " << std::dec << rx_packet.reference_level
<< " " << std::setprecision(10) << std::setw(10) << rx_packet.timestamp; << " " << pmt::to_uint64(pmt::tuple_ref(tstamp, 0)) << " " << std::setprecision(10) << pmt::to_double(pmt::tuple_ref(tstamp, 1));
gr::message::sptr msg = gr::message::make_from_string(std::string(d_payload.str())); gr::message::sptr msg = gr::message::make_from_string(std::string(d_payload.str()));
d_queue->handle(msg); d_queue->handle(msg);
} }

View File

@ -38,6 +38,7 @@ private:
int d_chip_rate; int d_chip_rate;
int d_samples_per_chip; int d_samples_per_chip;
int d_samples_per_symbol; int d_samples_per_symbol;
gr::tag_t d_timestamp;
gr::msg_queue::sptr d_queue; gr::msg_queue::sptr d_queue;
std::ostringstream d_payload; std::ostringstream d_payload;

View File

@ -51,6 +51,12 @@ from air_modes_swig import *
# import any pure python here # import any pure python here
# #
try:
import zmq
except ImportError:
raise RuntimeError("PyZMQ not found! Please install libzmq and PyZMQ to run gr-air-modes")
from rx_path import rx_path from rx_path import rx_path
from zmq_socket import zmq_pubsub_iface from zmq_socket import zmq_pubsub_iface
from parse import * from parse import *

View File

@ -18,7 +18,6 @@ class output_flightgear:
def __init__(self, cprdec, hostname, port, pub): def __init__(self, cprdec, hostname, port, pub):
self.hostname = hostname self.hostname = hostname
self.port = port self.port = port
self.localpos = localpos
self.positions = {} self.positions = {}
self.velocities = {} self.velocities = {}
self.callsigns = {} self.callsigns = {}
@ -26,42 +25,41 @@ class output_flightgear:
self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.sock.connect((self.hostname, self.port)) self.sock.connect((self.hostname, self.port))
pub.subscribe("type17_dl", output) pub.subscribe("type17_dl", self.output)
def output(self, msg): def output(self, msg):
try: try:
msgtype = msg.data["df"] msgtype = msg.data["df"]
if msgtype == 17: #ADS-B report if msgtype == 17: #ADS-B report
icao24 = msg.data["aa"] icao24 = msg.data["aa"]
bdsreg = msg.data["me"].get_type() bdsreg = msg.data["me"].get_type()
if bdsreg == 0x08: #ident packet if bdsreg == 0x08: #ident packet
(ident, actype) = air_modes.parseBDS08(data) (ident, actype) = air_modes.parseBDS08(msg.data)
#select model based on actype #select model based on actype
self.callsigns[icao24] = [ident, actype] self.callsigns[icao24] = [ident, actype]
elif bdsreg == 0x06: #BDS0,6 pos elif bdsreg == 0x06: #BDS0,6 pos
[ground_track, decoded_lat, decoded_lon, rnge, bearing] = air_modes.parseBDS06(data, self._cpr) [ground_track, decoded_lat, decoded_lon, rnge, bearing] = air_modes.parseBDS06(msg.data, self._cpr)
self.positions[icao24] = [decoded_lat, decoded_lon, 0] self.positions[icao24] = [decoded_lat, decoded_lon, 0]
self.update(icao24) self.update(icao24)
elif bdsreg == 0x05: #BDS0,5 pos elif bdsreg == 0x05: #BDS0,5 pos
[altitude, decoded_lat, decoded_lon, rnge, bearing] = air_modes.parseBDS05(data, self._cpr) [altitude, decoded_lat, decoded_lon, rnge, bearing] = air_modes.parseBDS05(msg.data, self._cpr)
self.positions[icao24] = [decoded_lat, decoded_lon, altitude] self.positions[icao24] = [decoded_lat, decoded_lon, altitude]
self.update(icao24) self.update(icao24)
elif bdsreg == 0x09: #velocity elif bdsreg == 0x09: #velocity
subtype = data["bds09"].get_type() subtype = msg.data["bds09"].get_type()
if subtype == 0: if subtype == 0:
[velocity, heading, vert_spd, turnrate] = air_modes.parseBDS09_0(data) [velocity, heading, vert_spd, turnrate] = air_modes.parseBDS09_0(msg.data)
elif subtype == 1: elif subtype == 1:
[velocity, heading, vert_spd] = air_modes.parseBDS09_1(data) [velocity, heading, vert_spd] = air_modes.parseBDS09_1(msg.data)
turnrate = 0 turnrate = 0
else: else:
return return
self.velocities[icao24] = [velocity, heading, vert_spd, turnrate] self.velocities[icao24] = [velocity, heading, vert_spd, turnrate]
except ADSBError: except ADSBError:
pass pass

View File

@ -53,7 +53,6 @@ def html_template(my_position, json_file):
}; };
function jsonp_callback(results) { // from JSONP function jsonp_callback(results) { // from JSONP
clearMarkers();
airplanes = {}; airplanes = {};
for (var i = 0; i < results.length; i++) { for (var i = 0; i < results.length; i++) {
airplanes[results[i].icao] = { airplanes[results[i].icao] = {
@ -67,10 +66,20 @@ def html_template(my_position, json_file):
highlight: results[i].highlight highlight: results[i].highlight
}; };
} }
// clearMarkers();
refreshIcons(); refreshIcons();
} }
function refreshIcons() { function refreshIcons() {
//prune the list
for(var i = 0; i < planes.length; i++) {
icao = planes[i].get("icao")
if(!(icao in airplanes)) {
planes[i].setMap(null)
planes.splice(i, 1);
};
};
for (var airplane in airplanes) { for (var airplane in airplanes) {
if (airplanes[airplane].highlight != 0) { if (airplanes[airplane].highlight != 0) {
icon_file = "http://www.nerdnetworks.org/~bistromath/airplane_sprite_highlight.png"; icon_file = "http://www.nerdnetworks.org/~bistromath/airplane_sprite_highlight.png";
@ -86,7 +95,7 @@ def html_template(my_position, json_file):
}; };
if (airplanes[airplane].ident.length != 8) { if (airplanes[airplane].ident.length != 8) {
identstr = airplane; identstr = airplane;
} else { } else {
identstr = airplanes[airplane].ident; identstr = airplanes[airplane].ident;
}; };
@ -94,14 +103,31 @@ def html_template(my_position, json_file):
var planeOptions = { var planeOptions = {
map: map, map: map,
position: airplanes[airplane].center, position: airplanes[airplane].center,
icao: airplane,
icon: plane_icon, icon: plane_icon,
labelContent: identstr, labelContent: identstr,
labelAnchor: new google.maps.Point(35, -32), labelAnchor: new google.maps.Point(35, -32),
labelClass: "labels", labelClass: "labels",
labelStyle: {opacity: 0.75} labelStyle: {opacity: 0.75}
}; };
planeMarker = new MarkerWithLabel(planeOptions);
planes.push(planeMarker); var i = 0;
for(i; i<planes.length; i++) {
if(planes[i].get("icao") == airplane) {
planes[i].setPosition(airplanes[airplane].center);
if(planes[i].get("icon") != plane_icon) {
planes[i].setIcon(plane_icon); //handles highlight and heading
};
if(planes[i].get("labelContent") != identstr) {
planes[i].set("labelContent", identstr);
};
break;
};
};
if(i == planes.length) {
planeMarker = new MarkerWithLabel(planeOptions);
planes.push(planeMarker);
};
}; };
}; };

View File

@ -335,13 +335,13 @@ def parseBDS09_1(data):
ew = bool(data["dew"]) ew = bool(data["dew"])
subtype = data["sub"] subtype = data["sub"]
if subtype == 0x02: if subtype == 0x02:
ns_vel <<= 2 ns_vel *= 4
ew_vel <<= 2 ew_vel *= 4
velocity = math.hypot(ns_vel, ew_vel) velocity = math.hypot(ns_vel, ew_vel)
if ew: if ew:
ew_vel = 0 - ew_vel ew_vel = 0 - ew_vel
if ns_vel == 0: if ns_vel == 0:
heading = 0 heading = 0
else: else:
@ -423,12 +423,12 @@ def parse_TCAS_CRM(data):
def make_parser(pub): def make_parser(pub):
publisher = pub publisher = pub
def publish(message): def publish(message):
[data, ecc, reference, timestamp] = message.split() [data, ecc, reference, int_timestamp, frac_timestamp] = message.split()
try: try:
ret = air_modes.modes_report(modes_reply(int(data, 16)), ret = air_modes.modes_report(modes_reply(int(data, 16)),
int(ecc, 16), int(ecc, 16),
10.0*math.log10(max(1e-8,float(reference))), 10.0*math.log10(max(1e-8,float(reference))),
air_modes.stamp(0, float(timestamp))) air_modes.stamp(int(int_timestamp), float(frac_timestamp)))
pub["modes_dl"] = ret pub["modes_dl"] = ret
pub["type%i_dl" % ret.data.get_type()] = ret pub["type%i_dl" % ret.data.get_type()] = ret
except ADSBError: except ADSBError:

View File

@ -27,6 +27,7 @@ from gnuradio import gr, gru, eng_notation, filter, blocks
from gnuradio.filter import optfir from gnuradio.filter import optfir
from gnuradio.eng_option import eng_option from gnuradio.eng_option import eng_option
from gnuradio.gr.pubsub import pubsub from gnuradio.gr.pubsub import pubsub
from gnuradio.filter import pfb
from optparse import OptionParser, OptionGroup from optparse import OptionParser, OptionGroup
import air_modes import air_modes
import zmq import zmq
@ -45,9 +46,16 @@ class modes_radio (gr.top_block, pubsub):
self._resample = None self._resample = None
self._setup_source(options) self._setup_source(options)
self._rx_path = air_modes.rx_path(self._rate, options.threshold, if self._rate < 4e6:
self._resample = pfb.arb_resampler_ccf(4.e6/self._rate)
self._rx_rate = 4e6
else:
self._rx_rate = self._rate
self._rx_path = air_modes.rx_path(self._rx_rate, options.threshold,
self._queue, options.pmf, options.dcblock) self._queue, options.pmf, options.dcblock)
#now subscribe to set various options via pubsub #now subscribe to set various options via pubsub
self.subscribe("freq", self.set_freq) self.subscribe("freq", self.set_freq)
self.subscribe("gain", self.set_gain) self.subscribe("gain", self.set_gain)
@ -81,7 +89,7 @@ class modes_radio (gr.top_block, pubsub):
@staticmethod @staticmethod
def add_radio_options(parser): def add_radio_options(parser):
group = OptionGroup(parser, "Receiver setup options") group = OptionGroup(parser, "Receiver setup options")
#Choose source #Choose source
group.add_option("-s","--source", type="string", default="uhd", group.add_option("-s","--source", type="string", default="uhd",
help="Choose source: uhd, osmocom, <filename>, or <ip:port> [default=%default]") help="Choose source: uhd, osmocom, <filename>, or <ip:port> [default=%default]")
@ -125,8 +133,20 @@ class modes_radio (gr.top_block, pubsub):
return self.get_gain() return self.get_gain()
def set_rate(self, rate): def set_rate(self, rate):
self._rx_path.set_rate(rate) if(rate < 4e6 and self._rate > 4e6):
return self._u.set_rate(rate) if self.live_source() else 0 raise NotImplementedError("Lowering rate <4e6Msps not currently supported.")
if(rate < 4e6):
self._resample.set_rate(4e6/rate)
self._rx_rate = 4e6
else:
self._rx_rate = rate
self._rx_path.set_rate(self._rx_rate)
if self._options.source in ("osmocom"):
return self._u.set_sample_rate(rate)
if self._options.source in ("uhd"):
return self._u.set_rate(rate)
else:
return 0
def set_threshold(self, threshold): def set_threshold(self, threshold):
self._rx_path.set_threshold(threshold) self._rx_path.set_threshold(threshold)
@ -199,7 +219,7 @@ class modes_radio (gr.top_block, pubsub):
ip, port = re.search("(.*)\:(\d{1,5})", options.source).groups() ip, port = re.search("(.*)\:(\d{1,5})", options.source).groups()
except: except:
raise Exception("Please input UDP source e.g. 192.168.10.1:12345") raise Exception("Please input UDP source e.g. 192.168.10.1:12345")
self._u = gr.udp_source(gr.sizeof_gr_complex, ip, int(port)) self._u = blocks.udp_source(gr.sizeof_gr_complex, ip, int(port))
print "Using UDP source %s:%s" % (ip, port) print "Using UDP source %s:%s" % (ip, port)
else: else:
self._u = blocks.file_source(gr.sizeof_gr_complex, options.source) self._u = blocks.file_source(gr.sizeof_gr_complex, options.source)
@ -208,5 +228,7 @@ class modes_radio (gr.top_block, pubsub):
print "Rate is %i" % (options.rate,) print "Rate is %i" % (options.rate,)
def close(self): def close(self):
self.stop()
self.wait()
self._sender.close() self._sender.close()
self._u = None self._u = None

View File

@ -37,7 +37,7 @@ class rx_path(gr.hier_block2):
# Convert incoming I/Q baseband to amplitude # Convert incoming I/Q baseband to amplitude
self._demod = blocks.complex_to_mag_squared() self._demod = blocks.complex_to_mag_squared()
if use_dcblock: if use_dcblock:
self._dcblock = filter.dc_blocker_cc(100*self._spc,True) self._dcblock = filter.dc_blocker_cc(100*self._spc,False)
self.connect(self, self._dcblock, self._demod) self.connect(self, self._dcblock, self._demod)
else: else:
self.connect(self, self._demod) self.connect(self, self._demod)
@ -65,13 +65,13 @@ class rx_path(gr.hier_block2):
self.connect(self._sync, self._slicer) self.connect(self._sync, self._slicer)
def set_rate(self, rate): def set_rate(self, rate):
self._sync.set_rate(rate) self._sync.set_rate(int(rate))
self._spc = int(rate/2e6) self._spc = int(rate/2e6)
self._avg.set_length_and_scale(48*self._spc, 1.0/(48*self._spc)) self._avg.set_length_and_scale(48*self._spc, 1.0/(48*self._spc))
if self._bb != self._demod: if self._bb != self._demod:
self._pmf.set_length_and_scale(self._spc, 1.0/self._spc) self._pmf.set_length_and_scale(self._spc, 1.0/self._spc)
if self._dcblock is not None: # if self._dcblock is not None:
self._dcblock.set_length(100*self._spc) # self._dcblock.set_length(100*self._spc)
def set_threshold(self, threshold): def set_threshold(self, threshold):
self._sync.set_threshold(threshold) self._sync.set_threshold(threshold)

View File

@ -23,7 +23,7 @@
import time, os, sys, socket import time, os, sys, socket
from string import split, join from string import split, join
import air_modes import air_modes
from datetime import * import datetime
from air_modes.exceptions import * from air_modes.exceptions import *
import threading import threading
@ -63,7 +63,7 @@ class output_sbs1:
#it could be cleaner if there were separate output_* fns #it could be cleaner if there were separate output_* fns
#but this works #but this works
for i in (0, 4, 5, 11, 17): for i in (0, 4, 5, 11, 17):
pub.subscribe("type%i_dl" % i, output) pub.subscribe("type%i_dl" % i, self.output)
#spawn thread to add new connections as they come in #spawn thread to add new connections as they come in
self._runner = dumb_task_runner(self.add_pending_conns, 0.1) self._runner = dumb_task_runner(self.add_pending_conns, 0.1)
@ -83,7 +83,7 @@ class output_sbs1:
# dictionary is getting too large. # dictionary is getting too large.
if len(self._aircraft_id_map) > 1e4: if len(self._aircraft_id_map) > 1e4:
minimum = min(self._aircraft_id_map.values()) + (len(self._aircraft_id_map) - 1e4) minimum = min(self._aircraft_id_map.values()) + (len(self._aircraft_id_map) - 1e4)
for icao, _id in self._aircraft_id_map: for icao, _id in dict(self._aircraft_id_map).iteritems():
if _id < minimum: if _id < minimum:
del self._aircraft_id_map[icao] del self._aircraft_id_map[icao]
@ -111,7 +111,7 @@ class output_sbs1:
pass pass
def current_time(self): def current_time(self):
timenow = datetime.now() timenow = datetime.datetime.now()
return [timenow.strftime("%Y/%m/%d"), timenow.strftime("%H:%M:%S.%f")[0:-3]] return [timenow.strftime("%Y/%m/%d"), timenow.strftime("%H:%M:%S.%f")[0:-3]]
def decode_fs(self, fs): def decode_fs(self, fs):
@ -154,7 +154,7 @@ class output_sbs1:
[datestr, timestr] = self.current_time() [datestr, timestr] = self.current_time()
aircraft_id = self.get_aircraft_id(ecc) aircraft_id = self.get_aircraft_id(ecc)
retstr = "MSG,7,0,%i,%06X,%i,%s,%s,%s,%s,,%s,,,,,,,,,," % (aircraft_id, ecc, aircraft_id+100, datestr, timestr, datestr, timestr, air_modes.decode_alt(shortdata["ac"], True)) retstr = "MSG,7,0,%i,%06X,%i,%s,%s,%s,%s,,%s,,,,,,,,,," % (aircraft_id, ecc, aircraft_id+100, datestr, timestr, datestr, timestr, air_modes.decode_alt(shortdata["ac"], True))
if vs: if shortdata["vs"]:
retstr += "1\r\n" retstr += "1\r\n"
else: else:
retstr += "0\r\n" retstr += "0\r\n"
@ -174,7 +174,7 @@ class output_sbs1:
def pp11(self, shortdata, ecc): def pp11(self, shortdata, ecc):
[datestr, timestr] = self.current_time() [datestr, timestr] = self.current_time()
aircraft_id = self.get_aircraft_id(icao24) aircraft_id = self.get_aircraft_id(shortdata["aa"])
return "MSG,8,0,%i,%06X,%i,%s,%s,%s,%s,,,,,,,,,,,,\r\n" % (aircraft_id, shortdata["aa"], aircraft_id+100, datestr, timestr, datestr, timestr) return "MSG,8,0,%i,%06X,%i,%s,%s,%s,%s,,,,,,,,,,,,\r\n" % (aircraft_id, shortdata["aa"], aircraft_id+100, datestr, timestr, datestr, timestr)
def pp17(self, data): def pp17(self, data):