diff --git a/conf/gnss-sdr_GPS_L1_2ch_udp.conf b/conf/gnss-sdr_GPS_L1_2ch_udp.conf new file mode 100644 index 000000000..6fa7684c6 --- /dev/null +++ b/conf/gnss-sdr_GPS_L1_2ch_udp.conf @@ -0,0 +1,86 @@ +; You can define your own receiver and invoke it by doing +; gnss-sdr --config_file=my_GNSS_SDR_configuration.conf +; + +[GNSS-SDR] + +;######### GLOBAL OPTIONS ################## +;internal_fs_sps: Internal signal sampling frequency after the signal conditioning stage [Sps]. +GNSS-SDR.internal_fs_sps=2600000 + +;######### SIGNAL_SOURCE CONFIG ############ +SignalSource.implementation=UDP_Signal_Source +;SignalSource.implementation=File_Signal_Source +SignalSource.filename=/home/javier/gnss/gnss-simulator/build/signal_out.bin ; <- PUT YOUR FILE HERE +SignalSource.item_type=gr_complex +SignalSource.address=0.0.0.0 +SignalSource.port=1234 +SignalSource.payload_bytes=1024 +SignalSource.sample_type=cbyte +SignalSource.RF_channels=2 +SignalSource.dump=true +SignalSource.dump_filename=./signal_source.dat + + +;######### SIGNAL_CONDITIONER CONFIG ############ +SignalConditioner0.implementation=Pass_Through +SignalConditioner1.implementation=Pass_Through + +;######### CHANNELS GLOBAL CONFIG ############ +Channels_1C.count=2 +Channels.in_acquisition=1 + +;# CHANNEL CONNECTION +Channel0.RF_channel_ID=0 +Channel0.signal=1C +Channel1.RF_channel_ID=1 +Channel1.signal=1C + +;######### ACQUISITION GLOBAL CONFIG ############ +Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition +Acquisition_1C.item_type=gr_complex +Acquisition_1C.threshold=20 +Acquisition_1C.use_CFAR_algorithm=false +Acquisition_1C.blocking=true +Acquisition_1C.doppler_max=10000 +Acquisition_1C.doppler_step=250 +Acquisition_1C.dump=false +Acquisition_1C.dump_filename=./acq_dump.dat + + +;######### TRACKING GLOBAL CONFIG ############ +Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_Tracking +Tracking_1C.item_type=gr_complex +Tracking_1C.dump=false +Tracking_1C.dump_filename=./tracking_ch_ +Tracking_1C.pll_bw_hz=35.0; +Tracking_1C.dll_bw_hz=2.0; +Tracking_1C.early_late_space_chips=0.5; + + +;######### TELEMETRY DECODER GPS CONFIG ############ +TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder +TelemetryDecoder_1C.dump=false + + +;######### OBSERVABLES CONFIG ############ +Observables.implementation=Hybrid_Observables +Observables.dump=false +Observables.dump_filename=./observables.dat + + +;######### PVT CONFIG ############ +PVT.implementation=RTKLIB_PVT +PVT.positioning_mode=Single ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic +PVT.iono_model=Broadcast ; options: OFF, Broadcast, SBAS, Iono-Free-LC, Estimate_STEC, IONEX +PVT.trop_model=Saastamoinen ; options: OFF, Saastamoinen, SBAS, Estimate_ZTD, Estimate_ZTD_Grad +PVT.output_rate_ms=100 +PVT.display_rate_ms=500 +PVT.dump_filename=./PVT +PVT.nmea_dump_filename=./gnss_sdr_pvt.nmea; +PVT.flag_nmea_tty_port=false; +PVT.nmea_dump_devname=/dev/pts/4 +PVT.flag_rtcm_server=false +PVT.flag_rtcm_tty_port=false +PVT.rtcm_dump_devname=/dev/pts/1 +PVT.dump=false diff --git a/src/algorithms/signal_source/adapters/CMakeLists.txt b/src/algorithms/signal_source/adapters/CMakeLists.txt index ededc5dc7..d135412e0 100644 --- a/src/algorithms/signal_source/adapters/CMakeLists.txt +++ b/src/algorithms/signal_source/adapters/CMakeLists.txt @@ -166,6 +166,7 @@ set(SIGNAL_SOURCE_ADAPTER_SOURCES file_signal_source.cc spir_gss6450_file_signal_source.cc rtl_tcp_signal_source.cc labsat_signal_source.cc + udp_signal_source.cc ${OPT_DRIVER_SOURCES} ) diff --git a/src/algorithms/signal_source/adapters/udp_signal_source.cc b/src/algorithms/signal_source/adapters/udp_signal_source.cc new file mode 100644 index 000000000..af0a63378 --- /dev/null +++ b/src/algorithms/signal_source/adapters/udp_signal_source.cc @@ -0,0 +1,186 @@ +/*! + * \file rtl_tcp_signal_source.cc + * \brief Signal source for the Realtek RTL2832U USB dongle DVB-T receiver + * over TCP. + * (see http://sdr.osmocom.org/trac/wiki/rtl-sdr for more information) + * \author Anthony Arnold, 2015. anthony.arnold(at)uqconnect.edu.au + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR 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 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "udp_signal_source.h" +#include "configuration_interface.h" +#include "GPS_L1_CA.h" +#include +#include +#include + + +using google::LogMessage; + + +UDPSignalSource::UDPSignalSource(ConfigurationInterface* configuration, + std::string role, unsigned int in_stream, unsigned int out_stream, + boost::shared_ptr queue) : role_(role), in_stream_(in_stream), out_stream_(out_stream), queue_(queue) +{ + // DUMP PARAMETERS + std::string empty = ""; + std::string default_dump_file = "./data/signal_source.dat"; + std::string default_item_type = "gr_complex"; + dump_ = configuration->property(role + ".dump", false); + dump_filename_ = configuration->property(role + ".dump_filename", + default_dump_file); + + // rtl_tcp PARAMETERS + std::string default_address = "127.0.0.1"; + int default_port = 1234; + + RF_channels_ = configuration->property(role + ".RF_channels", 2); + std::string default_sample_type = "cbyte"; + std::string sample_type = configuration->property(role + ".sample_type", default_sample_type); + + item_type_ = configuration->property(role + ".item_type", default_item_type); + address_ = configuration->property(role + ".address", default_address); + port_ = configuration->property(role + ".port", default_port); + int payload_bytes = configuration->property(role + ".payload_bytes", 1024); + + if (sample_type.compare("cbyte")==0) + { + std::cout<<"address_ "< gr_complex type conversion blocks + for (int n = 0; n < (RF_channels_ * 2); n++) + { + char_to_float.push_back(gr::blocks::char_to_float::make()); + } + + for (int n = 0; n < RF_channels_; n++) + { + float_to_complex_.push_back(gr::blocks::float_to_complex::make()); + } + + item_size_ = sizeof(gr_complex); + + if (dump_) + { + file_sink_dbg_=gr::blocks::file_sink::make(sizeof(char), "debug.dat"); + + for (int n = 0; n < RF_channels_; n++) + { + DLOG(INFO) << "Dumping output into file " << (dump_filename_+"ch"+std::to_string(n)); + file_sink_.push_back(gr::blocks::file_sink::make(item_size_, (dump_filename_+"ch"+std::to_string(n)).c_str())); + } + } +} + + +UDPSignalSource::~UDPSignalSource() +{ +} + + +void UDPSignalSource::connect(gr::top_block_sptr top_block) +{ + top_block->connect(udp_gnss_rx_source_,0, demux_,0); + DLOG(INFO)<<"connected udp_source to demux"<connect(demux_, n, char_to_float.at(n), 0); + DLOG(INFO) << "connected demux to char_to_float CH" << n; + } + for (int n = 0; n < RF_channels_; n++) + { + top_block->connect(char_to_float.at(n * 2), 0, float_to_complex_.at(n), 0); + top_block->connect(char_to_float.at(n * 2 + 1), 0, float_to_complex_.at(n), 1); + DLOG(INFO) << "connected char_to_float to float_to_complex_ CH" << n; + } + + if (dump_) + { + top_block->connect(udp_gnss_rx_source_,0, file_sink_dbg_,0); + for (int n = 0; n < RF_channels_; n++) + { + top_block->connect(float_to_complex_.at(n), 0, file_sink_.at(n), 0); + DLOG(INFO) << "connected source to file sink"; + } + } +} + + +void UDPSignalSource::disconnect(gr::top_block_sptr top_block) +{ + + for (int n = 0; n < (RF_channels_ * 2); n++) + { + top_block->disconnect(demux_, n, char_to_float.at(n), 0); + DLOG(INFO) << "disconnect demux to char_to_float CH" << n; + } + for (int n = 0; n < RF_channels_; n++) + { + top_block->disconnect(char_to_float.at(n * 2), 0, float_to_complex_.at(n), 0); + top_block->disconnect(char_to_float.at(n * 2 + 1), 0, float_to_complex_.at(n), 1); + DLOG(INFO) << "disconnect char_to_float to float_to_complex_ CH" << n; + } + + if (dump_) + { + top_block->disconnect(udp_gnss_rx_source_,0, file_sink_dbg_,0); + for (int n = 0; n < RF_channels_; n++) + { + top_block->disconnect(float_to_complex_.at(n), 0, file_sink_.at(n), 0); + DLOG(INFO) << "disconnected source to file sink"; + } + } + top_block->disconnect(udp_gnss_rx_source_,0, demux_,0); + DLOG(INFO)<<"disconnected udp_source to demux"<. + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_UDP_SIGNAL_SOURCE_H +#define GNSS_SDR_UDP_SIGNAL_SOURCE_H + +#include "gnss_block_interface.h" +#include "udp_gnss_rx_source.h" +#include +#include +#include +//#include +#include +#include +#include +#include +#include +#include + + +class ConfigurationInterface; + +/*! + * \brief This class reads from UDP packets, which streams interleaved + * I/Q samples over a network. + */ +class UDPSignalSource : public GNSSBlockInterface +{ +public: + UDPSignalSource(ConfigurationInterface* configuration, + std::string role, unsigned int in_stream, + unsigned int out_stream, boost::shared_ptr queue); + + virtual ~UDPSignalSource(); + + inline std::string role() override + { + return role_; + } + + /*! + * \brief Returns "UDP_Signal_Source" + */ + inline std::string implementation() override + { + return "UDP_Signal_Source"; + } + + inline size_t item_size() override + { + return item_size_; + } + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; + gr::basic_block_sptr get_right_block(int RF_channel) override; + +private: + std::string role_; + + // UDP settings + std::string address_; + int port_; + int RF_channels_; + + unsigned int in_stream_; + unsigned int out_stream_; + + + std::string item_type_; + size_t item_size_; + bool dump_; + std::string dump_filename_; + std::vector> char_to_float; + std::vector> float_to_complex_; + + udp_gnss_rx_source_sptr udp_gnss_rx_source_; + gr::blocks::deinterleave::sptr demux_; + gr::blocks::file_sink::sptr file_sink_dbg_; + std::vector> file_sink_; + boost::shared_ptr queue_; +}; + +#endif /*GNSS_SDR_UDP_SIGNAL_SOURCE_H */ diff --git a/src/algorithms/signal_source/gnuradio_blocks/CMakeLists.txt b/src/algorithms/signal_source/gnuradio_blocks/CMakeLists.txt index a9252edb0..863a90390 100644 --- a/src/algorithms/signal_source/gnuradio_blocks/CMakeLists.txt +++ b/src/algorithms/signal_source/gnuradio_blocks/CMakeLists.txt @@ -25,6 +25,7 @@ set(SIGNAL_SOURCE_GR_BLOCKS_SOURCES unpack_2bit_samples.cc unpack_spir_gss6450_samples.cc labsat23_source.cc + udp_gnss_rx_source.cc ) include_directories( diff --git a/src/algorithms/signal_source/gnuradio_blocks/udp_gnss_rx_source.cc b/src/algorithms/signal_source/gnuradio_blocks/udp_gnss_rx_source.cc new file mode 100644 index 000000000..ef24c829b --- /dev/null +++ b/src/algorithms/signal_source/gnuradio_blocks/udp_gnss_rx_source.cc @@ -0,0 +1,215 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007-2010,2013 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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. + * + * GNU Radio 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 GNU Radio; 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 "udp_gnss_rx_source.h" +#include +#include +#include +#include +#include +#include +#include + +const int udp_gnss_rx_source::BUF_SIZE_PAYLOADS = + gr::prefs::singleton()->get_long("udp_blocks", "buf_size_payloads", 50); + +udp_gnss_rx_source_sptr +make_udp_gnss_rx_source(size_t itemsize, + const std::string &ipaddr, int port, + int payload_size, bool eof) +{ + return gnuradio::get_initial_sptr + (new udp_gnss_rx_source(itemsize, ipaddr, port, + payload_size, eof)); +} + +udp_gnss_rx_source::udp_gnss_rx_source(size_t itemsize, + const std::string &host, int port, + int payload_size, bool eof) +: sync_block("udp_gnss_rx_source", + gr::io_signature::make(0, 0, 0), + gr::io_signature::make(1, 1, itemsize)), + d_itemsize(itemsize), d_payload_size(payload_size), + d_eof(eof), d_connected(false), d_residual(0), d_sent(0), d_offset(0) +{ + // Give us some more room to play. + d_rxbuf = new char[4*d_payload_size]; + d_residbuf = new char[BUF_SIZE_PAYLOADS*d_payload_size]; + + connect(host, port); +} + +udp_gnss_rx_source::~udp_gnss_rx_source() +{ + if(d_connected) + disconnect(); + + delete [] d_rxbuf; + delete [] d_residbuf; +} + +void +udp_gnss_rx_source::connect(const std::string &host, int port) +{ + if(d_connected) + disconnect(); + + d_host = host; + d_port = static_cast(port); + + std::string s_port; + s_port = (boost::format("%d")%d_port).str(); + + if(host.size() > 0) { + boost::asio::ip::udp::resolver resolver(d_io_service); + boost::asio::ip::udp::resolver::query query(d_host, s_port, + boost::asio::ip::resolver_query_base::passive); + d_endpoint = *resolver.resolve(query); + + d_socket = new boost::asio::ip::udp::socket(d_io_service); + d_socket->open(d_endpoint.protocol()); + + boost::asio::socket_base::reuse_address roption(true); + d_socket->set_option(roption); + + d_socket->bind(d_endpoint); + + start_receive(); + d_udp_thread = gr::thread::thread(boost::bind(&udp_gnss_rx_source::run_io_service, this)); + d_connected = true; + } +} + +void +udp_gnss_rx_source::disconnect() +{ + gr::thread::scoped_lock lock(d_setlock); + + if(!d_connected) + return; + + d_io_service.reset(); + d_io_service.stop(); + d_udp_thread.join(); + + d_socket->close(); + delete d_socket; + + d_connected = false; +} + +// Return port number of d_socket +int +udp_gnss_rx_source::get_port(void) +{ + //return d_endpoint.port(); + return d_socket->local_endpoint().port(); +} + +void +udp_gnss_rx_source::start_receive() +{ + d_socket->async_receive_from(boost::asio::buffer((void*)d_rxbuf, d_payload_size), d_endpoint_rcvd, + boost::bind(&udp_gnss_rx_source::handle_read, this, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); +} + +void +udp_gnss_rx_source::handle_read(const boost::system::error_code& error, + size_t bytes_transferred) +{ + if(!error) { + { + boost::lock_guard lock(d_udp_mutex); + if(d_eof && (bytes_transferred == 0)) { + // If we are using EOF notification, test for it and don't + // add anything to the output. + d_residual = WORK_DONE; + d_cond_wait.notify_one(); + return; + } + else { + // Make sure we never go beyond the boundary of the + // residual buffer. This will just drop the last bit of + // data in the buffer if we've run out of room. + if((int)(d_residual + bytes_transferred) >= (BUF_SIZE_PAYLOADS*d_payload_size)) { + GR_LOG_WARN(d_logger, "Too much data; dropping packet."); + } + else { + // otherwise, copy received data into local buffer for + // copying later. + memcpy(d_residbuf+d_residual, d_rxbuf, bytes_transferred); + d_residual += bytes_transferred; + } + } + d_cond_wait.notify_one(); + } + } + start_receive(); +} + +int +udp_gnss_rx_source::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + gr::thread::scoped_lock l(d_setlock); + + char *out = (char*)output_items[0]; + + // Use async receive_from to get data from UDP buffer and wait + // on a conditional signal before proceeding. We use this + // because the conditional wait is interruptable while a + // synchronous receive_from is not. + boost::unique_lock lock(d_udp_mutex); + + //use timed_wait to avoid permanent blocking in the work function + d_cond_wait.timed_wait(lock, boost::posix_time::milliseconds(10)); + + if (d_residual < 0) { + return d_residual; + } + + int bytes_left_in_buffer = (int)(d_residual - d_sent); + int bytes_to_send = std::min(d_itemsize * noutput_items, bytes_left_in_buffer); + + // Copy the received data in the residual buffer to the output stream + memcpy(out, d_residbuf+d_sent, bytes_to_send); + int nitems = bytes_to_send/d_itemsize; + + // Keep track of where we are if we don't have enough output + // space to send all the data in the residbuf. + if (bytes_to_send == bytes_left_in_buffer) { + d_residual = 0; + d_sent = 0; + } + else { + d_sent += bytes_to_send; + } + + return nitems; +} diff --git a/src/algorithms/signal_source/gnuradio_blocks/udp_gnss_rx_source.h b/src/algorithms/signal_source/gnuradio_blocks/udp_gnss_rx_source.h new file mode 100644 index 000000000..5bab10b4a --- /dev/null +++ b/src/algorithms/signal_source/gnuradio_blocks/udp_gnss_rx_source.h @@ -0,0 +1,91 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007-2010,2013 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_GR_UDP_GNSS_RX_SOURCE_IMPL_H +#define INCLUDED_GR_UDP_GNSS_RX_SOURCE_IMPL_H + +#include +#include +#include +#include + +class udp_gnss_rx_source; + +typedef boost::shared_ptr udp_gnss_rx_source_sptr; + +udp_gnss_rx_source_sptr make_udp_gnss_rx_source(size_t itemsize, + const std::string &ipaddr, int port, + int payload_size, bool eof); + + + + class udp_gnss_rx_source : public gr::blocks::udp_source + { + private: + size_t d_itemsize; + int d_payload_size; // maximum transmission unit (packet length) + bool d_eof; // look for an EOF signal + bool d_connected; // are we connected? + char *d_rxbuf; // get UDP buffer items + char *d_residbuf; // hold buffer between calls + ssize_t d_residual; // hold information about number of bytes stored in residbuf + ssize_t d_sent; // track how much of d_residbuf we've outputted + size_t d_offset; // point to residbuf location offset + + static const int BUF_SIZE_PAYLOADS; //!< The d_residbuf size in multiples of d_payload_size + + std::string d_host; + unsigned short d_port; + + boost::asio::ip::udp::socket *d_socket; + boost::asio::ip::udp::endpoint d_endpoint; + boost::asio::ip::udp::endpoint d_endpoint_rcvd; + boost::asio::io_service d_io_service; + + gr::thread::condition_variable d_cond_wait; + gr::thread::mutex d_udp_mutex; + gr::thread::thread d_udp_thread; + + void start_receive(); + void handle_read(const boost::system::error_code& error, + size_t bytes_transferred); + void run_io_service() { d_io_service.run(); } + + public: + udp_gnss_rx_source(size_t itemsize, + const std::string &host, int port, + int payload_size, bool eof); + ~udp_gnss_rx_source(); + + void connect(const std::string &host, int port); + void disconnect(); + + int payload_size() { return d_payload_size; } + int get_port(); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + +#endif /* INCLUDED_GR_UDP_GNSS_RX_SOURCE_H */ diff --git a/src/core/receiver/gnss_block_factory.cc b/src/core/receiver/gnss_block_factory.cc index 09d396b36..7aa1bab99 100644 --- a/src/core/receiver/gnss_block_factory.cc +++ b/src/core/receiver/gnss_block_factory.cc @@ -45,6 +45,7 @@ #include "spir_file_signal_source.h" #include "spir_gss6450_file_signal_source.h" #include "rtl_tcp_signal_source.h" +#include "udp_signal_source.h" #include "two_bit_packed_file_signal_source.h" #include "labsat_signal_source.h" #include "channel.h" @@ -1029,6 +1030,21 @@ std::unique_ptr GNSSBlockFactory::GetBlock( block = std::move(block_); } + catch (const std::exception &e) + { + std::cout << "GNSS-SDR program ended." << std::endl; + exit(1); + } + } + else if (implementation.compare("UDP_Signal_Source") == 0) + { + try + { + std::unique_ptr block_(new UDPSignalSource(configuration.get(), role, in_streams, + out_streams, queue)); + block = std::move(block_); + } + catch (const std::exception &e) { std::cout << "GNSS-SDR program ended." << std::endl;