diff options
-rw-r--r-- | CMakeLists.txt | 4 | ||||
-rw-r--r-- | cmake/Modules/GrVersion.cmake | 21 | ||||
-rw-r--r-- | docs/sphinx/source/blocks_blocks.rst | 1 | ||||
-rw-r--r-- | docs/sphinx/source/index.rst | 1 | ||||
-rw-r--r-- | gnuradio-runtime/lib/prefs.cc | 3 | ||||
-rw-r--r-- | gr-blocks/grc/blocks_block_tree.xml | 1 | ||||
-rw-r--r-- | gr-blocks/grc/blocks_tcp_server_sink.xml | 77 | ||||
-rw-r--r-- | gr-blocks/include/gnuradio/blocks/CMakeLists.txt | 1 | ||||
-rw-r--r-- | gr-blocks/include/gnuradio/blocks/tcp_server_sink.h | 66 | ||||
-rw-r--r-- | gr-blocks/lib/CMakeLists.txt | 1 | ||||
-rw-r--r-- | gr-blocks/lib/tcp_server_sink_impl.cc | 161 | ||||
-rw-r--r-- | gr-blocks/lib/tcp_server_sink_impl.h | 73 | ||||
-rw-r--r-- | gr-blocks/python/blocks/qa_tcp_server_sink.py | 87 | ||||
-rw-r--r-- | gr-blocks/swig/blocks_swig5.i | 3 | ||||
-rw-r--r-- | gr-dtv/lib/dvbt/dvbt_bit_inner_interleaver_impl.cc | 5 | ||||
-rw-r--r-- | gr-uhd/apps/uhd_app.py | 35 | ||||
-rwxr-xr-x | gr-uhd/apps/uhd_fft | 58 | ||||
-rw-r--r-- | gr-uhd/apps/uhd_siggen_base.py | 94 | ||||
-rwxr-xr-x | gr-uhd/apps/uhd_siggen_gui | 33 | ||||
-rw-r--r-- | gr-uhd/lib/usrp_source_impl.cc | 1 |
20 files changed, 643 insertions, 83 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 29e5e00778..e2d997d77a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -72,9 +72,9 @@ ELSE() ENDIF() IF(CMAKE_C_COMPILER_ID STREQUAL "GNU") - SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu11") + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99") ELSEIF(CMAKE_C_COMPILER_ID STREQUAL "Clang") - SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu11") + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99") ELSEIF(CMAKE_C_COMPILER_ID STREQUAL "MSVC") SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11") ELSE() diff --git a/cmake/Modules/GrVersion.cmake b/cmake/Modules/GrVersion.cmake index dceac67bab..414c34d64f 100644 --- a/cmake/Modules/GrVersion.cmake +++ b/cmake/Modules/GrVersion.cmake @@ -33,6 +33,16 @@ set(MAINT_VERSION ${VERSION_INFO_MAINT_VERSION}) ######################################################################## find_package(Git) +MACRO(create_manual_git_describe) + if(NOT GR_GIT_COUNT) + set(GR_GIT_COUNT "compat-xxx") + endif() + if(NOT GR_GIT_HASH) + set(GR_GIT_HASH "xunknown") + endif() + set(GIT_DESCRIBE "v${MAJOR_VERSION}.${API_COMPAT}-${GR_GIT_COUNT}-${GR_GIT_HASH}") +ENDMACRO() + if(GIT_FOUND AND EXISTS ${CMAKE_SOURCE_DIR}/.git) message(STATUS "Extracting version information from git describe...") execute_process( @@ -40,14 +50,11 @@ if(GIT_FOUND AND EXISTS ${CMAKE_SOURCE_DIR}/.git) OUTPUT_VARIABLE GIT_DESCRIBE OUTPUT_STRIP_TRAILING_WHITESPACE WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} ) -else() - if(NOT GR_GIT_COUNT) - set(GR_GIT_COUNT "compat-xxx") - endif() - if(NOT GR_GIT_HASH) - set(GR_GIT_HASH "xunknown") + if(GIT_DESCRIBE STREQUAL "") + create_manual_git_describe() endif() - set(GIT_DESCRIBE "v${MAJOR_VERSION}.${API_COMPAT}-${GR_GIT_COUNT}-${GR_GIT_HASH}") +else() + create_manual_git_describe() endif() ######################################################################## diff --git a/docs/sphinx/source/blocks_blocks.rst b/docs/sphinx/source/blocks_blocks.rst index 056e9efe9a..f214e01c47 100644 --- a/docs/sphinx/source/blocks_blocks.rst +++ b/docs/sphinx/source/blocks_blocks.rst @@ -185,6 +185,7 @@ gnuradio.blocks .. autoblock:: gnuradio.blocks.tagged_stream_mux .. autoblock:: gnuradio.blocks.tagged_stream_to_pdu .. autoblock:: gnuradio.blocks.tags_strobe +.. autoblock:: gnuradio.blocks.tcp_server_sink .. autoblock:: gnuradio.blocks.threshold_ff .. autoblock:: gnuradio.blocks.throttle .. autoblock:: gnuradio.blocks.transcendental diff --git a/docs/sphinx/source/index.rst b/docs/sphinx/source/index.rst index 7bba2f8e32..5c14d22cce 100644 --- a/docs/sphinx/source/index.rst +++ b/docs/sphinx/source/index.rst @@ -854,6 +854,7 @@ Networking Tools Blocks :nosignatures: gnuradio.blocks.socket_pdu + gnuradio.blocks.tcp_server_sink gnuradio.blocks.udp_sink gnuradio.blocks.udp_source diff --git a/gnuradio-runtime/lib/prefs.cc b/gnuradio-runtime/lib/prefs.cc index 341028eba8..18acae0124 100644 --- a/gnuradio-runtime/lib/prefs.cc +++ b/gnuradio-runtime/lib/prefs.cc @@ -30,6 +30,7 @@ #include <algorithm> #include <fstream> +#include <iostream> #include <boost/filesystem/operations.hpp> #include <boost/filesystem/path.hpp> @@ -113,7 +114,7 @@ namespace gr { std::string value = o.value[0]; d_config_map[section][key] = value; } - } catch(const boost::program_options::invalid_config_file_syntax & e) { + } catch(std::exception e) { std::cerr << "WARNING: Config file '" << fname << "' failed to parse:" << std::endl; std::cerr << e.what() << std::endl; std::cerr << "Skipping it" << std::endl; diff --git a/gr-blocks/grc/blocks_block_tree.xml b/gr-blocks/grc/blocks_block_tree.xml index c4857f3b3a..644773f686 100644 --- a/gr-blocks/grc/blocks_block_tree.xml +++ b/gr-blocks/grc/blocks_block_tree.xml @@ -158,6 +158,7 @@ <name>Networking Tools</name> <block>blocks_tuntap_pdu</block> <block>blocks_socket_pdu</block> + <block>blocks_tcp_server_sink</block> <block>blocks_udp_source</block> <block>blocks_udp_sink</block> </cat> diff --git a/gr-blocks/grc/blocks_tcp_server_sink.xml b/gr-blocks/grc/blocks_tcp_server_sink.xml new file mode 100644 index 0000000000..644027da65 --- /dev/null +++ b/gr-blocks/grc/blocks_tcp_server_sink.xml @@ -0,0 +1,77 @@ +<?xml version="1.0"?> +<!-- +################################################### +##TCP Server Sink +################################################### + --> +<block> + <name>TCP Server Sink</name> + <key>blocks_tcp_server_sink</key> + <import>from gnuradio import blocks</import> + <make>blocks.tcp_server_sink($type.size*$vlen, $ipaddr, $port, $noblock)</make> + <param> + <name>Input Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>size:gr.sizeof_gr_complex</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>size:gr.sizeof_float</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>size:gr.sizeof_int</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>size:gr.sizeof_short</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>size:gr.sizeof_char</opt> + </option> + </param> + <param> + <name>Destination IP Address</name> + <key>ipaddr</key> + <type>string</type> + </param> + <param> + <name>Destination Port</name> + <key>port</key> + <type>int</type> + </param> + <param> + <name>Nonblocking Mode</name> + <key>noblock</key> + <type>enum</type> + <option> + <name>On</name> + <key>True</key> + </option> + <option> + <name>Off</name> + <key>False</key> + </option> + </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <check>$vlen > 0</check> + <sink> + <name>in</name> + <type>$type</type> + <vlen>$vlen</vlen> + </sink> +</block> diff --git a/gr-blocks/include/gnuradio/blocks/CMakeLists.txt b/gr-blocks/include/gnuradio/blocks/CMakeLists.txt index 38c79d60f3..6b3eca69d3 100644 --- a/gr-blocks/include/gnuradio/blocks/CMakeLists.txt +++ b/gr-blocks/include/gnuradio/blocks/CMakeLists.txt @@ -174,6 +174,7 @@ install(FILES tagged_stream_multiply_length.h tagged_stream_to_pdu.h tags_strobe.h + tcp_server_sink.h test_tag_variable_rate_ff.h threshold_ff.h throttle.h diff --git a/gr-blocks/include/gnuradio/blocks/tcp_server_sink.h b/gr-blocks/include/gnuradio/blocks/tcp_server_sink.h new file mode 100644 index 0000000000..6d951a8e67 --- /dev/null +++ b/gr-blocks/include/gnuradio/blocks/tcp_server_sink.h @@ -0,0 +1,66 @@ +/* -*- c++ -*- */ +/* + * Copyright 2014 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_BLOCKS_TCP_SERVER_SINK_H +#define INCLUDED_BLOCKS_TCP_SERVER_SINK_H + +#include <gnuradio/blocks/api.h> +#include <gnuradio/sync_block.h> + +namespace gr { + namespace blocks { + + /*! + * \brief Send stream trought an TCP socket. + * \ingroup networking_tools_blk + * + * \details + * Listen for incomming TCP connection(s). Duplicate data for each + * opened connection. Optionaly can wait until first client connects + * before streaming starts. + */ + class BLOCKS_API tcp_server_sink : virtual public gr::sync_block + { + public: + // gr::blocks::tcp_server_sink::sptr + typedef boost::shared_ptr<tcp_server_sink> sptr; + + /*! + * \brief TCP Server Sink Constructor + * + * \param itemsize The size (in bytes) of the item datatype + * \param host The name or IP address of interface to bind to. + * \param port Port where to listen. + * \param noblock If false, wait until first client connects before + * streaming starts. In non blocking mode + * (noblock=true), drop data onto floor if no client + * is connected. + */ + static sptr make(size_t itemsize, + const std::string &host, int port, + bool noblock = false); + }; + + } /* namespace blocks */ +} /* namespace gr */ + +#endif /* INCLUDED_BLOCKS_TCP_SERVER_SINK_H */ diff --git a/gr-blocks/lib/CMakeLists.txt b/gr-blocks/lib/CMakeLists.txt index 643190c2ee..1d69f27a1d 100644 --- a/gr-blocks/lib/CMakeLists.txt +++ b/gr-blocks/lib/CMakeLists.txt @@ -199,6 +199,7 @@ list(APPEND gr_blocks_sources throttle_impl.cc transcendental_impl.cc tcp_connection.cc + tcp_server_sink_impl.cc tuntap_pdu_impl.cc tag_gate_impl.cc tagged_stream_align_impl.cc diff --git a/gr-blocks/lib/tcp_server_sink_impl.cc b/gr-blocks/lib/tcp_server_sink_impl.cc new file mode 100644 index 0000000000..329e798ca8 --- /dev/null +++ b/gr-blocks/lib/tcp_server_sink_impl.cc @@ -0,0 +1,161 @@ +/* -*- 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 "tcp_server_sink_impl.h" +#include <gnuradio/io_signature.h> +#include <algorithm> +#include <boost/array.hpp> +#include <boost/asio.hpp> +#include <boost/format.hpp> +#include <gnuradio/thread/thread.h> +#include <stdexcept> +#include <stdio.h> +#include <string.h> + +namespace gr { + namespace blocks { + + tcp_server_sink::sptr + tcp_server_sink::make(size_t itemsize, + const std::string &host, int port, + bool noblock) + { + return gnuradio::get_initial_sptr + (new tcp_server_sink_impl(itemsize, host, port, noblock)); + } + + tcp_server_sink_impl::tcp_server_sink_impl(size_t itemsize, + const std::string &host, int port, + bool noblock) + : sync_block("tcp_server_sink", + io_signature::make(1, 1, itemsize), + io_signature::make(0, 0, 0)), + d_itemsize(itemsize), + d_acceptor(d_io_service), + d_buf(new uint8_t[BUF_SIZE]), + d_writing(0) + { + std::string s_port = (boost::format("%d") % port).str(); + std::string s_host = host.empty() ? std::string("localhost") : host; + boost::asio::ip::tcp::resolver resolver(d_io_service); + boost::asio::ip::tcp::resolver::query query(s_host, s_port, + boost::asio::ip::resolver_query_base::passive); + d_endpoint = *resolver.resolve(query); + + d_acceptor.open(d_endpoint.protocol()); + d_acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); + d_acceptor.bind(d_endpoint); + d_acceptor.listen(); + + if (!noblock) { + d_socket.reset(new boost::asio::ip::tcp::socket(d_io_service)); + d_acceptor.accept(*d_socket, d_endpoint); + d_sockets.insert(d_socket.release()); + } + + d_socket.reset(new boost::asio::ip::tcp::socket(d_io_service)); + d_acceptor.async_accept(*d_socket, boost::bind(&tcp_server_sink_impl::do_accept, + this, boost::asio::placeholders::error)); + d_io_serv_thread = boost::thread( + boost::bind(&boost::asio::io_service::run, &d_io_service)); + } + + void + tcp_server_sink_impl::do_accept(const boost::system::error_code& error) + { + if (!error) { + gr::thread::scoped_lock guard(d_writing_mut); + d_sockets.insert(d_socket.release()); + d_socket.reset(new boost::asio::ip::tcp::socket(d_io_service)); + d_acceptor.async_accept(*d_socket, boost::bind(&tcp_server_sink_impl::do_accept, + this, boost::asio::placeholders::error)); + } + } + + void + tcp_server_sink_impl::do_write(const boost::system::error_code& error, + size_t len, std::set<boost::asio::ip::tcp::socket *>::iterator i) + { + { + gr::thread::scoped_lock guard(d_writing_mut); + --d_writing; + if (error) { + delete *i; + d_sockets.erase(i); + } + } + d_writing_cond.notify_one(); + } + + tcp_server_sink_impl::~tcp_server_sink_impl() + { + gr::thread::scoped_lock guard(d_writing_mut); + while (d_writing) { + d_writing_cond.wait(guard); + } + + for (std::set<boost::asio::ip::tcp::socket *>::iterator i = d_sockets.begin(); + i != d_sockets.end(); ++i ) { + delete *i; + } + d_sockets.clear(); + + d_io_service.reset(); + d_io_service.stop(); + d_io_serv_thread.join(); + } + + int + tcp_server_sink_impl::work (int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const char *in = (const char *) input_items[0]; + + gr::thread::scoped_lock guard(d_writing_mut); + while (d_writing) { + d_writing_cond.wait(guard); + } + + size_t data_len = std::min(size_t(BUF_SIZE), noutput_items * d_itemsize); + data_len -= data_len % d_itemsize; + memcpy(d_buf.get(), in, data_len); + for (std::set<boost::asio::ip::tcp::socket *>::iterator i = d_sockets.begin(); + i != d_sockets.end(); ++i ) { + boost::asio::async_write(**i, boost::asio::buffer(d_buf.get(), data_len), + boost::bind(&tcp_server_sink_impl::do_write, this, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + i)); + } + d_writing = d_sockets.size(); + + return data_len / d_itemsize; + } + + } /* namespace blocks */ +} /* namespace gr */ + diff --git a/gr-blocks/lib/tcp_server_sink_impl.h b/gr-blocks/lib/tcp_server_sink_impl.h new file mode 100644 index 0000000000..d10f3b95b8 --- /dev/null +++ b/gr-blocks/lib/tcp_server_sink_impl.h @@ -0,0 +1,73 @@ +/* -*- c++ -*- */ +/* + * Copyright 2014 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_TCP_SERVER_SINK_IMPL_H +#define INCLUDED_GR_TCP_SERVER_SINK_IMPL_H + +#include <gnuradio/blocks/tcp_server_sink.h> +#include <boost/asio.hpp> +#include <set> +#include <boost/ptr_container/ptr_vector.hpp> + +namespace gr { + namespace blocks { + + class tcp_server_sink_impl : public tcp_server_sink + { + private: + size_t d_itemsize; + + boost::asio::io_service d_io_service; + gr::thread::thread d_io_serv_thread; + boost::asio::ip::tcp::endpoint d_endpoint; + std::auto_ptr<boost::asio::ip::tcp::socket> d_socket; + std::set<boost::asio::ip::tcp::socket *> d_sockets; + boost::asio::ip::tcp::acceptor d_acceptor; + + boost::shared_ptr<uint8_t> d_buf; + enum { + BUF_SIZE = 256 * 1024, + }; + + int d_writing; + boost::condition_variable d_writing_cond; + boost::mutex d_writing_mut; + + void do_accept(const boost::system::error_code& error); + void do_write(const boost::system::error_code& error, std::size_t len, + std::set<boost::asio::ip::tcp::socket *>::iterator); + + public: + tcp_server_sink_impl(size_t itemsize, + const std::string &host, int port, + bool noblock); + ~tcp_server_sink_impl(); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } /* namespace blocks */ +} /* namespace gr */ + +#endif /* INCLUDED_GR_TCP_SERVER_SINK_IMPL_H */ diff --git a/gr-blocks/python/blocks/qa_tcp_server_sink.py b/gr-blocks/python/blocks/qa_tcp_server_sink.py new file mode 100644 index 0000000000..f7d3a0af92 --- /dev/null +++ b/gr-blocks/python/blocks/qa_tcp_server_sink.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python +# +# Copyright 2014 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. +# + +from gnuradio import gr, gr_unittest, blocks +import os +import socket +from time import sleep + +from threading import Timer +from multiprocessing import Process + +class test_tcp_sink(gr_unittest.TestCase): + + def setUp(self): + os.environ['GR_CONF_CONTROLPORT_ON'] = 'False' + self.tb_snd = gr.top_block() + self.tb_rcv = gr.top_block() + + def tearDown(self): + self.tb_rcv = None + self.tb_snd = None + + def _tcp_client(self): + dst = blocks.vector_sink_s() + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + for t in (0, 0.2): +# wait until server listens + sleep(t) + try: + sock.connect((self.addr, self.port)) + except socket.error as e: + if e.errno != 111: + raise + continue + break + fd = os.dup(sock.fileno()) + self.tb_rcv.connect(blocks.file_descriptor_source(self.itemsize, fd), dst) + self.tb_rcv.run() + self.assertEqual(self.data, dst.data()) + + def test_001(self): + self.addr = '127.0.0.1' + self.port = 65510 + self.itemsize = gr.sizeof_short + n_data = 16 + self.data = tuple([x for x in range(n_data)]) + +# tcp_server_sink blocks until client does not connect, start client process first + p = Process(target=self._tcp_client) + p.start() + + src = blocks.vector_source_s(self.data, False) + tcp_snd = blocks.tcp_server_sink(self.itemsize, self.addr, self.port, False) + self.tb_snd.connect(src, tcp_snd) + + self.tb_snd.run() + del tcp_snd + self.tb_snd = None + p.join() + + def stop_rcv(self): + self.timeout = True + self.tb_rcv.stop() + #print "tb_rcv stopped by Timer" + +if __name__ == '__main__': + gr_unittest.run(test_tcp_sink, "test_tcp_server_sink.xml") + diff --git a/gr-blocks/swig/blocks_swig5.i b/gr-blocks/swig/blocks_swig5.i index 51601a8c30..761b0a855a 100644 --- a/gr-blocks/swig/blocks_swig5.i +++ b/gr-blocks/swig/blocks_swig5.i @@ -56,6 +56,7 @@ #include "gnuradio/blocks/tagged_stream_multiply_length.h" #include "gnuradio/blocks/tagged_stream_to_pdu.h" #include "gnuradio/blocks/tags_strobe.h" +#include "gnuradio/blocks/tcp_server_sink.h" #include "gnuradio/blocks/test_tag_variable_rate_ff.h" #include "gnuradio/blocks/threshold_ff.h" #include "gnuradio/blocks/transcendental.h" @@ -100,6 +101,7 @@ %include "gnuradio/blocks/tagged_stream_multiply_length.h" %include "gnuradio/blocks/tagged_stream_to_pdu.h" %include "gnuradio/blocks/tags_strobe.h" +%include "gnuradio/blocks/tcp_server_sink.h" %include "gnuradio/blocks/test_tag_variable_rate_ff.h" %include "gnuradio/blocks/threshold_ff.h" %include "gnuradio/blocks/transcendental.h" @@ -143,6 +145,7 @@ GR_SWIG_BLOCK_MAGIC2(blocks, tagged_stream_mux); GR_SWIG_BLOCK_MAGIC2(blocks, tagged_stream_multiply_length); GR_SWIG_BLOCK_MAGIC2(blocks, tagged_stream_to_pdu); GR_SWIG_BLOCK_MAGIC2(blocks, tags_strobe); +GR_SWIG_BLOCK_MAGIC2(blocks, tcp_server_sink); GR_SWIG_BLOCK_MAGIC2(blocks, test_tag_variable_rate_ff); GR_SWIG_BLOCK_MAGIC2(blocks, threshold_ff); GR_SWIG_BLOCK_MAGIC2(blocks, transcendental); diff --git a/gr-dtv/lib/dvbt/dvbt_bit_inner_interleaver_impl.cc b/gr-dtv/lib/dvbt/dvbt_bit_inner_interleaver_impl.cc index d2bfb3d9d2..a5a9847812 100644 --- a/gr-dtv/lib/dvbt/dvbt_bit_inner_interleaver_impl.cc +++ b/gr-dtv/lib/dvbt/dvbt_bit_inner_interleaver_impl.cc @@ -118,8 +118,9 @@ namespace gr { void dvbt_bit_inner_interleaver_impl::forecast (int noutput_items, gr_vector_int &ninput_items_required) { - ninput_items_required[0] = noutput_items; - ninput_items_required[1] = noutput_items; + unsigned ninputs = ninput_items_required.size(); + for (unsigned i = 0; i < ninputs; i++) + ninput_items_required[i] = noutput_items; } int diff --git a/gr-uhd/apps/uhd_app.py b/gr-uhd/apps/uhd_app.py index ff4412a140..652a9fbab6 100644 --- a/gr-uhd/apps/uhd_app.py +++ b/gr-uhd/apps/uhd_app.py @@ -42,12 +42,25 @@ LONG_TPL = """{prefix} Motherboard: {mb_id} ({mb_serial}) """ class UHDApp(object): + " Base class for simple UHD-based applications " def __init__(self, prefix=None, args=None): self.prefix = prefix self.args = args self.verbose = args.verbose or 0 if self.args.sync == 'auto' and len(self.args.channels) > 1: self.args.sync = 'pps' + self.antenna = None + self.gain_range = None + self.samp_rate = None + self.has_lo_sensor = None + self.async_msgq = None + self.async_src = None + self.async_rcv = None + self.tr = None + self.gain = None + self.freq = None + self.channels = None + self.cpu_format = None def vprint(self, *args): """ @@ -78,7 +91,7 @@ class UHDApp(object): if info_pp['mb_serial'] == "": info_pp['mb_serial'] = "no serial" info_pp['db_subdev'] = usrp_info["{xx}_subdev_name".format(xx=tx_or_rx)] - info_pp['db_serial'] = ", " + usrp_info["{xx}_serial".format(xx=tx_or_rx)] + info_pp['db_serial'] = ", " + usrp_info["{xx}_serial".format(xx=tx_or_rx)] if info_pp['db_serial'] == "": info_pp['db_serial'] = "no serial" info_pp['subdev'] = self.usrp.get_subdev_spec(mboard) @@ -112,12 +125,12 @@ class UHDApp(object): """ Call this when USRP async metadata needs printing. """ - md = self.async_src.msg_to_async_metadata_t(msg) + metadata = self.async_src.msg_to_async_metadata_t(msg) print("[{prefix}] Channel: {chan} Time: {t} Event: {e}".format( prefix=self.prefix, - chan=md.channel, - t=md.time_spec.get_real_secs(), - e=md.event_code, + chan=metadata.channel, + t=metadata.time_spec.get_real_secs(), + e=metadata.event_code, )) def setup_usrp(self, ctor, args, cpu_format='fc32'): @@ -141,9 +154,13 @@ class UHDApp(object): if args.spec: for mb_idx in xrange(self.usrp.get_num_mboards()): self.usrp.set_subdev_spec(args.spec, mb_idx) - # Set the clock source: + # Set the clock and/or time source: if args.clock_source is not None: - self.usrp.set_clock_source(args.clock_source) + for mb_idx in xrange(self.usrp.get_num_mboards()): + self.usrp.set_clock_source(args.clock_source, mb_idx) + if args.time_source is not None: + for mb_idx in xrange(self.usrp.get_num_mboards()): + self.usrp.set_time_source(args.time_source, mb_idx) # Sampling rate: self.usrp.set_samp_rate(args.samp_rate) self.samp_rate = self.usrp.get_samp_rate() @@ -153,7 +170,7 @@ class UHDApp(object): if self.antenna is not None: for i, chan in enumerate(self.channels): if not self.antenna[i] in self.usrp.get_antennas(chan): - self.vprint("[ERROR] {} is not a valid antenna name for this USRP device!".format(ant)) + self.vprint("[ERROR] {} is not a valid antenna name for this USRP device!".format(self.antenna[i])) exit(1) self.usrp.set_antenna(self.antenna[i], chan) self.vprint("[{prefix}] Channel {chan}: Using antenna {ant}.".format( @@ -310,5 +327,7 @@ class UHDApp(object): default='auto', help="Set to 'pps' to sync devices to PPS") group.add_argument("--clock-source", help="Set the clock source; typically 'internal', 'external' or 'gpsdo'") + group.add_argument("--time-source", + help="Set the time source") return parser diff --git a/gr-uhd/apps/uhd_fft b/gr-uhd/apps/uhd_fft index bb557e96f0..aa10cdf900 100755 --- a/gr-uhd/apps/uhd_fft +++ b/gr-uhd/apps/uhd_fft @@ -1,6 +1,6 @@ #!/usr/bin/env python2 # -# Copyright 2015 Free Software Foundation, Inc. +# Copyright 2015-2016 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -277,7 +277,37 @@ class uhd_fft(gr.top_block, Qt.QWidget, UHDApp): _freeze_scope_thread = threading.Thread(target=lambda: _freeze_scaling(self.qtgui_time_sink_x_0, 2.0)) _freeze_scope_thread.daemon = True _freeze_scope_thread.start() - + if args.phase_relations and len(self.channels) > 1: + self.display_widget_phase = Qt.QWidget() + self.display_layout_phase = Qt.QBoxLayout(Qt.QBoxLayout.TopToBottom, self.display_widget_phase) + self.display_grid_layout_phase = Qt.QGridLayout() + self.display_layout_phase.addLayout(self.display_grid_layout_phase) + self.display.addTab(self.display_widget_phase, "Rel. Phase") + self.qtgui_phase_plot = qtgui.time_sink_f( + 1024, #size + self.samp_rate, #samp_rate + "", #name + len(self.channels) - 1 + ) + self.qtgui_phase_plot.set_update_time(self.update_rate) + self.qtgui_phase_plot.set_y_axis(-3.5, 3.5) + self.qtgui_phase_plot.set_y_label("Relative Phase", "") + self.qtgui_phase_plot.enable_tags(-1, True) + self.qtgui_phase_plot.set_trigger_mode(qtgui.TRIG_MODE_FREE, qtgui.TRIG_SLOPE_POS, 0.0, 0, 0, "") + self.qtgui_phase_plot.enable_autoscale(False) + self.qtgui_phase_plot.enable_grid(True) + self.qtgui_phase_plot.enable_control_panel(True) + self.qtgui_phase_plot.disable_legend() + for i in xrange(len(self.channels) - 1): + self.qtgui_phase_plot.set_line_label(i, "Phase Delta Channels {0}/{1}".format(i, i+1)) + self.qtgui_phase_plot.set_line_width(i, widths[i]) + self.qtgui_phase_plot.set_line_color(i, colors[i]) + self.qtgui_phase_plot.set_line_style(i, styles[i]) + self.qtgui_phase_plot.set_line_marker(i, markers[i]) + self.qtgui_phase_plot.set_line_alpha(i, alphas[i]) + self._qtgui_phase_plot_win = sip.wrapinstance(self.qtgui_phase_plot.pyqwidget(), Qt.QWidget) + self.display_grid_layout_phase.addWidget(self._qtgui_phase_plot_win, 0,0,1,4) + ### Other widgets ################################################### self._lo_locked_probe_tool_bar = Qt.QToolBar(self) self._lo_locked_probe_formatter = lambda x: {True: 'Yes', False: 'No'}[x] if self.has_lo_sensor: @@ -317,10 +347,24 @@ class uhd_fft(gr.top_block, Qt.QWidget, UHDApp): ################################################## self.msg_connect((self.qtgui_freq_sink_x_0, 'freq'), (self.qtgui_freq_sink_x_0, 'freq')) self.msg_connect((self.qtgui_freq_sink_x_0, 'freq'), (self.usrp, 'command')) - for c in self.channels: - self.connect((self.usrp, c), (self.qtgui_freq_sink_x_0, c)) - self.connect((self.usrp, c), (self.qtgui_time_sink_x_0, c)) - self.connect((self.usrp, c), (self.qtgui_waterfall_sink_x_0, c)) + for c, idx in enumerate(self.channels): + self.connect((self.usrp, c), (self.qtgui_freq_sink_x_0, idx)) + self.connect((self.usrp, c), (self.qtgui_time_sink_x_0, idx)) + self.connect((self.usrp, c), (self.qtgui_waterfall_sink_x_0, idx)) + if args.phase_relations and len(self.channels) > 1: + for c, idx in enumerate(self.channels[:-1]): + self.connect_phase_plot( + (self.usrp, c), + (self.usrp, self.channels[idx+1]), + (self.qtgui_phase_plot, idx) + ) + + def connect_phase_plot(self, src_port1, src_port2, dst_port): + " Calculate relative phase between two src ports and send it dst_port " + from gnuradio import blocks + multiplier = blocks.multiply_cc() + self.connect(src_port1, (multiplier, 0), blocks.complex_to_arg(), dst_port) + self.connect(src_port2, blocks.conjugate_cc(), (multiplier, 1)) def closeEvent(self, event): self.settings = Qt.QSettings("GNU Radio", "uhd_fft") @@ -417,6 +461,8 @@ def setup_argparser(): help="Specify FFT average alpha (overrides --fft-average)") group.add_argument("--update-rate", dest="update_rate", type=eng_arg.eng_float, default=eng_notation.num_to_str(.1), help="Set GUI widget update rate") + group.add_argument("--phase-relations", action="store_true", + help="Plot relative phases between multiple channels") return parser diff --git a/gr-uhd/apps/uhd_siggen_base.py b/gr-uhd/apps/uhd_siggen_base.py index 31415dac41..cc699dd145 100644 --- a/gr-uhd/apps/uhd_siggen_base.py +++ b/gr-uhd/apps/uhd_siggen_base.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python # # Copyright 2008,2009,2011,2012,2015 Free Software Foundation, Inc. # @@ -23,6 +23,17 @@ Provide a base flow graph for USRP signal generators. """ +from __future__ import print_function +import math +try: + from uhd_app import UHDApp +except ImportError: + from gnuradio.uhd.uhd_app import UHDApp +from gnuradio import gr, uhd, eng_notation, eng_arg +from gnuradio import analog +from gnuradio import blocks +from gnuradio.gr.pubsub import pubsub + DESC_KEY = 'desc' SAMP_RATE_KEY = 'samp_rate' LINK_RATE_KEY = 'link_rate' @@ -39,26 +50,9 @@ FREQ_RANGE_KEY = 'freq_range' GAIN_RANGE_KEY = 'gain_range' TYPE_KEY = 'type' -# FIXME figure out if this can be deleted -#def setter(ps, key, val): ps[key] = val - -import sys -import math -import argparse -try: - from uhd_app import UHDApp -except ImportError: - from gnuradio.uhd.uhd_app import UHDApp -from gnuradio import gr, gru, uhd, eng_notation, eng_arg -from gnuradio import analog -from gnuradio import blocks -from gnuradio.gr.pubsub import pubsub -from gnuradio.eng_option import eng_option -from optparse import OptionParser - n2s = eng_notation.num_to_str -waveforms = { +WAVEFORMS = { analog.GR_CONST_WAVE : "Constant", analog.GR_SIN_WAVE : "Complex Sinusoid", analog.GR_GAUSSIAN : "Gaussian Noise", @@ -78,6 +72,11 @@ class USRPSiggen(gr.top_block, pubsub, UHDApp): UHDApp.__init__(self, args=args, prefix="UHD-SIGGEN") self.extra_sink = None + # Allocate some attributes + self._src1 = None + self._src2 = None + self._src = None + # Initialize device: self.setup_usrp( ctor=uhd.usrp_sink, @@ -121,13 +120,13 @@ class USRPSiggen(gr.top_block, pubsub, UHDApp): self[key] = self[key] self[TYPE_KEY] = args.type #set type last - def set_samp_rate(self, sr): + def set_samp_rate(self, samp_rate): """ When sampling rate is updated, also update the signal sources. """ - self.vprint("Setting sampling rate to: {rate} Msps".format(rate=sr/1e6)) - self.usrp.set_samp_rate(sr) - sr = self.usrp.get_samp_rate() + self.vprint("Setting sampling rate to: {rate} Msps".format(rate=samp_rate/1e6)) + self.usrp.set_samp_rate(samp_rate) + samp_rate = self.usrp.get_samp_rate() if self[TYPE_KEY] in (analog.GR_SIN_WAVE, analog.GR_CONST_WAVE): self._src.set_sampling_freq(self[SAMP_RATE_KEY]) elif self[TYPE_KEY] == "2tone": @@ -138,10 +137,11 @@ class USRPSiggen(gr.top_block, pubsub, UHDApp): self._src2.set_sampling_freq(self[WAVEFORM_FREQ_KEY]*2*math.pi/self[SAMP_RATE_KEY]) else: return True # Waveform not yet set - self.vprint("Set sample rate to: {rate} Msps".format(rate=sr/1e6)) + self.vprint("Set sample rate to: {rate} Msps".format(rate=samp_rate/1e6)) return True def set_waveform_freq(self, freq): + " Change the frequency 1 of the generated waveform " if self[TYPE_KEY] == analog.GR_SIN_WAVE: self._src.set_frequency(freq) elif self[TYPE_KEY] == "2tone": @@ -152,6 +152,10 @@ class USRPSiggen(gr.top_block, pubsub, UHDApp): return True def set_waveform2_freq(self, freq): + """ + Change the frequency 2 of the generated waveform. This only + applies to 2-tone and sweep. + """ if freq is None: self[WAVEFORM2_FREQ_KEY] = -self[WAVEFORM_FREQ_KEY] return @@ -161,19 +165,22 @@ class USRPSiggen(gr.top_block, pubsub, UHDApp): self._src1.set_frequency(freq) return True - def set_waveform(self, type): + def set_waveform(self, waveform_type): + """ + Select the generated waveform + """ self.vprint("Selecting waveform...") self.lock() self.disconnect_all() - if type == analog.GR_SIN_WAVE or type == analog.GR_CONST_WAVE: + if waveform_type == analog.GR_SIN_WAVE or waveform_type == analog.GR_CONST_WAVE: self._src = analog.sig_source_c(self[SAMP_RATE_KEY], # Sample rate - type, # Waveform type + waveform_type, # Waveform waveform_type self[WAVEFORM_FREQ_KEY], # Waveform frequency self[AMPLITUDE_KEY], # Waveform amplitude self[WAVEFORM_OFFSET_KEY]) # Waveform offset - elif type == analog.GR_GAUSSIAN or type == analog.GR_UNIFORM: - self._src = analog.noise_source_c(type, self[AMPLITUDE_KEY]) - elif type == "2tone": + elif waveform_type == analog.GR_GAUSSIAN or waveform_type == analog.GR_UNIFORM: + self._src = analog.noise_source_c(waveform_type, self[AMPLITUDE_KEY]) + elif waveform_type == "2tone": self._src1 = analog.sig_source_c(self[SAMP_RATE_KEY], analog.GR_SIN_WAVE, self[WAVEFORM_FREQ_KEY], @@ -187,9 +194,9 @@ class USRPSiggen(gr.top_block, pubsub, UHDApp): self[AMPLITUDE_KEY]/2.0, 0) self._src = blocks.add_cc() - self.connect(self._src1,(self._src,0)) - self.connect(self._src2,(self._src,1)) - elif type == "sweep": + self.connect(self._src1, (self._src, 0)) + self.connect(self._src2, (self._src, 1)) + elif waveform_type == "sweep": # rf freq is center frequency # waveform_freq is total swept width # waveform2_freq is sweep rate @@ -205,21 +212,21 @@ class USRPSiggen(gr.top_block, pubsub, UHDApp): self._src = blocks.multiply_const_cc(self[AMPLITUDE_KEY]) self.connect(self._src1, self._src2, self._src) else: - raise RuntimeError("[UHD-SIGGEN] Unknown waveform type") - for c in xrange(len(self.channels)): - self.connect(self._src, (self.usrp, c)) + raise RuntimeError("[UHD-SIGGEN] Unknown waveform waveform_type") + for chan in xrange(len(self.channels)): + self.connect(self._src, (self.usrp, chan)) if self.extra_sink is not None: self.connect(self._src, self.extra_sink) self.unlock() - self.vprint("Set baseband modulation to:", waveforms[type]) - if type == analog.GR_SIN_WAVE: + self.vprint("Set baseband modulation to:", WAVEFORMS[waveform_type]) + if waveform_type == analog.GR_SIN_WAVE: self.vprint("Modulation frequency: %sHz" % (n2s(self[WAVEFORM_FREQ_KEY]),)) self.vprint("Initial phase:", self[WAVEFORM_OFFSET_KEY]) - elif type == "2tone": + elif waveform_type == "2tone": self.vprint("Tone 1: %sHz" % (n2s(self[WAVEFORM_FREQ_KEY]),)) self.vprint("Tone 2: %sHz" % (n2s(self[WAVEFORM2_FREQ_KEY]),)) - elif type == "sweep": - self.vprint("Sweeping across %sHz to %sHz" % (n2s(-self[WAVEFORM_FREQ_KEY]/2.0),n2s(self[WAVEFORM_FREQ_KEY]/2.0))) + elif waveform_type == "sweep": + self.vprint("Sweeping across %sHz to %sHz" % (n2s(-self[WAVEFORM_FREQ_KEY]/2.0), n2s(self[WAVEFORM_FREQ_KEY]/2.0))) self.vprint("Sweep rate: %sHz" % (n2s(self[WAVEFORM2_FREQ_KEY]),)) self.vprint("TX amplitude:", self[AMPLITUDE_KEY]) @@ -274,6 +281,7 @@ def setup_argparser(): return parser def main(): + " Go, go, go! " if gr.enable_realtime_scheduling() != gr.RT_OK: print("Note: failed to enable realtime scheduling, continuing") # Grab command line args and create top block @@ -281,8 +289,8 @@ def main(): parser = setup_argparser() args = parser.parse_args() tb = USRPSiggen(args) - except RuntimeError as e: - print(e) + except RuntimeError as ex: + print(ex) exit(1) tb.start() raw_input('[UHD-SIGGEN] Press Enter to quit:\n') diff --git a/gr-uhd/apps/uhd_siggen_gui b/gr-uhd/apps/uhd_siggen_gui index ab04ccc8e2..c5528f3777 100755 --- a/gr-uhd/apps/uhd_siggen_gui +++ b/gr-uhd/apps/uhd_siggen_gui @@ -1,6 +1,6 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python # -# Copyright 2015 Free Software Foundation, Inc. +# Copyright 2015-2016 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -32,13 +32,14 @@ Signal Generator App # Generated: Sun Jun 28 17:21:28 2015 ################################################## +from __future__ import print_function import sip import sys import threading import time from distutils.version import StrictVersion from PyQt4 import Qt -from PyQt4.QtCore import QObject, pyqtSlot +from PyQt4.QtCore import pyqtSlot from gnuradio import analog from gnuradio import eng_notation from gnuradio import gr @@ -69,9 +70,9 @@ class uhd_siggen_gui(Qt.QWidget): Qt.QWidget.__init__(self) self.setWindowTitle("UHD Signal Generator") try: - self.setWindowIcon(Qt.QIcon.fromTheme('gnuradio-grc')) + self.setWindowIcon(Qt.QIcon.fromTheme('gnuradio-grc')) except: - pass + pass self.top_scroll_layout = Qt.QVBoxLayout() self.setLayout(self.top_scroll_layout) self.top_scroll = Qt.QScrollArea() @@ -90,8 +91,8 @@ class uhd_siggen_gui(Qt.QWidget): # Widgets + Controls ################################################## ### Waveform Selector - self._waveform_options = uhd_siggen.waveforms.keys() - self._waveform_labels = uhd_siggen.waveforms.values() + self._waveform_options = uhd_siggen.WAVEFORMS.keys() + self._waveform_labels = uhd_siggen.WAVEFORMS.values() self._waveform_group_box = Qt.QGroupBox("Waveform") self._waveform_box = Qt.QHBoxLayout() class variable_chooser_button_group(Qt.QButtonGroup): @@ -259,11 +260,12 @@ class uhd_siggen_gui(Qt.QWidget): self._lo_locked_probe_0_tool_bar.addWidget(self._lo_locked_probe_0_label) self.top_grid_layout.addWidget(self._lo_locked_probe_0_tool_bar, 8,0,1,1) def _chan0_lo_locked_probe(): + " Monitor lock status of LO on channel 0 " while True: - val = all([self.usrp.get_sensor('lo_locked', c).to_bool() for c in range(len(self._sg.channels))]) try: + val = all([self.usrp.get_sensor('lo_locked', c).to_bool() for c in range(len(self._sg.channels))]) self.set_chan0_lo_locked(val) - except AttributeError: + except: pass time.sleep(.1) _chan0_lo_locked_thread = threading.Thread(target=_chan0_lo_locked_probe) @@ -366,8 +368,8 @@ class uhd_siggen_gui(Qt.QWidget): self.freq_fine + self.freq_coarse, self.lo_offset ) - for idx, c in enumerate(self._sg.channels): - tune_res = self.usrp.set_center_freq(tune_req, c) + for idx, chan in enumerate(self._sg.channels): + tune_res = self.usrp.set_center_freq(tune_req, chan) if idx == 0: self.set_label_dsp_freq(tune_res.actual_dsp_freq) self.set_label_rf_freq(tune_res.actual_rf_freq) @@ -446,7 +448,7 @@ def main(): """ Go, go, go! """ parser = setup_parser() args = parser.parse_args() - if(StrictVersion(Qt.qVersion()) >= StrictVersion("4.5.0")): + if StrictVersion(Qt.qVersion()) >= StrictVersion("4.5.0"): Qt.QApplication.setGraphicsSystem(gr.prefs().get_string('qtgui', 'style', 'raster')) qapp = Qt.QApplication(sys.argv) siggen_gui = uhd_siggen_gui(args) @@ -457,14 +459,17 @@ def main(): qapp.exec_() siggen_gui = None #to clean up Qt widgets -if __name__ == '__main__': +def x11_init_threads(): + " If on X11, init threads " import ctypes - import sys if sys.platform.startswith('linux'): try: x11 = ctypes.cdll.LoadLibrary('libX11.so') x11.XInitThreads() except: print("Warning: failed to XInitThreads()") + +if __name__ == '__main__': + x11_init_threads() main() diff --git a/gr-uhd/lib/usrp_source_impl.cc b/gr-uhd/lib/usrp_source_impl.cc index f0450a604d..ebfdf4abb2 100644 --- a/gr-uhd/lib/usrp_source_impl.cc +++ b/gr-uhd/lib/usrp_source_impl.cc @@ -480,6 +480,7 @@ namespace gr { { _dev->issue_stream_cmd(cmd, _stream_args.channels[i]); } + _tag_now = true; } bool |