diff --git a/CMakeLists.txt b/CMakeLists.txt index e9380b5..d59ada8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -111,7 +111,7 @@ find_package(Doxygen) # components required to the list of GR_REQUIRED_COMPONENTS (in all # caps such as FILTER or FFT) and change the version to the minimum # API compatible version required. -set(GR_REQUIRED_COMPONENTS RUNTIME) +set(GR_REQUIRED_COMPONENTS RUNTIME FILTER) find_package(Gnuradio "3.7.2" REQUIRED) if(NOT CPPUNIT_FOUND) diff --git a/grc/lora_channelizer.xml b/grc/lora_channelizer.xml new file mode 100644 index 0000000..578ae35 --- /dev/null +++ b/grc/lora_channelizer.xml @@ -0,0 +1,28 @@ + + + channelizer + lora_channelizer + + import lora + lora.channelizer($in_samp_rate, $out_samp_rate, $center_freq, $channel_list) + + + + in + complex + + + + + out + complex + + diff --git a/grc/lora_controller.xml b/grc/lora_controller.xml new file mode 100644 index 0000000..a766097 --- /dev/null +++ b/grc/lora_controller.xml @@ -0,0 +1,9 @@ + + + controller + lora_controller + + import lora + lora.controller($parent) + + diff --git a/grc/lora_receiver.xml b/grc/lora_receiver.xml index f3f2f52..0b98210 100644 --- a/grc/lora_receiver.xml +++ b/grc/lora_receiver.xml @@ -4,19 +4,13 @@ lora_lora_receiver [LoRa] import lora - lora.lora_receiver($in_samp_rate, $freq, $offset, $sf, $out_samp_rate, $threshold) + lora.lora_receiver($in_samp_rate, $center_freq, $channel_list, $sf, $out_samp_rate, $threshold) + set_center_freq($freq) set_sf($sf) - set_offset($offset) set_out_samp_rate($out_samp_rate) set_threshold($threshold) - - Spreading factor - sf - int - - Sample rate in_samp_rate @@ -24,24 +18,30 @@ float - - Detection threshold - threshold - 0.01 - float - - - Frequency - freq + Center frequency + center_freq 868e6 float - Offset - offset - 100e3 + Channel list + channel_list + [868.1e6] + float_vector + + + + Spreading factor + sf + int + + + + Detection threshold + threshold + 0.01 float @@ -63,10 +63,4 @@ message 1 - - - debug - message - 1 - diff --git a/include/lora/CMakeLists.txt b/include/lora/CMakeLists.txt index 458a440..9e60420 100644 --- a/include/lora/CMakeLists.txt +++ b/include/lora/CMakeLists.txt @@ -24,5 +24,7 @@ install(FILES api.h decoder.h message_file_sink.h - message_socket_sink.h DESTINATION include/lora + message_socket_sink.h + channelizer.h + controller.h DESTINATION include/lora ) diff --git a/include/lora/channelizer.h b/include/lora/channelizer.h new file mode 100644 index 0000000..383ebe4 --- /dev/null +++ b/include/lora/channelizer.h @@ -0,0 +1,55 @@ +/* -*- c++ -*- */ +/* + * Copyright 2017 Pieter Robyns. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + + +#ifndef INCLUDED_LORA_CHANNELIZER_H +#define INCLUDED_LORA_CHANNELIZER_H + +#include +#include + +namespace gr { + namespace lora { + + /*! + * \brief <+description of block+> + * \ingroup lora + * + */ + class LORA_API channelizer : virtual public gr::hier_block2 + { + public: + typedef boost::shared_ptr sptr; + + /*! + * \brief Return a shared_ptr to a new instance of lora::channelizer. + * + * To avoid accidental use of raw pointers, lora::channelizer's + * constructor is in a private implementation + * class. lora::channelizer::make is the public interface for + * creating new instances. + */ + static sptr make(float in_samp_rate, float out_samp_rate, float center_freq, std::vector channel_list); + }; + + } // namespace lora +} // namespace gr + +#endif /* INCLUDED_LORA_CHANNELIZER_H */ diff --git a/include/lora/controller.h b/include/lora/controller.h new file mode 100644 index 0000000..278e91c --- /dev/null +++ b/include/lora/controller.h @@ -0,0 +1,55 @@ +/* -*- c++ -*- */ +/* + * Copyright 2017 Pieter Robyns. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_LORA_CONTROLLER_H +#define INCLUDED_LORA_CONTROLLER_H + +#include +#include + +namespace gr { + namespace lora { + + /*! + * \brief <+description of block+> + * \ingroup lora + * + */ + class channelizer_impl; + class LORA_API controller : virtual public gr::block + { + public: + typedef boost::shared_ptr sptr; + + /*! + * \brief Return a shared_ptr to a new instance of lora::controller. + * + * To avoid accidental use of raw pointers, lora::controller's + * constructor is in a private implementation + * class. lora::controller::make is the public interface for + * creating new instances. + */ + static sptr make(void* parent); + }; + + } // namespace lora +} // namespace gr + +#endif /* INCLUDED_LORA_CONTROLLER_H */ diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 5023272..b2bf736 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -29,6 +29,8 @@ list(APPEND lora_sources decoder_impl.cc message_file_sink_impl.cc message_socket_sink_impl.cc + channelizer_impl.cc + controller_impl.cc ) set(lora_sources "${lora_sources}" PARENT_SCOPE) diff --git a/lib/channelizer_impl.cc b/lib/channelizer_impl.cc new file mode 100644 index 0000000..f73be74 --- /dev/null +++ b/lib/channelizer_impl.cc @@ -0,0 +1,77 @@ +/* -*- c++ -*- */ +/* + * Copyright 2017 Pieter Robyns. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "channelizer_impl.h" + +namespace gr { + namespace lora { + + channelizer::sptr + channelizer::make(float in_samp_rate, float out_samp_rate, float center_freq, std::vector channel_list) { + return gnuradio::get_initial_sptr + (new channelizer_impl(in_samp_rate, out_samp_rate, center_freq, channel_list)); + } + + /* + * The private constructor + */ + channelizer_impl::channelizer_impl(float in_samp_rate, float out_samp_rate, float center_freq, std::vector channel_list) + : gr::hier_block2("channelizer", + gr::io_signature::make(1, 1, sizeof(gr_complex)), + gr::io_signature::make(channel_list.size(), channel_list.size(), sizeof(gr_complex))), + d_cfo(0.0) + { + d_lpf = gr::filter::firdes::low_pass(1.0, out_samp_rate, 86000, 20000, gr::filter::firdes::WIN_HAMMING, 6.67); + d_freq_offset = channel_list[0] - center_freq; + d_xlating_fir_filter = gr::filter::freq_xlating_fir_filter_ccf::make(1, d_lpf, d_freq_offset, out_samp_rate); + d_controller = gr::lora::controller::make((void*)this); + d_resampler = gr::filter::fractional_resampler_cc::make(0, (float)in_samp_rate / (float)out_samp_rate); + //self.delay = delay(gr.sizeof_gr_complex, int((len(lpf)-1) / 2.0)) + + //Create message ports + message_port_register_hier_in(pmt::intern("control")); + + connect(self(), 0, d_resampler, 0); + connect(d_resampler, 0, d_xlating_fir_filter, 0); + connect(d_xlating_fir_filter, 0, self(), 0); + + msg_connect(self(), pmt::intern("control"), d_controller, pmt::intern("control")); + } + + /* + * Our virtual destructor. + */ + channelizer_impl::~channelizer_impl() { + } + + void channelizer_impl::apply_cfo(float cfo) { + d_cfo += cfo; + //std::cout << d_freq_offset + d_cfo << std::endl; + d_xlating_fir_filter->set_center_freq(d_freq_offset + d_cfo); + } + + + } /* namespace lora */ +} /* namespace gr */ diff --git a/lib/channelizer_impl.h b/lib/channelizer_impl.h new file mode 100644 index 0000000..2683e1e --- /dev/null +++ b/lib/channelizer_impl.h @@ -0,0 +1,52 @@ +/* -*- c++ -*- */ +/* + * Copyright 2017 Pieter Robyns. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + + +#ifndef INCLUDED_LORA_CHANNELIZER_IMPL_H +#define INCLUDED_LORA_CHANNELIZER_IMPL_H + +#include +#include +#include +#include +#include + +namespace gr { + namespace lora { + class channelizer_impl : public channelizer { + private: + gr::filter::freq_xlating_fir_filter_ccf::sptr d_xlating_fir_filter; + gr::filter::fractional_resampler_cc::sptr d_resampler; + std::vector d_lpf; + float d_cfo; + uint32_t d_freq_offset; + gr::lora::controller::sptr d_controller; + + public: + channelizer_impl(float in_samp_rate, float out_samp_rate, float center_freq, std::vector channel_list); + ~channelizer_impl(); + void apply_cfo(float cfo); + + // Where all the action really happens + }; + } // namespace lora +} // namespace gr + +#endif /* INCLUDED_LORA_CHANNELIZER_IMPL_H */ diff --git a/lib/controller_impl.cc b/lib/controller_impl.cc new file mode 100644 index 0000000..846f447 --- /dev/null +++ b/lib/controller_impl.cc @@ -0,0 +1,68 @@ +/* -*- c++ -*- */ +/* + * Copyright 2017 Pieter Robyns. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "controller_impl.h" +#include "channelizer_impl.h" + +namespace gr { + namespace lora { + + controller::sptr + controller::make(void* parent) { + return gnuradio::get_initial_sptr + (new controller_impl(parent)); + } + + /* + * The private constructor + */ + controller_impl::controller_impl(void* parent) + : gr::block("controller", + gr::io_signature::make(0, 0, 0), + gr::io_signature::make(0, 0, 0)) { + d_parent = parent; + d_port = pmt::intern("control"); + message_port_register_in(d_port); + set_msg_handler(d_port, boost::bind(&controller_impl::handle_control, this, _1)); + } + + void controller_impl::handle_control(pmt::pmt_t msg){ + if(pmt::symbol_to_string(pmt::car(msg)).compare("cfo") == 0) { + //std::cout << "Setting CFO " << pmt::to_float(pmt::cdr(msg)) << std::endl; + ((channelizer_impl*)d_parent)->apply_cfo(pmt::to_float(pmt::cdr(msg))); // TODO: Pretty hacky cast, can we do this in a cleaner way? + } + } + + /* + * Our virtual destructor. + */ + controller_impl::~controller_impl() + { + } + + + } /* namespace lora */ +} /* namespace gr */ diff --git a/lib/controller_impl.h b/lib/controller_impl.h new file mode 100644 index 0000000..365da22 --- /dev/null +++ b/lib/controller_impl.h @@ -0,0 +1,46 @@ +/* -*- c++ -*- */ +/* + * Copyright 2017 Pieter Robyns. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_LORA_CONTROLLER_IMPL_H +#define INCLUDED_LORA_CONTROLLER_IMPL_H + +#include + +namespace gr { + namespace lora { + + class controller_impl : public controller { + private: + void* d_parent; + pmt::pmt_t d_port; + + void handle_control(pmt::pmt_t msg); + + public: + controller_impl(void* parent); + ~controller_impl(); + + // Where all the action really happens + }; + + } // namespace lora +} // namespace gr + +#endif /* INCLUDED_LORA_CONTROLLER_IMPL_H */ diff --git a/lib/decoder_impl.cc b/lib/decoder_impl.cc index 071811a..cf06920 100644 --- a/lib/decoder_impl.cc +++ b/lib/decoder_impl.cc @@ -137,7 +137,7 @@ namespace gr { // Register gnuradio ports this->message_port_register_out(pmt::mp("frames")); - this->message_port_register_out(pmt::mp("debug")); + this->message_port_register_out(pmt::mp("control")); // Whitening empty file @@ -775,7 +775,7 @@ namespace gr { void decoder_impl::msg_raw_chirp_debug(const gr_complex *raw_samples, const uint32_t num_samples) { pmt::pmt_t chirp_blob = pmt::make_blob(raw_samples, sizeof(gr_complex) * num_samples); - message_port_pub(pmt::mp("debug"), chirp_blob); + //message_port_pub(pmt::mp("debug"), chirp_blob); } void decoder_impl::msg_lora_frame(const uint8_t *frame_bytes, const uint32_t frame_len) { diff --git a/python/lora_receiver.py b/python/lora_receiver.py index 743e429..b744f6e 100644 --- a/python/lora_receiver.py +++ b/python/lora_receiver.py @@ -20,76 +20,56 @@ # from gnuradio import gr -from gnuradio.filter import freq_xlating_fir_filter_ccf, firdes, fractional_resampler_cc -from gnuradio.analog import quadrature_demod_cf -from gnuradio.blocks import null_sink, delay import lora -import pmt class lora_receiver(gr.hier_block2): """ docstring for block lora_receiver """ - def __init__(self, in_samp_rate, freq, offset, sf, out_samp_rate, threshold = 0.01): + def __init__(self, in_samp_rate, center_freq, channel_list, sf, out_samp_rate, threshold = 0.01): gr.hier_block2.__init__(self, "lora_receiver", # Min, Max, gr.sizeof_ gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature(0, 0, 0)) # Output signature # Parameters - self.offset = offset - self.sf = sf self.in_samp_rate = in_samp_rate + self.center_freq = center_freq + self.sf = sf self.out_samp_rate = out_samp_rate - bw = 125000 + self.channel_list = channel_list # Define blocks - null1 = null_sink(gr.sizeof_float) - null2 = null_sink(gr.sizeof_float) - self.c_decoder = lora.decoder(out_samp_rate, sf) + self.channelizer = lora.channelizer(in_samp_rate, out_samp_rate, center_freq, channel_list) + self.decoder = lora.decoder(out_samp_rate, sf) self.set_threshold(threshold) - decimation = 1 - - lpf = firdes.low_pass(1, out_samp_rate, 86000, 20000, firdes.WIN_HAMMING, 6.67) - channelizer = freq_xlating_fir_filter_ccf(decimation, lpf, offset, out_samp_rate) - self.channelizer = channelizer - resampler = fractional_resampler_cc(0, float(in_samp_rate) / float(out_samp_rate)) - self.delay = delay(gr.sizeof_gr_complex, int((len(lpf)-1) / 2.0)) - # Messages - self.message_port_register_hier_out('debug') self.message_port_register_hier_out('frames') # Connect blocks - self.connect( (self, 0), (resampler, 0) ) - self.connect( (resampler, 0), (channelizer, 0) ) - self.connect( (channelizer, 0), (self.c_decoder, 0) ) - self.connect( (resampler, 0), (self.delay, 0) ) - self.connect( (self.delay, 0), (self.c_decoder, 1) ) - self.msg_connect( (self.c_decoder, 'debug' ), (self, 'debug' ) ) - self.msg_connect( (self.c_decoder, 'frames'), (self, 'frames') ) + self.connect((self, 0), (self.channelizer, 0)) + self.connect((self.channelizer, 0), (self.decoder, 0)) + self.msg_connect((self.decoder, 'frames'), (self, 'frames')) + self.msg_connect((self.decoder, 'control'), (self.channelizer, 'control')) def get_sf(self): return self.sf def set_sf(self, sf): self.sf = sf - ## hier_block2 does not have a realtime attribute: - ## http://gnuradio.org/doc/sphinx/runtime.html?highlight=hier_block2#gnuradio.gr.hier_block2 - # if self.realtime: - self.c_decoder.set_sf(self.sf) + self.decoder.set_sf(self.sf) - def get_offset(self): - return self.offset + def get_center_freq(self): + return self.center_freq - def set_offset(self, offset): - self.offset = offset - self.channelizer.set_center_freq(self.offset) + def set_center_freq(self, center_freq): + self.center_freq = center_freq + self.channelizer.set_center_freq(self.center_freq) def get_threshold(self): return self.threshold def set_threshold(self, threshold): self.threshold = threshold - self.c_decoder.set_abs_threshold(self.threshold) + self.decoder.set_abs_threshold(self.threshold) diff --git a/swig/lora_swig.i b/swig/lora_swig.i index 5f01969..035db72 100644 --- a/swig/lora_swig.i +++ b/swig/lora_swig.i @@ -11,6 +11,8 @@ #include "lora/decoder.h" #include "lora/message_file_sink.h" #include "lora/message_socket_sink.h" +#include "lora/channelizer.h" +#include "lora/controller.h" %} @@ -20,3 +22,7 @@ GR_SWIG_BLOCK_MAGIC2(lora, decoder); GR_SWIG_BLOCK_MAGIC2(lora, message_file_sink); %include "lora/message_socket_sink.h" GR_SWIG_BLOCK_MAGIC2(lora, message_socket_sink); +%include "lora/channelizer.h" +GR_SWIG_BLOCK_MAGIC2(lora, channelizer); +%include "lora/controller.h" +GR_SWIG_BLOCK_MAGIC2(lora, controller);