Merge branch 'master' of https://github.com/bistromath/gr-air-modes into simple_state_server
This commit is contained in:
commit
b4695038e3
@ -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
|
||||||
########################################################################
|
########################################################################
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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 *
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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:
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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):
|
||||||
|
Loading…
Reference in New Issue
Block a user