diff options
225 files changed, 29410 insertions, 2902 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 7622d9d5e4..d355b7e801 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,8 +46,8 @@ message(STATUS "Build type set to ${CMAKE_BUILD_TYPE}.") # Set the version information here set(VERSION_INFO_MAJOR_VERSION 3) set(VERSION_INFO_API_COMPAT 7) -set(VERSION_INFO_MINOR_VERSION 7) -set(VERSION_INFO_MAINT_VERSION 1) +set(VERSION_INFO_MINOR_VERSION 8) +set(VERSION_INFO_MAINT_VERSION git) include(GrVersion) #setup version info # Append -O2 optimization flag for Debug builds @@ -409,6 +409,14 @@ add_subdirectory(gr-zeromq) if(ENABLE_GR_CTRLPORT) set(GR_CTRLPORT True) add_definitions(-DGR_CTRLPORT) + + if(CTRLPORT_BACKENDS GREATER 0) + set(GR_RPCSERVER_ENABLED True) + + if(THRIFT_FOUND) + set(GR_RPCSERVER_THRIFT True) + endif(THRIFT_FOUND) + endif(CTRLPORT_BACKENDS GREATER 0) endif(ENABLE_GR_CTRLPORT) # Install our Cmake modules into $prefix/lib/cmake/gnuradio diff --git a/cmake/Modules/FindThrift.cmake b/cmake/Modules/FindThrift.cmake new file mode 100644 index 0000000000..f12bce01e6 --- /dev/null +++ b/cmake/Modules/FindThrift.cmake @@ -0,0 +1,79 @@ +INCLUDE(FindPkgConfig) +PKG_CHECK_MODULES(PC_THRIFT thrift) + +set(THRIFT_REQ_VERSION "0.9.2") + +# If pkg-config found Thrift and it doesn't meet our version +# requirement, warn and exit -- does not cause an error; just doesn't +# enable Thrift. +if(PC_THRIFT_FOUND AND PC_THRIFT_VERSION VERSION_LESS ${THRIFT_REQ_VERSION}) + message(STATUS "Could not find appropriate version of Thrift: ${PC_THRIFT_VERSION} < ${THRIFT_REQ_VERSION}") + return() +endif(PC_THRIFT_FOUND AND PC_THRIFT_VERSION VERSION_LESS ${THRIFT_REQ_VERSION}) + + +# Else, look for it ourselves + +FIND_PATH(THRIFT_INCLUDE_DIRS + NAMES thrift/Thrift.h + HINTS ${PC_THRIFT_INCLUDE_DIR} + ${CMAKE_INSTALL_PREFIX}/include + PATHS + /usr/local/include + /usr/include + ) + +FIND_LIBRARY(THRIFT_LIBRARIES + NAMES thrift + HINTS ${PC_THRIFT_LIBDIR} + ${CMAKE_INSTALL_PREFIX}/lib + ${CMAKE_INSTALL_PREFIX}/lib64 + PATHS + ${THRIFT_INCLUDE_DIRS}/../lib + /usr/local/lib + /usr/lib + ) + +# Get the thrift binary to build our files during cmake +FIND_PROGRAM(THRIFT_BIN thrift) + +# Use binary to get version string and test against THRIFT_REQ_VERSION +EXECUTE_PROCESS( + COMMAND ${THRIFT_BIN} --version + OUTPUT_VARIABLE THRIFT_VERSION + ERROR_VARIABLE THRIFT_VERSION_ERROR + ) + +if(NOT THRIFT_BIN) + message(STATUS "Binary 'thrift' not found.") + return() +endif(NOT THRIFT_BIN) + +STRING(REGEX MATCH "[0-9]+.[0-9]+.[0-9]+" + THRIFT_VERSION "${THRIFT_VERSION}") + +if(THRIFT_VERSION VERSION_LESS THRIFT_REQ_VERSION) + message(STATUS "Could not find appropriate version of Thrift: ${THRIFT_VERSION} < ${THRIFT_REQ_VERSION}") + return() +endif(THRIFT_VERSION VERSION_LESS THRIFT_REQ_VERSION) + + +# Check that Thrift for Python is available +include(GrPython) +GR_PYTHON_CHECK_MODULE("Thrift" thrift "1" PYTHON_THRIFT_FOUND) + +# Set to found if we've made it this far +if(THRIFT_INCLUDE_DIRS AND THRIFT_LIBRARIES AND PYTHON_THRIFT_FOUND) + set(THRIFT_FOUND TRUE CACHE BOOL "If Thift has been found") +endif(THRIFT_INCLUDE_DIRS AND THRIFT_LIBRARIES AND PYTHON_THRIFT_FOUND) + + +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(THRIFT DEFAULT_MSG + THRIFT_LIBRARIES THRIFT_INCLUDE_DIRS + THRIFT_BIN PYTHON_THRIFT_FOUND THRIFT_FOUND +) +MARK_AS_ADVANCED( + THRIFT_LIBRARIES THRIFT_INCLUDE_DIRS + THRIFT_BIN PYTHON_THRIFT_FOUND THRIFT_FOUND +) diff --git a/cmake/Modules/GrSwig.cmake b/cmake/Modules/GrSwig.cmake index abf4dc4612..ef3a76eb4c 100644 --- a/cmake/Modules/GrSwig.cmake +++ b/cmake/Modules/GrSwig.cmake @@ -105,17 +105,36 @@ endfunction(GR_SWIG_MAKE_DOCS) macro(GR_SWIG_MAKE name) set(ifiles ${ARGN}) - # Shimming this in here to take care of a SWIG bug with handling - # vector<size_t> and vector<unsigned int> (on 32-bit machines) and - # vector<long unsigned int> (on 64-bit machines). Use this to test - # the size of size_t, then set SIZE_T_32 if it's a 32-bit machine - # or not if it's 64-bit. The logic in gr_type.i handles the rest. - INCLUDE(CheckTypeSize) - CHECK_TYPE_SIZE("size_t" SIZEOF_SIZE_T) - CHECK_TYPE_SIZE("unsigned int" SIZEOF_UINT) - if(${SIZEOF_SIZE_T} EQUAL ${SIZEOF_UINT}) - list(APPEND GR_SWIG_FLAGS -DSIZE_T_32) - endif(${SIZEOF_SIZE_T} EQUAL ${SIZEOF_UINT}) + # Take care of a SWIG < 3.0 bug with handling std::vector<size_t>, + # by mapping to the correct sized type on the runtime system, one + # of "unsigned int", "unsigned long", or "unsigned long long". + # Compare the sizeof(size_t) with the sizeof the other types, and + # pick the first one in the list with the same sizeof. The logic + # in gnuradio-runtime/swig/gr_types.i handles the rest. It is + # probably not necessary to do this assignment all of the time, + # but it's easier to do it this way than to figure out the + # conditions when it is necessary -- and doing it this way won't + # hurt. This bug seems to have been fixed with SWIG >= 3.0, and + # mostly happens when not doing a native build (e.g., on Mac OS X + # when using a 64-bit CPU but building for 32-bit). + + if(SWIG_VERSION VERSION_LESS "3.0.0") + include(CheckTypeSize) + check_type_size("size_t" SIZEOF_SIZE_T) + check_type_size("unsigned int" SIZEOF_UINT) + check_type_size("unsigned long" SIZEOF_UL) + check_type_size("unsigned long long" SIZEOF_ULL) + + if(${SIZEOF_SIZE_T} EQUAL ${SIZEOF_UINT}) + list(APPEND GR_SWIG_FLAGS -DSIZE_T_UINT) + elseif(${SIZEOF_SIZE_T} EQUAL ${SIZEOF_UL}) + list(APPEND GR_SWIG_FLAGS -DSIZE_T_UL) + elseif(${SIZEOF_SIZE_T} EQUAL ${SIZEOF_ULL}) + list(APPEND GR_SWIG_FLAGS -DSIZE_T_ULL) + else() + message(FATAL_ERROR "GrSwig: Unable to find replace for std::vector<size_t>; this should never happen!") + endif() + endif() #do swig doc generation if specified if(GR_SWIG_DOC_FILE) diff --git a/cmake/Modules/GrTest.cmake b/cmake/Modules/GrTest.cmake index 62caab4b51..ff78ed2726 100644 --- a/cmake/Modules/GrTest.cmake +++ b/cmake/Modules/GrTest.cmake @@ -66,7 +66,8 @@ function(GR_ADD_TEST test_name) file(TO_NATIVE_PATH "${GR_TEST_LIBRARY_DIRS}" libpath) #ok to use on dir list? file(TO_NATIVE_PATH "${GR_TEST_PYTHON_DIRS}" pypath) #ok to use on dir list? - set(environs "VOLK_GENERIC=1" "GR_DONT_LOAD_PREFS=1" "srcdir=${srcdir}") + set(environs "VOLK_GENERIC=1" "GR_DONT_LOAD_PREFS=1" "srcdir=${srcdir}" + "GR_CONF_CONTROLPORT_ON=False") list(APPEND environs ${GR_TEST_ENVIRONS}) #http://www.cmake.org/pipermail/cmake/2009-May/029464.html diff --git a/config.h.in b/config.h.in index 82751a3cf7..ad6e3d022c 100644 --- a/config.h.in +++ b/config.h.in @@ -30,6 +30,12 @@ #ifndef GR_CTRLPORT #cmakedefine GR_CTRLPORT #endif +#ifndef GR_RPCSERVER_ENABLED +#cmakedefine GR_RPCSERVER_ENABLED +#endif +#ifndef GR_RPCSERVER_THRIFT +#cmakedefine GR_RPCSERVER_THRIFT +#endif #ifndef ENABLE_GR_LOG #cmakedefine ENABLE_GR_LOG #endif diff --git a/docs/doxygen/other/build_guide.dox b/docs/doxygen/other/build_guide.dox index 56bcce7f96..8fc3f911fb 100644 --- a/docs/doxygen/other/build_guide.dox +++ b/docs/doxygen/other/build_guide.dox @@ -63,7 +63,7 @@ first. Most recent systems have these packages available. \li audio-osx \li audio-windows -* Optional but recommended dependencies. +<b>Optional but recommended dependencies.</b> It is not necessary to satisfy all of these dependencies; just the one(s) that are right for your system. On Linux, don't expect @@ -82,6 +82,17 @@ audio-osx and audio-windows to be either satisfied or built. \li log4cpp (>= 1.0) http://log4cpp.sourceforge.net/ +<b>Optional</b> + +\ref page_ctrlport may use various backends to perform the RPC +process, and each is its own dependency. + +Currently, ControlPort only supports the Apache Thrift backend. + +\li thrift (>= 0.9.2) https://thrift.apache.org/ + + + \section build_gr_cmake Building GNU Radio GNU Radio is built using the CMake build system diff --git a/docs/doxygen/other/ctrlport.dox b/docs/doxygen/other/ctrlport.dox index 64bf9f7d38..94a768e429 100644 --- a/docs/doxygen/other/ctrlport.dox +++ b/docs/doxygen/other/ctrlport.dox @@ -16,8 +16,427 @@ gnuradio.ctrlport module, imported as: from gnuradio import ctrlport \endcode -ControlPort is currently a temporary stub implementation of a set of -RPC calls we would like to enable that would allow remote viewing, -command, and control of GNU Radio flowgraphs and blocks. + +\section ctrlport_conf Configuration + +ControlPort is configured using two files. The first is the GNU Radio +preferences file while the second file is specific to the type of +middleware used. + +The GNU Radio preferences file has three options. The 'on' option is +used to enable or disable the use of ControlPort, and is disabled by +default. The 'config' option allows a user to specify the +middleware-specific configuration file. The 'edges_list' is a special +option that exports the list of nodes and edges of the flowgraph +across ControlPort. This latter option is mainly used for redrawing +the flowgraph for the Performance Counter applications. + +\code + [ControlPort] + on = True + edges_list = True + config = path-to/ctrlport.conf +\endcode + +The ControlPort preferences are installed by default into +'gnuradio-runtime.conf'. These can always be overridden in the local +~/.gnuradio/config.conf file. + + + +\section ctrlport_deps Dependencies + +ControlPort is an abstracted remote procedure call tool that. It is +built on top of other middleware libraries. The following subsections +explain some details about the use of the particular middleware +project. + +Currently, the only implemented middleware library is the Apache +Thrift project. + +\subsection ctrlport_thrift Apache Thrift + +Current version support: >= 0.9.2 + +Apache Thrift is a middleware layer that defines interfaces of a +program using its own Thrift language. GNU Radio's interface file is: + +gnuradio-runtime/lib/controlport/thrift/gnuradio.thrift + +This file defines the interfaces set, get, trigger, and properties. It +also defines a set of data structure Knobs to allow us to pass any +type of data over the interfaces. + +To use Thrift in ControlPort requires a minimum Thrift version of +0.9.0. If a Thrift version greater than or equal to this version is +not found, the Thrift backend to ControlPort will not be installed, +through ControlPort itself still will be. During cmake configuration +time, it prints out information about finding Thrift and requires: + +\li Thrift header files by looking for thrift/Thrift.h +\li Thrift C++ libraries: libthrift.so +\li Thrift Python bindings: "import thrift" + +If all of these are not satisfied, the Thrift backend will not be +installed. Upon completion, cmake outputs a notification of what +components will be built. You will see this if Thrift was found and +can be used: + +\code +* gr-ctrlport +* * thrift +\endcode + +Cmake also uses the Thrift compiler ("thrift") to build the C++ and +Python files necessary for compiling ControlPort. It runs "thrift +--gen cpp" the C++ bindings in the build directory, and then +it runs "thrift --gen py" to build the Python bindings, also in the +build directory. These are used to compile the Thrift ControlPort +features and are necessary files to run the Python clients. If cmake +fails to produce these bindings, it should error out. + + + +\subsubsection ctrlport_thrift_prefs Configuration + +Thrift does not support its own concept of a configuration file, so we +have built one for our purposes in GNU Radio. The 'config' option in +the ControlPort section of the preference files tells ControlPort +where to find the backend-specific file format. GNU Radio's Thrift +format follows the same "[Section] key = value" scheme used in all of +its other preference files. Currently supported configuration options +are: + +\code +[thrift] +port = 9090 +nthreads = 2 +buffersize = 1434 +init_attempts = 100 +\endcode + + +\subsubsection ctrlport_thrift_issues Thrift: Current Issues + +Thrift uses a thread pool system to handle each connection, but it +will only allow up to a specified number of threads in the server. The +default value is 10 threads, but the Thrift configuration file allows +the user to change this value. + +Thrift also does not find and use a free ephemeral port when launching +the server. It must be told explicitly which port to launch on, which +we set in the configuration file. This makes it difficult to launch +multiple flowgraphs on the same machine because that will cause a port +collision. Until this is fixed, a way around this is to use the +environmental variable GR_CONF_THRIFT_PORT=xxx to set the port number +for that specific application. + +Efficiency issues of Thrift come from the over-the-wire formatting +done by the transport protocol. It defaults to using 512 byte packets, +which can lead to a lot of fragmentation of the data over the +connection. The buffersize configuration allows the user to set this +value to whatever number fits their network needs. The default 1434 is +designed around the standard 1500 byte Ethernet frame size limit minus +the TCP/IP and Ethernet header size. + + +\subsection ctrlport_client_translation Translation Layer for Clients + +Different backends will produce different ways to interface with the +system. ControlPort in the running flowgraph acts as the server by +exposing interfaces to blocks. The interfaces and API in GNU Radio to +communicate with ControlPort are all abstracted completely away from +the backend methods and data types. That is, the code in GNU Radio's +scheduler and in the blocks that expose their ControlPort interfaces +will work regardless of the backend used. + +We are building better abstractions on the clients sides now, as +well. Although certain backends will support other features of +discovery and services that work well with their products, GNU Radio +wants to make sure that clients can access the data from the +interfaces in the same way for any backend used. This abstraction is +done through the GNURadioControlPortClient. This class is told which +type of backend is used, and defaults to Thrift, and can be passed +information about the server's endpoint such as the host name and port +number to attach to. The GNURadioControlPortClient returns a 'radio' +object that represents the connection to the running flowgraph. + + +\section ctrlport_using Using ControlPort to Export Variables + +The ability to export variables from a block is inherited from +gr::block. Then, when the flowgraph is started, the function +<b>setup_rpc()</b> is called in turn for each block. By default, this +is an empty function. A block overloads this function and defines and +exports variables in it. + +Say we have a class <b>gr::blocks::foo</b> that has variables <b>a</b> +and <b>b</b> that we want to export. Specifically, we want to be able +to read the values of both <b>a</b> and <b>b</b> and also set the +value of <b>b</b>. The class <b>gr::blocks::foo</b> has setters and +getters all set up. So our class implementation header file looks +something like: + +\code +namespace gr { + namespace blocks { + + class foo_impl : public foo + { + private: + float d_a, d_b; + + public: + foo_impl(float a, float b); + ~foo_impl(); + + float a() const { return d_a; } + float b() const { return d_a; } + void set_a(float a) { d_a = a; } + void set_b(float b) { d_b = b; } + void setup_rpc(); + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } /* namespace blocks */ +} /* namespace gr */ +\endcode + +The source code then sets up the class and fills in +<b>setup_rpc()</b>. + +\code +namespace gr { + namespace blocks { + + foo_impl::foo_impl(float a, float b): + sync_bloc(....), + d_a(a), d_b(b) + { } + + foo_impl::~foo_impl() + { } + + void + foo_impl::setup_rpc() + { +#ifdef GR_CTRLPORT + add_rpc_variable( + rpcbasic_sptr(new rpcbasic_register_get<foo, float>( + alias(), "a", + &foo::a, + pmt::mp(-2.0f), pmt::mp(2.0f), pmt::mp(0.0f), + "", "Get value of a", RPC_PRIVLVL_MIN, + DISPTIME | DISPOPTSTRIP))); + + add_rpc_variable( + rpcbasic_sptr(new rpcbasic_register_get<foo, float>( + alias(), "b", + &foo::b, + pmt::mp(0.0f), pmt::mp(20.0f), pmt::mp(10.0f), + "", "Get value of b", RPC_PRIVLVL_MIN, + DISPTIME | DISPOPTSTRIP))); + + add_rpc_variable( + rpcbasic_sptr(new rpcbasic_register_set<foo, float>( + alias(), "b", + &foo::set_b, + pmt::mp(0.0f), pmt::mp(20.0f), pmt::mp(10.0f), + "", "Set value of b", RPC_PRIVLVL_MIN, + DISPNULL))); +#endif /* GR_CTRLPORT */ + } + + int + foo_impl::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { .... } + + } /* namespace blocks */ +} /* namespace gr */ +\endcode + +In the above example, we're ignoring some of the basic semantics of +the class as a GNU Radio block and focus just on the call to set up +the get and set functions over ControlPort. Each block has a function +that allows us to add a new ControlPort interface object to a list, +the <b>add_rpc_variable</b>. We don't care about that list anymore; +that's for ControlPort to worry about. We just add new variables, +either setters or getters. + +Without dissecting every piece of the above calls, notice that we use +the public class, <b>gr::blocks::foo</b> as the class, not the +implementation class. We also use the block's alias, which GNU Radio +uses as a database entry to connect a block by name to the pointer in +memory. This allows ControlPort to know where the object in memory is +at any given time to access the setters and getters. + +The three PMTs specified are simply an expected minimum, maximum, and +default value. None of these are strictly enforced and only serve as +guides. The RPC_PRIVLVL_MIN is currently a placeholder for a +privilege level setting. In many cases, reading <b>b</b> might be +fine for everyone, but we want strong restrictions on who has the +ability to set <b>b</b>. + +And finally, we can specify display options to hint at the right way +to display this variable when remotely plotting it. More on that in +the following section. + +Finally, note that we put \#ifdefs around the code. We always want +<b>setup_rpc</b> to be there and callable, but if ControlPort was not +built for GNU Radio, we cannot register any variables with it. This is +just a nicety to allow us to set up our code for use with ControlPort +without requiring it. + + +\subsection ctrlport_alt_reg Alternative Registers + +If using the concept above, <b>setup_rpc</b> automatically gets called +when the flowgraph is started. In most instances, this is all we ever +need since there's nothing interesting going on until then. However, +if not using a gr::block or needing access before we run the flowgraph, +the above method won't work (it comes down to when the block's alias +has meaning). + +There are alternate variable registration functions for the sets and +gets. These take the form: + +\code + rpcbasic_register_get(const std::string& name, + const char* functionbase, + T* obj, + Tfrom (T::*function)(), + const pmt::pmt_t &min, const pmt::pmt_t &max, const pmt::pmt_t &def, + const char* units_ = "", + const char* desc_ = "", + priv_lvl_t minpriv_ = RPC_PRIVLVL_MIN, + DisplayType display_ = DISPNULL) + + rpcbasic_register_set(const std::string& name, + const char* functionbase, + T* obj, + void (T::*function)(Tto), + const pmt::pmt_t &min, const pmt::pmt_t &max, const pmt::pmt_t &def, + const char* units_ = "", + const char* desc_ = "", + priv_lvl_t minpriv_ = RPC_PRIVLVL_MIN, + DisplayType display_ = DISPNULL) +\endcode + +The only thing different about the above code is that instead of +taking a single 'alias()' name, which provides us access to the +objects pointer, we instead provide a unique name +(<b>fucntionbase</b>) and a pointer to the object itself +(<b>obj</b>). These are templated functions, so the class T is known +from that. + +If using this method, the recommended way is to create a new function +(not <b>setup_rpc</b>), register the variable using +<b>add_rpc_variable</b> but with the different <b>register_get/set</b> +shown here, and then call this function either in the object's +constructor or make it a public member function to be called when you +need it. + + +\section ctrlport_disp Display Options + +When exporting a new RPC variable over ControlPort, one argument is a +display options mask. These options are useful to a remote client to +tell identify activities like default plotters and initial +conditions. The <b>gr-ctrlport-monitor</b> application uses this +heavily in determining how to plot ControlPort variables. + +The options mask is just a 32-bit value with options OR'd +together. Certain options are only appropriate for certain types of +plots. Options on plots where that option is not available will +simply be ignored. + +The main caveat to be aware of is that the DISPXY plot type is +specific to complex values. Therefore, DISPOPTCPLX is assumed. + +These options are specified in rpccallbackregister_base.h and are +exposed through SWIG to live in the \b gr namespace. + +<b>Plot Types</b> +\li <b>DISPNULL:</b> Nothing specified. +\li <b>DISPTIME:</b> Time-domain plot. +\li <b>DISPXY:</b> XY or constellation plot (complex only). +\li <b>DISPPSD:</b> PSD plot. +\li <b>DISPSPEC:</b> Spectrogram plot. +\li <b>DISPRAST:</b> Time raster plot (non-complex only) + +<b>Plot Options</b> +\li <b>DISPOPTCPLX:</b> Signal is complex. +\li <b>DISPOPTLOG:</b> Start plot in semilog-y mode (time domain only). +\li <b>DISPOPTSTEM:</b> Start plot in stem mode (time domain only). +\li <b>DISPOPTSTRIP:</b> Run plot as a stripchart (time domain only). +\li <b>DISPOPTSCATTER:</b> Do scatter plot instead of lines (XY plot only). + + +\section ctrlport_probes ControlPort Probes + +ControlPort provides a set of probes that can be used as sinks that +pass vectors of data across ControlPort. These probes are used to +sample or visualize data remotely. We can place a ControlPort probe +anywhere in the flowgraph to grab the latest sample of data from the +block it's connected to. + +The main ControlPort probe to use is +<b>blocks.ctrlport_probe2_x</b>. From GRC, this is simply "CtrlPort +Probe", which can handle complex, floats, ints, shorts, and bytes. The +blocks are named and given a description to identify them over +ControlPort. The blocks also take a vector length for how many samples +to pass back at a time. Finally, these blocks take a display hint, +as described in the above section. This allows us to specify the +default behavior for how to display the samples. + +Another block that can be used is the <b>fft.ctrlport_probe_psd</b> to +calculate the PSD and pass that over the ControlPort interface. + +\section ctrlport_monitors ControlPort Monitors + +There are two main ControlPort monitor applications provided with GNU +Radio. Both act similarly. The first is a standard ControlPort monitor +application. This connects to a running flowgraph and displays all +exported interfaces in a table format. The name, unit, latest sample, +and description of all interfaces are display in a +row. Double-clicking will open up the default display. Right clicking +any item will allow the user to select the type of plot to use to +display the data. + +When a display is active, using the buttons at the top, the subwindows +can all be tiled or windowed as needed to manage the full +interface. We can then drag-and-drop any other item on top of a +currently running display plot. + +To launch the ControlPort monitor application, know the IP address and +port of the ControlPort endpoint established by the flowgraph and run: + +<pre> +gr-ctrlport-monitor \<ip-addr\> -p \<port\> +</pre> + + +\subsection perfmonitor Performance Monitor + +A second application is used to locally redraw the flowgraph and +display some of the Performance Counters. In this application, the +nodes are blue boxes where the size of the box is proportional to the +work time and the color depth and line width are proportional to the +output buffer fullness. + +The controls at the top of the Performance Monitor application allow +us to select the instantaneous, average, and variance values of the +Performance Counters. And the work time and buffer fullness can be +displayed as a table or bar graph. + +To launch the Performance Monitor, run: + +<pre> +gr-perf-monitorx \<ip-addr\> -p \<port\> +</pre> */ diff --git a/docs/doxygen/other/perf_counters.dox b/docs/doxygen/other/perf_counters.dox index 1a5bf40cba..9bca38268a 100644 --- a/docs/doxygen/other/perf_counters.dox +++ b/docs/doxygen/other/perf_counters.dox @@ -85,4 +85,14 @@ The options for the [PerfCounters] section are: \li clock: sets the type of clock used when calculating work_time ('thread' or 'monotonic'). + +\section pc_perfmonitor Performance Monitor + +See \ref perfmonitor for some details of using a ControlPort-based +monitor application, gr-perf-monitorx, for visualizing the +counters. This application is particularly useful in learning which +blocks are the computationally complex blocks that could use extra +optimization or work to improve their performance. It can also be used +to understand the current 'health' of the application. + */ diff --git a/gnuradio-runtime/include/gnuradio/CMakeLists.txt b/gnuradio-runtime/include/gnuradio/CMakeLists.txt index 3fc2fe7bd8..472f91847b 100644 --- a/gnuradio-runtime/include/gnuradio/CMakeLists.txt +++ b/gnuradio-runtime/include/gnuradio/CMakeLists.txt @@ -86,6 +86,16 @@ install(FILES COMPONENT "runtime_devel" ) +if(THRIFT_FOUND) +install(FILES + rpcserver_booter_thrift.h + thrift_application_base.h + thrift_server_template.h + DESTINATION ${GR_INCLUDE_DIR}/gnuradio + COMPONENT "runtime_devel" +) +endif(THRIFT_FOUND) + ########################################################################## # Configure logger ########################################################################## diff --git a/gnuradio-runtime/include/gnuradio/prefs.h b/gnuradio-runtime/include/gnuradio/prefs.h index a9a28586ab..4dc92b3631 100644 --- a/gnuradio-runtime/include/gnuradio/prefs.h +++ b/gnuradio-runtime/include/gnuradio/prefs.h @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2006,2013 Free Software Foundation, Inc. + * Copyright 2006,2013,2015 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -47,10 +47,38 @@ namespace gr { public: static prefs *singleton(); + /*! + * \brief Creates an object to read preference files. + * + * \details + * + * If no file name is given (empty arg list or ""), this opens up + * the standard GNU Radio configuration files in + * prefix/etc/gnuradio/conf.d as well as ~/.gnuradio/config.conf. + * + * Only access this through the singleton defined here: + * \code + * prefs *p = prefs::singleton(); + * \endcode + */ prefs(); + virtual ~prefs(); /*! + * If specifying a file name, this opens that specific + * configuration file of the standard form containing sections and + * key-value pairs: + * + * \code + * [SectionName] + * key0 = value0 + * key1 = value1 + * \endcode + */ + void add_config_file(const std::string &configfile); + + /*! * \brief Returns the configuration options as a string. */ std::string to_string(); @@ -137,7 +165,7 @@ namespace gr { protected: virtual std::vector<std::string> _sys_prefs_filenames(); - virtual void _read_files(); + virtual std::string _read_files(const std::vector<std::string> &filenames); virtual void _convert_to_map(const std::string &conf); virtual char * option_to_env(std::string section, std::string option); diff --git a/gnuradio-runtime/include/gnuradio/rpcbufferedget.h b/gnuradio-runtime/include/gnuradio/rpcbufferedget.h new file mode 100644 index 0000000000..ad05551d1a --- /dev/null +++ b/gnuradio-runtime/include/gnuradio/rpcbufferedget.h @@ -0,0 +1,64 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 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 RPCBUFFEREDGET_H +#define RPCBUFFEREDGET_H + +#include <boost/thread/condition_variable.hpp> +#include <boost/thread/mutex.hpp> + +template<typename TdataType> +class rpcbufferedget { +public: + rpcbufferedget(const unsigned int init_buffer_size = 4096) : + d_data_needed(false), d_data_ready(), d_buffer_lock(), d_buffer(init_buffer_size) {;} + + ~rpcbufferedget() { + d_data_ready.notify_all(); + } + + void offer_data(const TdataType& data) { + if (!d_data_needed) + return; + { + boost::mutex::scoped_lock lock(d_buffer_lock); + d_buffer = data; + d_data_needed = false; + } + d_data_ready.notify_one(); + } + + TdataType get() { + boost::mutex::scoped_lock lock(d_buffer_lock); + d_data_needed = true; + d_data_ready.wait(lock); + return d_buffer; + } + +private: + bool d_data_needed; + boost::condition_variable d_data_ready; + boost::mutex d_buffer_lock; + TdataType d_buffer; +}; + +#endif diff --git a/gnuradio-runtime/include/gnuradio/rpcmanager.h b/gnuradio-runtime/include/gnuradio/rpcmanager.h index 5635572a8b..e7ee4c4942 100644 --- a/gnuradio-runtime/include/gnuradio/rpcmanager.h +++ b/gnuradio-runtime/include/gnuradio/rpcmanager.h @@ -54,7 +54,7 @@ class GR_RUNTIME_API rpcmanager : public virtual rpcmanager_base static bool booter_registered; static bool aggregator_registered; static void rpcserver_booter_base_sptr_dest(rpcserver_booter_base* b) {;} - static rpcserver_booter_base* boot; + static std::auto_ptr<rpcserver_booter_base> boot; static std::auto_ptr<rpcserver_booter_aggregator> aggregator; }; diff --git a/gnuradio-runtime/include/gnuradio/rpcpmtconverters_thrift.h b/gnuradio-runtime/include/gnuradio/rpcpmtconverters_thrift.h new file mode 100644 index 0000000000..d55e7eb3b9 --- /dev/null +++ b/gnuradio-runtime/include/gnuradio/rpcpmtconverters_thrift.h @@ -0,0 +1,75 @@ +/* + * Copyright 2014,2015 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 RPCPMTCONVERTERS_THRIFT_H +#define RPCPMTCONVERTERS_THRIFT_H + +#include <pmt/pmt.h> +#include <boost/noncopyable.hpp> +#include <boost/ptr_container/ptr_map.hpp> +#include "thrift/gnuradio_types.h" + + +namespace rpcpmtconverter +{ + GNURadio::Knob from_pmt(const pmt::pmt_t& knob); + + struct to_pmt_f { + to_pmt_f() {;} + virtual ~to_pmt_f() {} + virtual pmt::pmt_t operator()(const GNURadio::Knob& knob); + }; + + struct to_pmt_byte_f : public to_pmt_f { pmt::pmt_t operator()(const GNURadio::Knob& knob); }; + struct to_pmt_short_f : public to_pmt_f { pmt::pmt_t operator()(const GNURadio::Knob& knob); }; + struct to_pmt_int_f : public to_pmt_f { pmt::pmt_t operator()(const GNURadio::Knob& knob); }; + struct to_pmt_long_f : public to_pmt_f { pmt::pmt_t operator()(const GNURadio::Knob& knob); }; + struct to_pmt_double_f : public to_pmt_f { pmt::pmt_t operator()(const GNURadio::Knob& knob); }; + struct to_pmt_string_f : public to_pmt_f { pmt::pmt_t operator()(const GNURadio::Knob& knob); }; + struct to_pmt_bool_f : public to_pmt_f { pmt::pmt_t operator()(const GNURadio::Knob& knob); }; + struct to_pmt_complex_f: public to_pmt_f { pmt::pmt_t operator()(const GNURadio::Knob& knob); }; + struct to_pmt_f32vect_f: public to_pmt_f { pmt::pmt_t operator()(const GNURadio::Knob& knob); }; + struct to_pmt_f64vect_f: public to_pmt_f { pmt::pmt_t operator()(const GNURadio::Knob& knob); }; + struct to_pmt_s64vect_f: public to_pmt_f { pmt::pmt_t operator()(const GNURadio::Knob& knob); }; + struct to_pmt_s32vect_f: public to_pmt_f { pmt::pmt_t operator()(const GNURadio::Knob& knob); }; + struct to_pmt_s16vect_f: public to_pmt_f { pmt::pmt_t operator()(const GNURadio::Knob& knob); }; + struct to_pmt_s8vect_f : public to_pmt_f { pmt::pmt_t operator()(const GNURadio::Knob& knob); }; + struct to_pmt_c32vect_f: public to_pmt_f { pmt::pmt_t operator()(const GNURadio::Knob& knob); }; + + class To_PMT : private boost::noncopyable { + public: + static To_PMT instance; + template<typename TO_PMT_F> friend struct to_pmt_reg; + pmt::pmt_t operator()(const GNURadio::Knob& knob); + + protected: + boost::ptr_map<GNURadio::BaseTypes::type, to_pmt_f> to_pmt_map; + + private: + To_PMT() {;} + }; + + template<typename TO_PMT_F> struct to_pmt_reg { + to_pmt_reg(To_PMT& instance, const GNURadio::BaseTypes::type type); + }; +} + +#endif /* RPCPMTCONVERTERS_THRIFT_H */ diff --git a/gnuradio-runtime/include/gnuradio/rpcregisterhelpers.h b/gnuradio-runtime/include/gnuradio/rpcregisterhelpers.h index 0999dea747..f82f5ed0aa 100644 --- a/gnuradio-runtime/include/gnuradio/rpcregisterhelpers.h +++ b/gnuradio-runtime/include/gnuradio/rpcregisterhelpers.h @@ -672,7 +672,7 @@ struct rpcbasic_register_set : public rpcbasic_base d_minpriv = minpriv_; d_display = display_; d_object = dynamic_cast<T*>(global_block_registry.block_lookup(pmt::intern(block_alias)).get()); -#ifdef RPCSERVER_ENABLED +#ifdef GR_RPCSERVER_ENABLED callbackregister_base::configureCallback_t extractor(new rpcbasic_extractor<T,Tto>(d_object, function), minpriv_, std::string(units_), @@ -726,7 +726,7 @@ struct rpcbasic_register_set : public rpcbasic_base d_minpriv = minpriv_; d_display = display_; d_object = obj; -#ifdef RPCSERVER_ENABLED +#ifdef GR_RPCSERVER_ENABLED callbackregister_base::configureCallback_t extractor(new rpcbasic_extractor<T,Tto>(d_object, function), minpriv_, std::string(units_), @@ -741,7 +741,7 @@ struct rpcbasic_register_set : public rpcbasic_base ~rpcbasic_register_set() { -#ifdef RPCSERVER_ENABLED +#ifdef GR_RPCSERVER_ENABLED rpcmanager::get()->i()->unregisterConfigureCallback(d_id); #endif } @@ -830,7 +830,7 @@ struct rpcbasic_register_trigger : public rpcbasic_base d_desc = desc_; d_minpriv = minpriv_; d_object = dynamic_cast<T*>(global_block_registry.block_lookup(pmt::intern(block_alias)).get()); -#ifdef RPCSERVER_ENABLED +#ifdef GR_RPCSERVER_ENABLED callbackregister_base::configureCallback_t extractor(new rpcbasic_extractor<T,void>(d_object, function), minpriv_, std::string(desc_)); @@ -870,7 +870,7 @@ struct rpcbasic_register_trigger : public rpcbasic_base d_desc = desc_; d_minpriv = minpriv_; d_object = obj; -#ifdef RPCSERVER_ENABLED +#ifdef GR_RPCSERVER_ENABLED callbackregister_base::configureCallback_t extractor(new rpcbasic_extractor<T,void>(d_object, function), minpriv_, std::string(desc_)); @@ -884,7 +884,7 @@ struct rpcbasic_register_trigger : public rpcbasic_base ~rpcbasic_register_trigger() { -#ifdef RPCSERVER_ENABLED +#ifdef GR_RPCSERVER_ENABLED rpcmanager::get()->i()->unregisterConfigureCallback(d_id); #endif } @@ -988,7 +988,7 @@ public: d_minpriv = minpriv_; d_display = display_; d_object = dynamic_cast<T*>(global_block_registry.block_lookup(pmt::intern(block_alias)).get()); -#ifdef RPCSERVER_ENABLED +#ifdef GR_RPCSERVER_ENABLED callbackregister_base::queryCallback_t inserter(new rpcbasic_inserter<T,Tfrom>(d_object, function), minpriv_, std::string(units_), display_, std::string(desc_), min, max, def); @@ -1022,7 +1022,7 @@ public: d_minpriv = minpriv_; d_display = display_; d_object = dynamic_cast<T*>(global_block_registry.block_lookup(pmt::intern(block_alias)).get()); -#ifdef RPCSERVER_ENABLED +#ifdef GR_RPCSERVER_ENABLED callbackregister_base::queryCallback_t inserter(new rpcbasic_inserter<T,Tfrom>(d_object, (Tfrom (T::*)())function), minpriv_, std::string(units_), display_, std::string(desc_), min, max, def); @@ -1076,7 +1076,7 @@ public: d_minpriv = minpriv_; d_display = display_; d_object = obj; -#ifdef RPCSERVER_ENABLED +#ifdef GR_RPCSERVER_ENABLED callbackregister_base::queryCallback_t inserter(new rpcbasic_inserter<T,Tfrom>(d_object, function), minpriv_, std::string(units_), display_, std::string(desc_), min, max, def); @@ -1111,7 +1111,7 @@ public: d_minpriv = minpriv_; d_display = display_; d_object = obj; -#ifdef RPCSERVER_ENABLED +#ifdef GR_RPCSERVER_ENABLED callbackregister_base::queryCallback_t inserter(new rpcbasic_inserter<T,Tfrom>(d_object, (Tfrom (T::*)())function), minpriv_, std::string(units_), display_, std::string(desc_), min, max, def); @@ -1125,7 +1125,7 @@ public: ~rpcbasic_register_get() { -#ifdef RPCSERVER_ENABLED +#ifdef GR_RPCSERVER_ENABLED rpcmanager::get()->i()->unregisterQueryCallback(d_id); #endif } diff --git a/gnuradio-runtime/include/gnuradio/rpcserver_booter_thrift.h b/gnuradio-runtime/include/gnuradio/rpcserver_booter_thrift.h new file mode 100644 index 0000000000..fd1da09fa6 --- /dev/null +++ b/gnuradio-runtime/include/gnuradio/rpcserver_booter_thrift.h @@ -0,0 +1,51 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 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 RPCSERVER_BOOTER_THRIFT_H +#define RPCSERVER_BOOTER_THRIFT_H + +#include <gnuradio/rpcserver_booter_base.h> +#include <gnuradio/thrift_server_template.h> +#include "thrift/ControlPort.h" + +class rpcserver_base; +class rpcserver_thrift; + +class rpcserver_booter_thrift + : public virtual rpcserver_booter_base, + public virtual thrift_server_template<rpcserver_base, + rpcserver_thrift, + rpcserver_booter_thrift> +{ + public: + rpcserver_booter_thrift(); + ~rpcserver_booter_thrift(); + + rpcserver_base* i(); + const std::string & type() {return d_type;} + const std::vector<std::string> endpoints(); + + private: + std::string d_type; +}; + +#endif /* RPCSERVER_BOOTER_THRIFT_H */ diff --git a/gnuradio-runtime/include/gnuradio/rpcserver_selector.h b/gnuradio-runtime/include/gnuradio/rpcserver_selector.h index 8a14f78d99..31ab6cea0b 100644 --- a/gnuradio-runtime/include/gnuradio/rpcserver_selector.h +++ b/gnuradio-runtime/include/gnuradio/rpcserver_selector.h @@ -23,10 +23,12 @@ #ifndef RPCSERVER_SELECTOR #define RPCSERVER_SELECTOR -//#define RPCSERVER_ENABLED +#include <gnuradio/config.h> -//#define RPCSERVER_ICE -//#define RPCSERVER_ERLANG -//#define RPCSERVER_XMLRPC +//#define GR_RPCSERVER_ENABLED +//#define GR_RPCSERVER_ICE +//#define GR_RPCSERVER_THRIFT +//#define GR_RPCSERVER_ERLANG +//#define GR_RPCSERVER_XMLRPC #endif diff --git a/gnuradio-runtime/include/gnuradio/rpcserver_thrift.h b/gnuradio-runtime/include/gnuradio/rpcserver_thrift.h new file mode 100644 index 0000000000..203be66e9a --- /dev/null +++ b/gnuradio-runtime/include/gnuradio/rpcserver_thrift.h @@ -0,0 +1,233 @@ +/* -*- c++ -*- */ +/* + * Copyright 2014,2015 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 RPCSERVER_THRIFT_H +#define RPCSERVER_THRIFT_H + +#include <gnuradio/rpcserver_base.h> +#include <gnuradio/rpcpmtconverters_thrift.h> +#include <string> +#include <iostream> +#include <sstream> +#include <map> +#include "thrift/ControlPort.h" +#include "thrift/gnuradio_types.h" +#include <boost/format.hpp> +#include <boost/thread/mutex.hpp> + +#define S(x) #x +#define S_(x) S(x) +#define S__LINE__ S_(__LINE__) + +class rpcserver_thrift : public virtual rpcserver_base, public GNURadio::ControlPortIf +{ +public: + rpcserver_thrift(); + virtual ~rpcserver_thrift(); + + void registerConfigureCallback(const std::string &id, + const configureCallback_t callback); + void unregisterConfigureCallback(const std::string &id); + + void registerQueryCallback(const std::string &id, + const queryCallback_t callback); + void unregisterQueryCallback(const std::string &id); + + void setKnobs(const GNURadio::KnobMap&); + void getKnobs(GNURadio::KnobMap&, + const GNURadio::KnobIDList&); + void getRe(GNURadio::KnobMap&, + const GNURadio::KnobIDList&); + void properties(GNURadio::KnobPropMap&, + const GNURadio::KnobIDList& knobs); + virtual void shutdown(); + + private: + boost::mutex d_callback_map_lock; + + typedef std::map<std::string, configureCallback_t> ConfigureCallbackMap_t; + ConfigureCallbackMap_t d_setcallbackmap; + + typedef std::map<std::string, queryCallback_t> QueryCallbackMap_t; + QueryCallbackMap_t d_getcallbackmap; + + template<typename T, typename TMap> struct set_f + : public std::unary_function<T,void> + { + set_f(TMap &_setcallbackmap, const priv_lvl_t &_cur_priv) + : d_setcallbackmap(_setcallbackmap), cur_priv(_cur_priv) + { + ; + } + + void operator()(const T& p) + { + ConfigureCallbackMap_t::const_iterator iter(d_setcallbackmap.find(p.first)); + if(iter != d_setcallbackmap.end()) { + if(cur_priv <= iter->second.priv) { + (*iter->second.callback).post(pmt::PMT_NIL, rpcpmtconverter::To_PMT::instance(p.second)); + } + else { + std::cout << "Key " << p.first << " requires PRIVLVL <= " + << iter->second.priv << " to set, currently at: " + << cur_priv << std::endl; + } + } + else { + throw apache::thrift::TApplicationException(__FILE__ " " S__LINE__); + } + } + + TMap& d_setcallbackmap; + const priv_lvl_t& cur_priv; + }; + + template<typename T, typename TMap> + struct get_f : public std::unary_function<T,void> + { + get_f(TMap &_getcallbackmap, const priv_lvl_t &_cur_priv, GNURadio::KnobMap &_outknobs) : + d_getcallbackmap(_getcallbackmap), cur_priv(_cur_priv), outknobs(_outknobs) + {} + + void operator()(const T& p) + { + QueryCallbackMap_t::const_iterator iter(d_getcallbackmap.find(p)); + if(iter != d_getcallbackmap.end()) { + if(cur_priv <= iter->second.priv) { + outknobs[p] = rpcpmtconverter::from_pmt((*iter->second.callback).retrieve()); + } + else { + std::cout << "Key " << iter->first << " requires PRIVLVL: <= " + << iter->second.priv << " to get, currently at: " + << cur_priv << std::endl; + } + } + else { + std::stringstream ss; + ss << "Ctrlport Key called with unregistered key (" << p << ")\n"; + std::cout << ss.str(); + throw apache::thrift::TApplicationException(__FILE__ " " S__LINE__); + } + } + + TMap& d_getcallbackmap; + const priv_lvl_t& cur_priv; + GNURadio::KnobMap& outknobs; + }; + + template<typename T, typename TMap, typename TKnobMap> + struct get_all_f : public std::unary_function<T,void> + { + get_all_f(TMap &_getcallbackmap, const priv_lvl_t &_cur_priv, TKnobMap &_outknobs) : + d_getcallbackmap(_getcallbackmap), cur_priv(_cur_priv), outknobs(_outknobs) + {;} + + void operator()(const T& p) + { + if(cur_priv <= p.second.priv) { + outknobs[p.first] = rpcpmtconverter::from_pmt(p.second.callback->retrieve()); + } + else { + std::cout << "Key " << p.first << " requires PRIVLVL <= " + << p.second.priv << " to get, currently at: " + << cur_priv << std::endl; + } + } + + TMap& d_getcallbackmap; + const priv_lvl_t& cur_priv; + TKnobMap& outknobs; + }; + + template<typename T, typename TMap, typename TKnobMap> + struct properties_all_f : public std::unary_function<T,void> + { + properties_all_f(QueryCallbackMap_t &_getcallbackmap, + const priv_lvl_t &_cur_priv, + GNURadio::KnobPropMap &_outknobs) + : d_getcallbackmap(_getcallbackmap), + cur_priv(_cur_priv), + outknobs(_outknobs) + {;} + + void operator()(const T& p) + { + if(cur_priv <= p.second.priv) { + GNURadio::KnobProp prop; + prop.type = GNURadio::KnobType::KNOBDOUBLE; + prop.units = p.second.units; + prop.description = p.second.description; + prop.min = rpcpmtconverter::from_pmt(p.second.min); + prop.max = rpcpmtconverter::from_pmt(p.second.max); + prop.display = static_cast<uint32_t>(p.second.display); + outknobs[p.first] = prop; + } + else { + std::cout << "Key " << p.first << " requires PRIVLVL <= " + << p.second.priv << " to get, currently at: " + << cur_priv << std::endl; + } + } + + TMap& d_getcallbackmap; + const priv_lvl_t& cur_priv; + TKnobMap& outknobs; + }; + + template<class T, typename TMap, typename TKnobMap> + struct properties_f : public std::unary_function<T,void> + { + properties_f(TMap &_getcallbackmap, const priv_lvl_t &_cur_priv, TKnobMap &_outknobs) : + d_getcallbackmap(_getcallbackmap), cur_priv(_cur_priv), outknobs(_outknobs) + {;} + + void operator()(const T& p) + { + typename TMap::const_iterator iter(d_getcallbackmap.find(p)); + if(iter != d_getcallbackmap.end()) { + if(cur_priv <= iter->second.priv) { + GNURadio::KnobProp prop; + prop.type = GNURadio::KnobType::KNOBDOUBLE; + prop.units = iter->second.units; + prop.description = iter->second.description; + prop.min = rpcpmtconverter::from_pmt(iter->second.min); + prop.max = rpcpmtconverter::from_pmt(iter->second.max); + prop.display = static_cast<uint32_t>(iter->second.display); + outknobs[p] = prop; + } + else { + std::cout << "Key " << iter->first << " requires PRIVLVL: <= " + << iter->second.priv << " to get, currently at: " << cur_priv << std::endl; + } + } + else { + throw apache::thrift::TApplicationException(__FILE__ " " S__LINE__); + } + } + + TMap& d_getcallbackmap; + const priv_lvl_t& cur_priv; + TKnobMap& outknobs; + }; +}; + +#endif /* RPCSERVER_THRIFT_H */ diff --git a/gnuradio-runtime/include/gnuradio/thrift_application_base.h b/gnuradio-runtime/include/gnuradio/thrift_application_base.h new file mode 100644 index 0000000000..d58f034a4f --- /dev/null +++ b/gnuradio-runtime/include/gnuradio/thrift_application_base.h @@ -0,0 +1,252 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 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 THRIFT_APPLICATION_BASE_H +#define THRIFT_APPLICATION_BASE_H + +#include <gnuradio/api.h> +#include <gnuradio/logger.h> +#include <gnuradio/prefs.h> +#include <gnuradio/thread/thread.h> +#include <boost/date_time/posix_time/posix_time.hpp> +#include <boost/scoped_ptr.hpp> + +namespace { + // Time, in milliseconds, to wait between checks to the Thrift runtime to see if + // it has fully initialized. + static const unsigned int THRIFTAPPLICATION_ACTIVATION_TIMEOUT_MS(200); +}; + +namespace apache { namespace thrift { namespace server { class TServer; } } } + +/*! + * \brief Class to be statically initialized by thrift_application_base. Used + * to store state for thrift_application_base's singleton functions. + */ + +class thrift_application_base_impl +{ +public: + thrift_application_base_impl() : + d_application_initilized(false), + d_endpointStr(""), + d_start_thrift_thread() {;} + + // Used to ensure the Thrift runtime is initialized on the first call to ::i(). + bool d_application_initilized; + // Stores the generated endpoint string after the Thrift runtime has initialized. + std::string d_endpointStr; + // Thread to execute the Thrift runtime's blocking serve() function. + boost::shared_ptr<gr::thread::thread> d_start_thrift_thread; +}; + +/*! + * \brief Base class for a Thrift application with a singleton with + * instance function thrift_application_base::i(). Lazy initialization + * is used to start the Thrift runtime, therefore the Thrift runtime + * is not started unless thrift_application_base::i() is called at + * least once. This typically means that at least one rpc variable + * must be registered by a block before the runtime will start. + * + * \param TserverBase Template parameter naming the type of the server + * base, which is typically rpcserverbase. + * \param TserverClass Template parameter naming the eventual type of + * the fully derived application. + * \param _app Reference to the fully derived application instance to + * be returned by thrift_application_base::i(). + */ + +template<typename TserverBase, typename TserverClass> +class thrift_application_base +{ +public: + thrift_application_base(TserverClass* _app); + + /*! + * Destructor for the application. Since shutdown and cleanup of the + * runtime is typically custom to a particular booter + * implementation, this must be implemented as a specialized function + * for a particular booter. Thus a template implementation is not + * provided here. + */ + ~thrift_application_base(); + + /*! + * The application singleton instance function. + */ + static TserverBase* i(); + + /*! + * Returns the endpoint string of this application. + */ + static const std::vector<std::string> endpoints(); + +protected: + /*! + * Allows this application's booter to set the endpoint string after + * the Thrift runtime has initialized. + * + * \param[in] endpoint The endpoint string reported by this class. + */ + void set_endpoint(const std::string& endpoint); + + virtual TserverBase* i_impl() = 0; + + /*! + * Reference to the fully derived application instance. + */ + static TserverClass* d_application; + + /*! + * Reference to the Thrift runtime. + */ + boost::scoped_ptr<apache::thrift::server::TServer> d_thriftserver; + + /*! + * Max number of attempts when checking the Thrift runtime for + * Initialization before giving up. Set in the Thrift config file + * (see \ref ctrlport_thrift_prefs). + */ + static const unsigned int d_default_max_init_attempts; + + /*! + * Default port for the runtime to listen on, if a static port is + * not specified. Set in the Thrift config file (see \ref + * ctrlport_thrift_prefs). + */ + static const unsigned int d_default_thrift_port; + + /*! + * Maximum number of threads to create when serving multiple rpc + * clients. Set in the Thrift config file (see \ref + * ctrlport_thrift_prefs). + */ + static const unsigned int d_default_num_thrift_threads; + + /*! + * Default packet size for the IP payload of thrift packets. Set in + * the Thrift config file (see \ref ctrlport_thrift_prefs). + */ + static const unsigned int d_default_thrift_buffer_size; + + /*! + * \ref page_logger instances. + */ + gr::logger_ptr d_logger, d_debug_logger; + +private: + + // Function to be called in a separate thread to invoke the blocking + // ThriftServer::serve() function. Must be specialized for a particular + // booter implementation, therefore a template implementation is + // not provided here. + void start_thrift(); + + // Non-blocking function that returns true when the Thrift + // runtime has finished initialization. Must be implemented + // as a specialized template function for a particular booter + // implementation, therefore template implementation is not + // provided here. + bool application_started(); + + // Internal function to start the initialization of the runtime. + // Since this singleton uses lazy instantiation, this function + // will be called on the first call to the instance function ::i(), + // and since ::i() is static, this function must be static as well. + static void start_application(); + + // Pointer to the structure containing staticly allocated + // state information for the applicaiton_base singleton. + static boost::scoped_ptr<thrift_application_base_impl > p_impl; + + // Mutex to protect the endpoint string. + gr::thread::mutex d_lock; + + // Will be set to true by a the application_started() function, + // specialized for a particular booter implementation, once the + // thrift runtime has successfully initialized. + bool d_thirft_is_running; +}; + +template<typename TserverBase, typename TserverClass> +TserverClass* thrift_application_base<TserverBase, TserverClass>::d_application(0); + +template<typename TserverBase, typename TserverClass> +thrift_application_base<TserverBase, TserverClass>::thrift_application_base(TserverClass* _app) + : d_lock(), + d_thirft_is_running(false) +{ + gr::configure_default_loggers(d_logger, d_debug_logger, "controlport"); + d_application = _app; +} + +template<typename TserverBase, typename TserverClass> +void thrift_application_base<TserverBase, TserverClass>::start_application() +{ + unsigned int max_init_attempts = \ + static_cast<unsigned int>(gr::prefs::singleton()->get_long("thrift", "init_attempts", + d_default_max_init_attempts)); + + if(!p_impl->d_application_initilized) { + p_impl->d_start_thrift_thread.reset( + (new gr::thread::thread(boost::bind(&thrift_application_base::start_thrift, d_application)))); + + bool app_started(false); + for(unsigned int attempts(0); (!app_started && attempts < max_init_attempts); ++attempts) { + boost::this_thread::sleep(boost::posix_time::milliseconds(THRIFTAPPLICATION_ACTIVATION_TIMEOUT_MS)); + app_started = d_application->application_started(); + } + + if(!app_started) { + GR_LOG_WARN(d_logger, "thrift_application_base::start_application(), " + "timeout waiting to port number might have failed?"); + } + + p_impl->d_application_initilized = true; + } +} + +template<typename TserverBase, typename TserverClass> +const std::vector<std::string> thrift_application_base<TserverBase, TserverClass>::endpoints() +{ + std::vector<std::string> ep; + ep.push_back(p_impl->d_endpointStr); + return ep; +} + +template<typename TserverBase, typename TserverClass> +void thrift_application_base<TserverBase, TserverClass>::set_endpoint(const std::string& endpoint) +{ + gr::thread::scoped_lock guard(d_lock); + p_impl->d_endpointStr = endpoint; +} + +template<typename TserverBase, typename TserverClass> +TserverBase* thrift_application_base<TserverBase, TserverClass>::i() +{ + if(!p_impl->d_application_initilized) { + start_application(); + } + return d_application->i_impl(); +} + +#endif diff --git a/gnuradio-runtime/include/gnuradio/thrift_server_template.h b/gnuradio-runtime/include/gnuradio/thrift_server_template.h new file mode 100644 index 0000000000..e2d6f63a69 --- /dev/null +++ b/gnuradio-runtime/include/gnuradio/thrift_server_template.h @@ -0,0 +1,159 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 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 THRIFT_SERVER_TEMPLATE_H +#define THRIFT_SERVER_TEMPLATE_H + +#include <gnuradio/prefs.h> +#include <gnuradio/logger.h> +#include <gnuradio/rpcserver_thrift.h> +#include <gnuradio/thrift_application_base.h> +#include <iostream> + +#include <thrift/server/TSimpleServer.h> +#include <thrift/server/TThreadPoolServer.h> +#include <thrift/concurrency/ThreadManager.h> +#include <thrift/concurrency/PlatformThreadFactory.h> +#include <thrift/transport/TServerSocket.h> +#include <thrift/transport/TBufferTransports.h> +#include "thrift/ControlPort.h" + +using namespace apache; + +template<typename TserverBase, typename TserverClass, typename TImplClass> +class thrift_server_template : public thrift_application_base<TserverBase, TImplClass> +{ +public: + thrift_server_template(TImplClass* _this); + ~thrift_server_template(); + +protected: + TserverBase* i_impl(); + friend class thrift_application_base<TserverBase, TImplClass>; + +private: + boost::shared_ptr<TserverClass> d_handler; + boost::shared_ptr<thrift::TProcessor> d_processor; + boost::shared_ptr<thrift::transport::TServerTransport> d_serverTransport; + boost::shared_ptr<thrift::transport::TTransportFactory> d_transportFactory; + boost::shared_ptr<thrift::protocol::TProtocolFactory> d_protocolFactory; + /** + * Custom TransportFactory that allows you to override the default Thrift buffer size + * of 512 bytes. + * + */ + class TBufferedTransportFactory : public thrift::transport::TTransportFactory + { + public: + TBufferedTransportFactory(const unsigned int _bufferSize) : bufferSize(_bufferSize) {;} + + virtual ~TBufferedTransportFactory() {} + + virtual boost::shared_ptr<thrift::transport::TTransport> getTransport( + boost::shared_ptr<thrift::transport::TTransport> trans) + { + return boost::shared_ptr<thrift::transport::TTransport> + (new thrift::transport::TBufferedTransport(trans, bufferSize)); + } + private: + unsigned int bufferSize; + }; +}; + +template<typename TserverBase, typename TserverClass, typename TImplClass> +thrift_server_template<TserverBase, TserverClass, TImplClass>::thrift_server_template(TImplClass* _this) + : thrift_application_base<TserverBase, TImplClass>(_this), + d_handler(new TserverClass()), + d_processor(new GNURadio::ControlPortProcessor(d_handler)), + d_serverTransport(), + d_transportFactory(), + d_protocolFactory(new thrift::protocol::TBinaryProtocolFactory()) +{ + gr::logger_ptr logger, debug_logger; + gr::configure_default_loggers(logger, debug_logger, "controlport"); + + unsigned int port, nthreads, buffersize; + std::string thrift_config_file = gr::prefs::singleton()->get_string("ControlPort", "config", ""); + + if(thrift_config_file.length() > 0) { + gr::prefs::singleton()->add_config_file(thrift_config_file); + } + + // Collect configuration options from the Thrift config file; + // defaults if the config file doesn't exist or list the specific + // options. + port = static_cast<unsigned int> + (gr::prefs::singleton()->get_long("thrift", "port", + thrift_application_base<TserverBase, + TImplClass>::d_default_thrift_port)); + nthreads = static_cast<unsigned int> + (gr::prefs::singleton()->get_long("thrift", "nthreads", + thrift_application_base<TserverBase, + TImplClass>::d_default_num_thrift_threads)); + buffersize = static_cast<unsigned int> + (gr::prefs::singleton()->get_long("thrift", "buffersize", + thrift_application_base<TserverBase, + TImplClass>::d_default_thrift_buffer_size)); + + d_serverTransport.reset(new thrift::transport::TServerSocket(port)); + + d_transportFactory.reset(new thrift_server_template::TBufferedTransportFactory(buffersize)); + + if(nthreads <= 1) { + // "Thrift: Single-threaded server" + //std::cout << "Thrift Single-threaded server" << std::endl; + thrift_application_base<TserverBase, TImplClass>::d_thriftserver.reset + (new thrift::server::TSimpleServer(d_processor, d_serverTransport, + d_transportFactory, d_protocolFactory)); + } + else { + //std::cout << "Thrift Multi-threaded server : " << d_nthreads << std::endl; + boost::shared_ptr<thrift::concurrency::ThreadManager> threadManager + (thrift::concurrency::ThreadManager::newSimpleThreadManager(nthreads)); + + threadManager->threadFactory + (boost::shared_ptr<thrift::concurrency::PlatformThreadFactory> + (new thrift::concurrency::PlatformThreadFactory())); + + threadManager->start(); + + thrift_application_base<TserverBase, TImplClass>::d_thriftserver.reset + (new thrift::server::TThreadPoolServer(d_processor, d_serverTransport, + d_transportFactory, d_protocolFactory, + threadManager)); + } +} + +template<typename TserverBase, typename TserverClass, typename TImplClass> +thrift_server_template<TserverBase, TserverClass,TImplClass>::~thrift_server_template() +{ +} + +template<typename TserverBase, typename TserverClass, typename TImplClass> +TserverBase* thrift_server_template<TserverBase, TserverClass, TImplClass>::i_impl() +{ + //std::cerr << "thrift_server_template: i_impl" << std::endl; + + return d_handler.get(); +} + +#endif /* THRIFT_SERVER_TEMPLATE_H */ diff --git a/gnuradio-runtime/lib/CMakeLists.txt b/gnuradio-runtime/lib/CMakeLists.txt index 6b4db0806f..cc51f97855 100644 --- a/gnuradio-runtime/lib/CMakeLists.txt +++ b/gnuradio-runtime/lib/CMakeLists.txt @@ -55,10 +55,15 @@ include_directories(${GNURADIO_RUNTIME_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}/../include/ ${VOLK_INCLUDE_DIRS} - ${THRIFT_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS} ) +if(ENABLE_CTRLPORT_THRIFT) + list(APPEND include_directories + ${THRIFT_INCLUDE_DIRS} + ) +endif(ENABLE_CTRLPORT_THRIFT) + ######################################################################## # Include subdirs rather to populate to the sources lists. ######################################################################## @@ -209,20 +214,23 @@ add_dependencies(gnuradio-runtime # STATIC LIB BUILD ####################################################### if(ENABLE_STATIC_LIBS) - # Remove controlport-specific source files from staticlibs build + # Remove controlport-specific source files from staticlibs build if + # ICE is the backend since it does not build statically. if(ENABLE_GR_CTRLPORT) - list(REMOVE_ITEM gnuradio_runtime_sources - ${gnuradio_ctrlport_sources} - ) - - # Remove GR_CTRLPORT set this target's definitions. - # Makes sure we don't try to use ControlPort stuff in source files - GET_DIRECTORY_PROPERTY(STATIC_DEFS COMPILE_DEFINITIONS) - list(REMOVE_ITEM STATIC_DEFS "GR_CTRLPORT") - SET_PROPERTY(DIRECTORY PROPERTY COMPILE_DEFINITIONS "${STATIC_DEFS}") - - # readd it to the target since we removed it from the directory-wide list. - SET_PROPERTY(TARGET gnuradio-runtime APPEND PROPERTY COMPILE_DEFINITIONS "GR_CTRLPORT") + if(ICE_FOUND) + list(REMOVE_ITEM gnuradio_runtime_sources + ${gnuradio_ctrlport_sources} + ) + + # Remove GR_CTRLPORT set this target's definitions. + # Makes sure we don't try to use ControlPort stuff in source files + GET_DIRECTORY_PROPERTY(STATIC_DEFS COMPILE_DEFINITIONS) + list(REMOVE_ITEM STATIC_DEFS "GR_CTRLPORT") + SET_PROPERTY(DIRECTORY PROPERTY COMPILE_DEFINITIONS "${STATIC_DEFS}") + + # readd it to the target since we removed it from the directory-wide list. + SET_PROPERTY(TARGET gnuradio-runtime APPEND PROPERTY COMPILE_DEFINITIONS "GR_CTRLPORT") + endif(ICE_FOUND) endif(ENABLE_GR_CTRLPORT) add_library(gnuradio-runtime_static STATIC ${gnuradio_runtime_sources}) diff --git a/gnuradio-runtime/lib/block.cc b/gnuradio-runtime/lib/block.cc index f26d6bb933..6edb73966d 100644 --- a/gnuradio-runtime/lib/block.cc +++ b/gnuradio-runtime/lib/block.cc @@ -842,42 +842,42 @@ namespace gr { d_rpc_vars.push_back( rpcbasic_sptr(new rpcbasic_register_get<block, std::vector<float> >( alias(), "input \% full", &block::pc_input_buffers_full, - pmt::make_c32vector(0,0), pmt::make_c32vector(0,1), pmt::make_c32vector(0,0), + pmt::make_f32vector(0,0), pmt::make_f32vector(0,1), pmt::make_f32vector(0,0), "", "how full input buffers are", RPC_PRIVLVL_MIN, DISPTIME | DISPOPTSTRIP))); d_rpc_vars.push_back( rpcbasic_sptr(new rpcbasic_register_get<block, std::vector<float> >( alias(), "avg input \% full", &block::pc_input_buffers_full_avg, - pmt::make_c32vector(0,0), pmt::make_c32vector(0,1), pmt::make_c32vector(0,0), + pmt::make_f32vector(0,0), pmt::make_f32vector(0,1), pmt::make_f32vector(0,0), "", "Average of how full input buffers are", RPC_PRIVLVL_MIN, DISPTIME | DISPOPTSTRIP))); d_rpc_vars.push_back( rpcbasic_sptr(new rpcbasic_register_get<block, std::vector<float> >( alias(), "var input \% full", &block::pc_input_buffers_full_var, - pmt::make_c32vector(0,0), pmt::make_c32vector(0,1), pmt::make_c32vector(0,0), + pmt::make_f32vector(0,0), pmt::make_f32vector(0,1), pmt::make_f32vector(0,0), "", "Var. of how full input buffers are", RPC_PRIVLVL_MIN, DISPTIME | DISPOPTSTRIP))); d_rpc_vars.push_back( rpcbasic_sptr(new rpcbasic_register_get<block, std::vector<float> >( alias(), "output \% full", &block::pc_output_buffers_full, - pmt::make_c32vector(0,0), pmt::make_c32vector(0,1), pmt::make_c32vector(0,0), + pmt::make_f32vector(0,0), pmt::make_f32vector(0,1), pmt::make_f32vector(0,0), "", "how full output buffers are", RPC_PRIVLVL_MIN, DISPTIME | DISPOPTSTRIP))); d_rpc_vars.push_back( rpcbasic_sptr(new rpcbasic_register_get<block, std::vector<float> >( alias(), "avg output \% full", &block::pc_output_buffers_full_avg, - pmt::make_c32vector(0,0), pmt::make_c32vector(0,1), pmt::make_c32vector(0,0), + pmt::make_f32vector(0,0), pmt::make_f32vector(0,1), pmt::make_f32vector(0,0), "", "Average of how full output buffers are", RPC_PRIVLVL_MIN, DISPTIME | DISPOPTSTRIP))); d_rpc_vars.push_back( rpcbasic_sptr(new rpcbasic_register_get<block, std::vector<float> >( alias(), "var output \% full", &block::pc_output_buffers_full_var, - pmt::make_c32vector(0,0), pmt::make_c32vector(0,1), pmt::make_c32vector(0,0), + pmt::make_f32vector(0,0), pmt::make_f32vector(0,1), pmt::make_f32vector(0,0), "", "Var. of how full output buffers are", RPC_PRIVLVL_MIN, DISPTIME | DISPOPTSTRIP))); #endif /* defined(GR_CTRLPORT) && defined(GR_PERFORMANCE_COUNTERS) */ diff --git a/gnuradio-runtime/lib/controlport/CMakeLists.txt b/gnuradio-runtime/lib/controlport/CMakeLists.txt index 262c5adb8b..f0d2618c01 100644 --- a/gnuradio-runtime/lib/controlport/CMakeLists.txt +++ b/gnuradio-runtime/lib/controlport/CMakeLists.txt @@ -19,8 +19,13 @@ if(ENABLE_GR_CTRLPORT) +# Keep track of the number of backends ControlPort supports +SET(CTRLPORT_BACKENDS 0) + # Add definition so we can compile in ControlPort to the blocks. -ADD_DEFINITIONS(-DGR_CTRLPORT) +add_definitions(-DGR_CTRLPORT) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) list(APPEND gnuradio_ctrlport_sources ${CMAKE_CURRENT_SOURCE_DIR}/rpcmanager.cc @@ -29,14 +34,71 @@ list(APPEND gnuradio_ctrlport_sources ${CMAKE_CURRENT_SOURCE_DIR}/rpcserver_selector.cc ) + +OPTION(ENABLE_CTRLPORT_THRIFT "Enable ControlPort Thrift support" ON) + +if(ENABLE_CTRLPORT_THRIFT) + +# Look if Thrift is installed and use it as a ControlPort backend. +FIND_PACKAGE(Thrift) + +if(THRIFT_FOUND) + +MATH(EXPR CTRLPORT_BACKENDS "${CTRLPORT_BACKENDS} + 1") + +# Indicate thrift as an installed backend in the cmake summary. +message(STATUS "Found and enabling Thrift backend to ControlPort") +GR_APPEND_SUBCOMPONENT("thrift") + +# Run Thrrift To compile C++ and Python files +message(STATUS "Running thrift to build C++ bindings") +file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/thrift/) +EXECUTE_PROCESS( + COMMAND ${THRIFT_BIN} --gen cpp -out ${CMAKE_CURRENT_BINARY_DIR}/thrift/ ${CMAKE_CURRENT_SOURCE_DIR}/thrift/gnuradio.thrift + OUTPUT_VARIABLE THRIFT_CPP_OUTPUT + ERROR_VARIABLE THRIFT_CPP_ERROR + ) + +list(APPEND gnuradio_ctrlport_sources + ${CMAKE_CURRENT_SOURCE_DIR}/thrift/rpcserver_thrift.cc + ${CMAKE_CURRENT_SOURCE_DIR}/thrift/rpcpmtconverters_thrift.cc + ${CMAKE_CURRENT_SOURCE_DIR}/thrift/rpcserver_booter_thrift.cc + ${CMAKE_CURRENT_SOURCE_DIR}/thrift/thrift_application_base.cc +) + +# add files built by compiling gnuradio.thrift +list(APPEND gnuradio_ctrlport_sources + ${CMAKE_CURRENT_BINARY_DIR}/thrift/gnuradio_types.cpp + ${CMAKE_CURRENT_BINARY_DIR}/thrift/gnuradio_constants.cpp + ${CMAKE_CURRENT_BINARY_DIR}/thrift/ControlPort.cpp +) + +# Add required libraries here +list(APPEND gnuradio_runtime_libs + ${THRIFT_LIBRARIES} +) + +# Add install rule to move example Thrift configuration file into +# $prefix/etc/gnuradio +install( + FILES ${CMAKE_CURRENT_SOURCE_DIR}/thrift/thrift.conf.example + DESTINATION ${SYSCONFDIR}/${CMAKE_PROJECT_NAME} + COMPONENT "runtime_runtime" +) + +endif(THRIFT_FOUND) +endif(ENABLE_CTRLPORT_THRIFT) + ######################################################################## # Add controlport stuff to gnuradio-runtime ######################################################################## include_directories(${CMAKE_CURRENT_BINARY_DIR}) -# Add any required libraries here -#list(APPEND gnuradio_runtime_libs -#) +# Save the number of backends for testing against later +set( + CTRLPORT_BACKENDS ${CTRLPORT_BACKENDS} + CACHE INTERNAL "Number of ControlPort backends available" +) endif(ENABLE_GR_CTRLPORT) diff --git a/gnuradio-runtime/lib/controlport/rpcmanager.cc b/gnuradio-runtime/lib/controlport/rpcmanager.cc index 0c7bc135be..a67febe386 100644 --- a/gnuradio-runtime/lib/controlport/rpcmanager.cc +++ b/gnuradio-runtime/lib/controlport/rpcmanager.cc @@ -26,16 +26,12 @@ bool rpcmanager::booter_registered(false); bool rpcmanager::aggregator_registered(false); -rpcserver_booter_base* rpcmanager::boot(0); +std::auto_ptr<rpcserver_booter_base> rpcmanager::boot(0); std::auto_ptr<rpcserver_booter_aggregator> rpcmanager::aggregator(0); rpcmanager::rpcmanager() {;} -rpcmanager::~rpcmanager() -{ - if(boot) - delete boot; -} +rpcmanager::~rpcmanager() {;} rpcserver_booter_base* rpcmanager::get() @@ -44,10 +40,10 @@ rpcmanager::get() return aggregator.get(); } else if(booter_registered) { - return boot; + return boot.get(); } assert(booter_registered || aggregator_registered); - return boot; + return boot.get(); } void @@ -63,7 +59,7 @@ rpcmanager::register_booter(rpcserver_booter_base* booter) aggregator->agg()->registerServer(bootreg); } else if(!booter_registered) { - boot = booter; + boot.reset(booter); booter_registered = true; } else { diff --git a/gnuradio-runtime/lib/controlport/rpcserver_booter_aggregator.cc b/gnuradio-runtime/lib/controlport/rpcserver_booter_aggregator.cc index 201dfb3929..a1983b4ac5 100644 --- a/gnuradio-runtime/lib/controlport/rpcserver_booter_aggregator.cc +++ b/gnuradio-runtime/lib/controlport/rpcserver_booter_aggregator.cc @@ -23,7 +23,8 @@ #include <gnuradio/rpcserver_booter_aggregator.h> rpcserver_booter_aggregator::rpcserver_booter_aggregator() : - d_type(std::string("aggregator")), server(new rpcserver_aggregator()) + d_type(std::string("aggregator")), + server(new rpcserver_aggregator()) {;} rpcserver_booter_aggregator::~rpcserver_booter_aggregator() diff --git a/gnuradio-runtime/lib/controlport/rpcserver_selector.cc b/gnuradio-runtime/lib/controlport/rpcserver_selector.cc index 692f151958..8f3b4557c2 100644 --- a/gnuradio-runtime/lib/controlport/rpcserver_selector.cc +++ b/gnuradio-runtime/lib/controlport/rpcserver_selector.cc @@ -26,14 +26,23 @@ bool rpcmanager::make_aggregator(false); -#ifdef RPCSERVER_ICE +#ifdef GR_RPCSERVER_ENABLED +rpcmanager manager_instance; +#endif + +#ifdef GR_RPCSERVER_ICE #error TODO ICE #endif -#ifdef RPCSERVER_ERLANG +#ifdef GR_RPCSERVER_THRIFT +#include <gnuradio/rpcserver_booter_thrift.h> +rpcmanager::rpcserver_booter_register_helper<rpcserver_booter_thrift> boot_thrift; +#endif + +#ifdef GR_RPCSERVER_ERLANG #error TODO ERLANG #endif -#ifdef RPCSERVER_XMLRPC +#ifdef GR_RPCSERVER_XMLRPC #error TODO XMLRPC #endif diff --git a/gnuradio-runtime/lib/controlport/thrift/README b/gnuradio-runtime/lib/controlport/thrift/README new file mode 100644 index 0000000000..5448e512f7 --- /dev/null +++ b/gnuradio-runtime/lib/controlport/thrift/README @@ -0,0 +1,41 @@ +For info on ControlPort and Thrift, see the wiki page: + +http://gnuradio.org/redmine/projects/gnuradio/wiki/ControlPort + +This readme is to address the patch file in the repo for Thrift. We +believe that there is a bug in Thrift itself that occasionally causes +a segfault when shutting down the server. If you run into a problem +when shutting down an application running ControlPort, this might be +the cause. If so, we have included a patch with the source code in +this directory that should be applied to Thrift before rebuilding the +Thrift library: + +thrift-codebase-shutdown-patch.diff + +Note that we are working off Thrift version 0.9.2, so this patch may +not be relevant or even cleanly apply in later versions of Thrift. + +We are also still trying to track down another shutdown problem with +Thrift that again appears to be related to their code. If a segfault +persists after the above patch is applied to Thrift, do a backtrace in +GDB to see what the error looks like. If it is different than the +following backtrace, definitely report it to the Discuss GNU Radio +Mailing List as a known bug. If you see the same backtrace as here, +this is a known bug that occurs very irregularly, but help in tracing +down the cause is appreciated. + +#0 0x00007f07b5b478c2 in ?? () from /lib/x86_64-linux-gnu/libc.so.6 +(gdb) bt +#0 0x00007f07b5b478c2 in ?? () from /lib/x86_64-linux-gnu/libc.so.6 +#1 0x00007f07b5b4856d in ?? () from /lib/x86_64-linux-gnu/libc.so.6 +#2 0x00007f07afc924c5 in std::locale::_Impl::~_Impl() () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6 +#3 0x00007f07afc925fd in std::locale::~locale() () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6 +#4 0x00007f07b5b05259 in ?? () from /lib/x86_64-linux-gnu/libc.so.6 +#5 0x00007f07b5b052a5 in exit () from /lib/x86_64-linux-gnu/libc.so.6 +#6 0x000000000042fb83 in Py_Exit () +#7 0x000000000042fcb9 in ?? () +#8 0x000000000042ec32 in PyErr_PrintEx () +#9 0x0000000000469f2f in PyRun_SimpleFileExFlags () +#10 0x000000000046ab81 in Py_Main () +#11 0x00007f07b5aeaec5 in __libc_start_main () from /lib/x86_64-linux-gnu/libc.so.6 +#12 0x000000000057497e in _start () diff --git a/gnuradio-runtime/lib/controlport/thrift/gnuradio.thrift b/gnuradio-runtime/lib/controlport/thrift/gnuradio.thrift new file mode 100644 index 0000000000..ae7f839a2f --- /dev/null +++ b/gnuradio-runtime/lib/controlport/thrift/gnuradio.thrift @@ -0,0 +1,108 @@ +/* + * Copyright 2014,2015 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. + */ + +namespace cpp GNURadio +namespace py GNURadio + +struct complex { + 1: double re; + 2: double im; +} + +typedef list<bool> VectorB +typedef binary VectorC +typedef list<i16> VectorT +typedef list<i32> VectorI +typedef list<i64> VectorL +typedef list<double> VectorF +typedef list<double> VectorD +typedef list<string> VectorS +typedef list<complex> VectorZ + +enum BaseTypes { BOOL, BYTE, SHORT, INT, LONG, DOUBLE, STRING, COMPLEX, + F32VECTOR, F64VECTOR, S64VECTOR, S32VECTOR, S16VECTOR, + S8VECTOR, C32VECTOR } + +union KnobBase { + 1: bool a_bool; + 2: byte a_byte; + 3: i16 a_short; + 4: i32 a_int; + 5: i64 a_long; + 6: double a_double; + 7: string a_string; + 8: complex a_complex; + 9: VectorF a_f32vector; + 10: VectorD a_f64vector; + 11: VectorL a_s64vector; + 12: VectorI a_s32vector; + 13: VectorT a_s16vector; + 14: VectorC a_s8vector; + 15: VectorZ a_c32vector; +} + +struct Knob { + 1: BaseTypes type; + 2: KnobBase value; +} + +enum KnobType { KNOBBOOL, KNOBCHAR, KNOBINT, KNOBDOUBLE, KNOBSTRING, + KNOBLONG, KNOBVECBOOL, KNOBVECCHAR, KNOBVECINT, + KNOBVECDOUBLE, KNOBVECSTRING, KNOBVECLONG, KNOBSHORT} + +const i32 DISPNULL = 0x0000 +const i32 DISPTIME = 0x0001 +const i32 DISPXY = 0x0002 +const i32 DISPPSD = 0x0004 +const i32 DISPSPEC = 0x0008 +const i32 DISPRAST = 0x0010 +const i32 DISPOPTCPLX = 0x0100 +const i32 DISPOPTLOG = 0x0200 +const i32 DISPOPTSTEM = 0x0400 +const i32 DISPOPTSTRIP = 0x0800 +const i32 DISPOPTSCATTER = 0x1000 + +struct KnobProp { + 1: KnobType type, + 2: string units, + 3: string description, + 4: i32 display, + 5: Knob min, + 6: Knob max, + 7: Knob defaultvalue +} + +typedef list<string> KnobIDList +typedef map<string, Knob> KnobMap +typedef map<string, KnobProp> KnobPropMap +typedef map<string, string> WaveformArgMap + +service StreamReceiver { + void push(1:VectorC data); +} + +service ControlPort { + void setKnobs(1:KnobMap knobs); + KnobMap getKnobs(1:KnobIDList knobs); + KnobMap getRe(1:KnobIDList knobs); + KnobPropMap properties(1:KnobIDList knobs); + void shutdown(); +} diff --git a/gnuradio-runtime/lib/controlport/thrift/rpcpmtconverters_thrift.cc b/gnuradio-runtime/lib/controlport/thrift/rpcpmtconverters_thrift.cc new file mode 100644 index 0000000000..cc8804f79d --- /dev/null +++ b/gnuradio-runtime/lib/controlport/thrift/rpcpmtconverters_thrift.cc @@ -0,0 +1,303 @@ +/* + * Copyright 2014,2015 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. + */ + +#include <boost/assign/ptr_map_inserter.hpp> +#include <gnuradio/rpcpmtconverters_thrift.h> +#include <gnuradio/gr_complex.h> +#include "thrift/gnuradio_types.h" +#include <iostream> + +GNURadio::Knob +rpcpmtconverter::from_pmt(const pmt::pmt_t& knob) +{ + if(pmt::is_real(knob)) { + GNURadio::Knob result; + result.type = GNURadio::BaseTypes::DOUBLE; + result.value.__set_a_double(pmt::to_double(knob)); + return result; + } + else if(pmt::is_symbol(knob)) { + std::string value = pmt::symbol_to_string(knob); + GNURadio::Knob result; + result.type = GNURadio::BaseTypes::STRING; + result.value.__set_a_string(value); + return result; + } + else if(pmt::is_integer(knob)) { + GNURadio::Knob result; + result.type = GNURadio::BaseTypes::LONG; + result.value.__set_a_long(pmt::to_long(knob)); + return result; + } + else if(pmt::is_bool(knob)) { + GNURadio::Knob result; + result.type = GNURadio::BaseTypes::BOOL; + result.value.__set_a_bool(pmt::to_bool(knob)); + return result; + } + else if(pmt::is_uint64(knob)) { + GNURadio::Knob result; + result.type = GNURadio::BaseTypes::LONG; + result.value.__set_a_long(pmt::to_uint64(knob)); + return result; + } + else if(pmt::is_complex(knob)) { + GNURadio::Knob result; + result.type = GNURadio::BaseTypes::COMPLEX; + std::complex<double> tmp = pmt::to_complex(knob); + GNURadio::complex cpx; + cpx.re = tmp.real(); + cpx.im = tmp.imag(); + result.value.__set_a_complex(cpx); + return result; + } + else if(pmt::is_f32vector(knob)) { + GNURadio::Knob result; + result.type = GNURadio::BaseTypes::F32VECTOR; + size_t size(pmt::length(knob)); + const float* start((const float*)pmt::f32vector_elements(knob,size)); + result.value.__set_a_f32vector(std::vector<double>(start,start+size)); + return result; + } + else if(pmt::is_f64vector(knob)) { + GNURadio::Knob result; + result.type = GNURadio::BaseTypes::F64VECTOR; + size_t size(pmt::length(knob)); + const double* start((const double*)pmt::f64vector_elements(knob,size)); + result.value.__set_a_f64vector(std::vector<double>(start,start+size)); + return result; + } + else if(pmt::is_s64vector(knob)) { + GNURadio::Knob result; + result.type = GNURadio::BaseTypes::S64VECTOR; + size_t size(pmt::length(knob)); + const int64_t* start((const int64_t*)pmt::s64vector_elements(knob,size)); + result.value.__set_a_s64vector(std::vector<int64_t>(start,start+size)); + return result; + } + else if(pmt::is_s32vector(knob)) { + GNURadio::Knob result; + result.type = GNURadio::BaseTypes::S32VECTOR; + size_t size(pmt::length(knob)); + const int32_t* start((const int32_t*)pmt::s32vector_elements(knob,size)); + result.value.__set_a_s32vector(std::vector<int32_t>(start,start+size)); + return result; + } + else if(pmt::is_s16vector(knob)) { + GNURadio::Knob result; + result.type = GNURadio::BaseTypes::S16VECTOR; + size_t size(pmt::length(knob)); + const int16_t* start((const int16_t*)pmt::s16vector_elements(knob,size)); + result.value.__set_a_s16vector(std::vector<int16_t>(start,start+size)); + return result; + } + else if(pmt::is_s8vector(knob)) { + GNURadio::Knob result; + result.type = GNURadio::BaseTypes::S8VECTOR; + size_t size(pmt::length(knob)); + const int8_t* start((const int8_t*)pmt::s8vector_elements(knob,size)); + result.value.__set_a_s8vector(std::basic_string<char>(start,start+size)); + return result; + } + else if(pmt::is_c32vector(knob)) { + std::vector< GNURadio::complex > z; + + GNURadio::Knob result; + result.type = GNURadio::BaseTypes::C32VECTOR; + size_t size(pmt::length(knob)); + const gr_complex* start((const gr_complex*)pmt::c32vector_elements(knob,size)); + for(size_t s = 0; s < size; s++) { + GNURadio::complex z0; + gr_complex z1 = gr_complex(*(start+s)); + z0.__set_re(z1.real()); + z0.__set_im(z1.imag()); + z.push_back(z0); + } + result.value.__set_a_c32vector(z); + return result; + } + else { + std::cerr << "Error: Don't know how to handle Knob Type (from): " << knob << std::endl; + assert(0); + } + return GNURadio::Knob(); +} + +pmt::pmt_t +rpcpmtconverter::to_pmt_byte_f::operator()(const GNURadio::Knob& knob) +{ + return pmt::mp(knob.value.a_byte); +} + +pmt::pmt_t +rpcpmtconverter::to_pmt_short_f::operator()(const GNURadio::Knob& knob) +{ + return pmt::mp(knob.value.a_short); +} + +pmt::pmt_t +rpcpmtconverter::to_pmt_int_f::operator()(const GNURadio::Knob& knob) +{ + return pmt::mp(knob.value.a_int); +} + +pmt::pmt_t +rpcpmtconverter::to_pmt_long_f::operator()(const GNURadio::Knob& knob) +{ + return pmt::from_long(knob.value.a_long); +} + +pmt::pmt_t +rpcpmtconverter::to_pmt_double_f::operator()(const GNURadio::Knob& knob) +{ + return pmt::mp(knob.value.a_double); +} + +pmt::pmt_t +rpcpmtconverter::to_pmt_string_f::operator()(const GNURadio::Knob& knob) +{ + return pmt::string_to_symbol(knob.value.a_string); +} + +pmt::pmt_t +rpcpmtconverter::to_pmt_bool_f::operator()(const GNURadio::Knob& knob) +{ + if(knob.value.a_bool) + return pmt::PMT_T; + else + return pmt::PMT_F; +} + +pmt::pmt_t +rpcpmtconverter::to_pmt_complex_f::operator()(const GNURadio::Knob& knob) +{ + gr_complexd cpx(knob.value.a_complex.re, knob.value.a_complex.im); + return pmt::from_complex(cpx); +} + +pmt::pmt_t +rpcpmtconverter::to_pmt_f32vect_f::operator()(const GNURadio::Knob& knob) +{ + std::vector<double> v_double = knob.value.a_f32vector; + std::vector<float> v(v_double.begin(), v_double.end()); + return pmt::init_f32vector(v.size(), v); +} + +pmt::pmt_t +rpcpmtconverter::to_pmt_f64vect_f::operator()(const GNURadio::Knob& knob) +{ + std::vector<double> v = knob.value.a_f64vector; + return pmt::init_f64vector(v.size(), v); +} + +pmt::pmt_t +rpcpmtconverter::to_pmt_s64vect_f::operator()(const GNURadio::Knob& knob) +{ + std::vector<int64_t> v = knob.value.a_s64vector; + return pmt::init_s64vector(v.size(), v); +} + +pmt::pmt_t +rpcpmtconverter::to_pmt_s32vect_f::operator()(const GNURadio::Knob& knob) +{ + std::vector<int32_t> v = knob.value.a_s32vector; + return pmt::init_s32vector(v.size(), v); +} + +pmt::pmt_t +rpcpmtconverter::to_pmt_s16vect_f::operator()(const GNURadio::Knob& knob) +{ + std::vector<int16_t> v = knob.value.a_s16vector; + return pmt::init_s16vector(v.size(), v); +} + +pmt::pmt_t +rpcpmtconverter::to_pmt_s8vect_f::operator()(const GNURadio::Knob& knob) +{ + std::basic_string<char> v = knob.value.a_s8vector; + return pmt::init_s8vector(v.size(), reinterpret_cast<const int8_t*>(v.data())); +} + +pmt::pmt_t +rpcpmtconverter::to_pmt_c32vect_f::operator()(const GNURadio::Knob& knob) +{ + std::vector<GNURadio::complex> v0 = knob.value.a_c32vector; + std::vector<GNURadio::complex>::iterator vitr; + std::vector<gr_complex> v; + for(vitr = v0.begin(); vitr != v0.end(); vitr++) { + v.push_back(gr_complex(vitr->re, vitr->im)); + } + return pmt::init_c32vector(v.size(), v); +} + +rpcpmtconverter::To_PMT rpcpmtconverter::To_PMT::instance; + +rpcpmtconverter::to_pmt_reg<rpcpmtconverter::to_pmt_bool_f> reg_bool(rpcpmtconverter::To_PMT::instance, + GNURadio::BaseTypes::BOOL); +rpcpmtconverter::to_pmt_reg<rpcpmtconverter::to_pmt_byte_f> reg_byte(rpcpmtconverter::To_PMT::instance, + GNURadio::BaseTypes::BYTE); +rpcpmtconverter::to_pmt_reg<rpcpmtconverter::to_pmt_short_f> reg_short(rpcpmtconverter::To_PMT::instance, + GNURadio::BaseTypes::SHORT); +rpcpmtconverter::to_pmt_reg<rpcpmtconverter::to_pmt_int_f> reg_int(rpcpmtconverter::To_PMT::instance, + GNURadio::BaseTypes::INT); +rpcpmtconverter::to_pmt_reg<rpcpmtconverter::to_pmt_long_f> reg_long(rpcpmtconverter::To_PMT::instance, + GNURadio::BaseTypes::LONG); +rpcpmtconverter::to_pmt_reg<rpcpmtconverter::to_pmt_double_f> reg_double(rpcpmtconverter::To_PMT::instance, + GNURadio::BaseTypes::DOUBLE); +rpcpmtconverter::to_pmt_reg<rpcpmtconverter::to_pmt_string_f> reg_string(rpcpmtconverter::To_PMT::instance, + GNURadio::BaseTypes::STRING); +rpcpmtconverter::to_pmt_reg<rpcpmtconverter::to_pmt_complex_f> reg_complex(rpcpmtconverter::To_PMT::instance, + GNURadio::BaseTypes::COMPLEX); +rpcpmtconverter::to_pmt_reg<rpcpmtconverter::to_pmt_f32vect_f> reg_f32v(rpcpmtconverter::To_PMT::instance, + GNURadio::BaseTypes::F32VECTOR); +rpcpmtconverter::to_pmt_reg<rpcpmtconverter::to_pmt_f64vect_f> reg_f64v(rpcpmtconverter::To_PMT::instance, + GNURadio::BaseTypes::F64VECTOR); +rpcpmtconverter::to_pmt_reg<rpcpmtconverter::to_pmt_s64vect_f> reg_s64v(rpcpmtconverter::To_PMT::instance, + GNURadio::BaseTypes::S64VECTOR); +rpcpmtconverter::to_pmt_reg<rpcpmtconverter::to_pmt_s32vect_f> reg_s32v(rpcpmtconverter::To_PMT::instance, + GNURadio::BaseTypes::S32VECTOR); +rpcpmtconverter::to_pmt_reg<rpcpmtconverter::to_pmt_s16vect_f> reg_s16v(rpcpmtconverter::To_PMT::instance, + GNURadio::BaseTypes::S16VECTOR); +rpcpmtconverter::to_pmt_reg<rpcpmtconverter::to_pmt_s8vect_f> reg_s8v(rpcpmtconverter::To_PMT::instance, + GNURadio::BaseTypes::S8VECTOR); +rpcpmtconverter::to_pmt_reg<rpcpmtconverter::to_pmt_c32vect_f> reg_c32v(rpcpmtconverter::To_PMT::instance, + GNURadio::BaseTypes::C32VECTOR); + +template<typename TO_PMT_F> +rpcpmtconverter::to_pmt_reg<TO_PMT_F>::to_pmt_reg(To_PMT& instance, + const GNURadio::BaseTypes::type type) +{ + boost::assign::ptr_map_insert<TO_PMT_F>(instance.to_pmt_map)(type); +} + +pmt::pmt_t +rpcpmtconverter::to_pmt_f::operator()(const GNURadio::Knob& knob) +{ + std::cerr << "Error: Don't know how to handle Knob Type: " << knob.type << std::endl; + assert(0); + return pmt::pmt_t(); +} + +pmt::pmt_t +rpcpmtconverter::To_PMT::operator()(const GNURadio::Knob& knob) +{ + return to_pmt_map[knob.type](knob); +} diff --git a/gnuradio-runtime/lib/controlport/thrift/rpcserver_booter_thrift.cc b/gnuradio-runtime/lib/controlport/thrift/rpcserver_booter_thrift.cc new file mode 100644 index 0000000000..1d6cafe0c0 --- /dev/null +++ b/gnuradio-runtime/lib/controlport/thrift/rpcserver_booter_thrift.cc @@ -0,0 +1,133 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 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. + */ + +#include <gnuradio/rpcserver_thrift.h> +#include <gnuradio/rpcserver_booter_thrift.h> + +#include <boost/asio/ip/host_name.hpp> + +namespace { + static const char* const CONTROL_PORT_CLASS("thrift"); + static const unsigned int ETHERNET_HEADER_SIZE(14); + static const unsigned int IP_HEADER_SIZE(20); + static const unsigned int TCP_HEADER_SIZE(32); + static const unsigned int ETHERNET_TYPICAL_MTU(1500); + static const unsigned int ALRIGHT_DEFAULT_BUFFER_SIZE( + ETHERNET_TYPICAL_MTU - ETHERNET_HEADER_SIZE - IP_HEADER_SIZE - TCP_HEADER_SIZE); +}; + +/*! + * \brief A booter implementation for a Thrift application class. + */ + +rpcserver_booter_thrift::rpcserver_booter_thrift() : + thrift_server_template<rpcserver_base, + rpcserver_thrift, + rpcserver_booter_thrift>(this), + d_type(std::string(CONTROL_PORT_CLASS)) +{;} + +rpcserver_booter_thrift::~rpcserver_booter_thrift() +{;} + +rpcserver_base* +rpcserver_booter_thrift::i() +{ + return thrift_server_template<rpcserver_base, rpcserver_thrift, + rpcserver_booter_thrift>::i(); +} + +/*! + * \brief Returns the endpoint string for the application + */ + +const std::vector<std::string> +rpcserver_booter_thrift::endpoints() +{ + return thrift_server_template<rpcserver_base, rpcserver_thrift, + rpcserver_booter_thrift>::endpoints(); +} + +// Specialized thrift_application_base attributes and functions +// for this rpcserver_booter instance. + +template<class rpcserver_base, class rpcserver_booter_thrift> +const unsigned int thrift_application_base<rpcserver_base, rpcserver_booter_thrift>::d_default_max_init_attempts(100U); + +template<class rpcserver_base, class rpcserver_booter_thrift> +const unsigned int thrift_application_base<rpcserver_base, rpcserver_booter_thrift>::d_default_thrift_port(0U); + +template<class rpcserver_base, class rpcserver_booter_thrift> +const unsigned int thrift_application_base<rpcserver_base, rpcserver_booter_thrift>::d_default_num_thrift_threads(10U); + +template<class rpcserver_base, class rpcserver_booter_thrift> +const unsigned int thrift_application_base<rpcserver_base, rpcserver_booter_thrift>::d_default_thrift_buffer_size( + ALRIGHT_DEFAULT_BUFFER_SIZE); + +template<class rpcserver_base, class rpcserver_booter_thrift> +boost::scoped_ptr<thrift_application_base_impl> + thrift_application_base<rpcserver_base, rpcserver_booter_thrift>::p_impl( + new thrift_application_base_impl()); + +template<class rpcserver_base, class rpcserver_booter_thrift> +thrift_application_base<rpcserver_base, rpcserver_booter_thrift>::~thrift_application_base() +{ + if(d_thirft_is_running) { + d_thriftserver->stop(); + d_thirft_is_running = false; + } +} + +template<class rpcserver_base, class rpcserver_booter_thrift> +void thrift_application_base<rpcserver_base, rpcserver_booter_thrift>::start_thrift() +{ + d_thriftserver->serve(); +} + +template<class rpcserver_base, typename rpcserver_booter_thrift> +bool thrift_application_base<rpcserver_base, rpcserver_booter_thrift>::application_started() +{ + if (d_thirft_is_running) return true; + + bool result(false); + // Define the endpoint. + apache::thrift::transport::TServerTransport *thetransport = + d_thriftserver->getServerTransport().get(); + + // Determine the specified endpoint port number, or the port number selected by bind() if + int used_port = ((apache::thrift::transport::TServerSocket*)thetransport)->getPort(); + + if (used_port > 0) { + // Determine the hostname of this host + const std::string boost_hostname(boost::asio::ip::host_name()); + + std::string endpoint = boost::str(boost::format("-h %1% -p %2%") % boost_hostname % used_port); + + set_endpoint(endpoint); + + GR_LOG_INFO(d_logger, "Apache Thrift: " + endpoint); + d_thirft_is_running = true; + result = true; + } + + return result; +} diff --git a/gnuradio-runtime/lib/controlport/thrift/rpcserver_thrift.cc b/gnuradio-runtime/lib/controlport/thrift/rpcserver_thrift.cc new file mode 100644 index 0000000000..3e6eabc854 --- /dev/null +++ b/gnuradio-runtime/lib/controlport/thrift/rpcserver_thrift.cc @@ -0,0 +1,202 @@ +/* -*- c++ -*- */ +/* + * Copyright 2014,2015 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. + */ + +#include <gnuradio/rpcserver_thrift.h> +#include <iostream> +#include <sstream> +#include <stdexcept> +#include <pmt/pmt.h> +#include <thrift/protocol/TBinaryProtocol.h> +#include <thrift/transport/TSocket.h> +#include <thrift/transport/TTransportUtils.h> +#include <boost/xpressive/xpressive.hpp> +#include "thrift/ControlPort.h" + +#define DEBUG 0 + +using namespace rpcpmtconverter; + +rpcserver_thrift::rpcserver_thrift() +{ + //std::cerr << "rpcserver_thrift::ctor" << std::endl; +} + +rpcserver_thrift::~rpcserver_thrift() +{ + //std::cerr << "rpcserver_thrift::dtor" << std::endl; +} + +void +rpcserver_thrift::registerConfigureCallback(const std::string &id, + const configureCallback_t callback) +{ + boost::mutex::scoped_lock lock(d_callback_map_lock); + { + ConfigureCallbackMap_t::const_iterator iter(d_setcallbackmap.find(id)); + if(iter != d_setcallbackmap.end()) { + std::stringstream s; + s << "rpcserver_thrift:: rpcserver_thrift ERROR registering set, already registered: " + << id << std::endl; + throw std::runtime_error(s.str().c_str()); + } + } + + if(DEBUG) { + std::cerr << "rpcserver_thrift registering set: " << id << std::endl; + } + d_setcallbackmap.insert(ConfigureCallbackMap_t::value_type(id, callback)); +} + +void +rpcserver_thrift::unregisterConfigureCallback(const std::string &id) +{ + boost::mutex::scoped_lock lock(d_callback_map_lock); + ConfigureCallbackMap_t::iterator iter(d_setcallbackmap.find(id)); + if(iter == d_setcallbackmap.end()) { + std::stringstream s; + s << "rpcserver_thrift:: rpcserver_thrift ERROR unregistering set, not registered: " + << id << std::endl; + throw std::runtime_error(s.str().c_str()); + } + + if(DEBUG) + std::cerr << "rpcserver_thrift unregistering set: " << id << std::endl; + + d_setcallbackmap.erase(iter); +} + +void +rpcserver_thrift::registerQueryCallback(const std::string &id, + const queryCallback_t callback) +{ + boost::mutex::scoped_lock lock(d_callback_map_lock); + { + QueryCallbackMap_t::const_iterator iter(d_getcallbackmap.find(id)); + if(iter != d_getcallbackmap.end()) { + std::stringstream s; + s << "rpcserver_thrift:: rpcserver_thrift ERROR registering get, already registered: " + << id << std::endl; + throw std::runtime_error(s.str().c_str()); + } + } + + if(DEBUG) { + std::cerr << "rpcserver_thrift registering get: " << id << std::endl; + } + d_getcallbackmap.insert(QueryCallbackMap_t::value_type(id, callback)); +} + +void +rpcserver_thrift::unregisterQueryCallback(const std::string &id) +{ + boost::mutex::scoped_lock lock(d_callback_map_lock); + QueryCallbackMap_t::iterator iter(d_getcallbackmap.find(id)); + if(iter == d_getcallbackmap.end()) { + std::stringstream s; + s << "rpcserver_thrift:: rpcserver_thrift ERROR unregistering get, registered: " + << id << std::endl; + throw std::runtime_error(s.str().c_str()); + } + + if(DEBUG) { + std::cerr << "rpcserver_thrift unregistering get: " << id << std::endl; + } + + d_getcallbackmap.erase(iter); +} + +void +rpcserver_thrift::setKnobs(const GNURadio::KnobMap& knobs) +{ + boost::mutex::scoped_lock lock(d_callback_map_lock); + std::for_each(knobs.begin(), knobs.end(), + set_f<GNURadio::KnobMap::value_type,ConfigureCallbackMap_t> + (d_setcallbackmap, cur_priv)); +} + + +void +rpcserver_thrift::getKnobs(GNURadio::KnobMap& _return, + const GNURadio::KnobIDList& knobs) +{ + boost::mutex::scoped_lock lock(d_callback_map_lock); + if(knobs.size() == 0) { + std::for_each(d_getcallbackmap.begin(), d_getcallbackmap.end(), + get_all_f<QueryCallbackMap_t::value_type, QueryCallbackMap_t, GNURadio::KnobMap> + (d_getcallbackmap, cur_priv, _return)); + } + else { + std::for_each(knobs.begin(), knobs.end(), + get_f<GNURadio::KnobIDList::value_type, QueryCallbackMap_t> + (d_getcallbackmap, cur_priv, _return)); + } +} + +void +rpcserver_thrift::getRe(GNURadio::KnobMap& _return, const GNURadio::KnobIDList& knobs) +{ + boost::mutex::scoped_lock lock(d_callback_map_lock); + if(knobs.size() == 0) { + std::for_each(d_getcallbackmap.begin(), d_getcallbackmap.end(), + get_all_f<QueryCallbackMap_t::value_type, QueryCallbackMap_t, GNURadio::KnobMap> + (d_getcallbackmap, cur_priv, _return)); + } + else { + QueryCallbackMap_t::iterator it; + for(it = d_getcallbackmap.begin(); it != d_getcallbackmap.end(); it++){ + for(size_t j=0; j<knobs.size(); j++) { + const boost::xpressive::sregex re(boost::xpressive::sregex::compile(knobs[j])); + if(boost::xpressive::regex_match(it->first, re)) { + get_f<GNURadio::KnobIDList::value_type, QueryCallbackMap_t> + (d_getcallbackmap, cur_priv, _return)(it->first); + break; + } + } + } + } +} + +void +rpcserver_thrift::properties(GNURadio::KnobPropMap& _return, + const GNURadio::KnobIDList& knobs) +{ + boost::mutex::scoped_lock lock(d_callback_map_lock); + if(knobs.size() == 0) { + std::for_each(d_getcallbackmap.begin(), d_getcallbackmap.end(), + properties_all_f<QueryCallbackMap_t::value_type, + QueryCallbackMap_t, GNURadio::KnobPropMap>(d_getcallbackmap, + cur_priv, _return)); + } + else { + std::for_each(knobs.begin(), knobs.end(), + properties_f<GNURadio::KnobIDList::value_type, + QueryCallbackMap_t, GNURadio::KnobPropMap>(d_getcallbackmap, + cur_priv, _return)); + } +} + +void +rpcserver_thrift::shutdown() { + if (DEBUG) { + std::cerr << "Shutting down..." << std::endl; + } +} diff --git a/gnuradio-runtime/lib/controlport/thrift/thrift-codebase-shutdown-patch.diff b/gnuradio-runtime/lib/controlport/thrift/thrift-codebase-shutdown-patch.diff new file mode 100644 index 0000000000..eaf54d5c70 --- /dev/null +++ b/gnuradio-runtime/lib/controlport/thrift/thrift-codebase-shutdown-patch.diff @@ -0,0 +1,98 @@ +diff --git a/lib/cpp/src/thrift/concurrency/ThreadManager.cpp b/lib/cpp/src/thrift/concurrency/ThreadManager.cpp +index 255d237..9954a8a 100644 +--- a/lib/cpp/src/thrift/concurrency/ThreadManager.cpp ++++ b/lib/cpp/src/thrift/concurrency/ThreadManager.cpp +@@ -409,6 +409,8 @@ void ThreadManager::Impl::removeWorker(size_t value) { + + workerMaxCount_ -= value; + ++ shutdown_mutex_.unlock(); ++ + if (idleCount_ < value) { + for (size_t ix = 0; ix < idleCount_; ix++) { + monitor_.notify(); +diff --git a/lib/cpp/src/thrift/concurrency/ThreadManager.h b/lib/cpp/src/thrift/concurrency/ThreadManager.h +index 7bb71d1..e97fd25 100644 +--- a/lib/cpp/src/thrift/concurrency/ThreadManager.h ++++ b/lib/cpp/src/thrift/concurrency/ThreadManager.h +@@ -24,6 +24,7 @@ + #include <thrift/cxxfunctional.h> + #include <sys/types.h> + #include <thrift/concurrency/Thread.h> ++#include <thrift/concurrency/Mutex.h> + + namespace apache { + namespace thrift { +@@ -59,6 +60,7 @@ protected: + ThreadManager() {} + + public: ++ Mutex shutdown_mutex_; + typedef apache::thrift::stdcxx::function<void(boost::shared_ptr<Runnable>)> ExpireCallback; + + virtual ~ThreadManager() {} +diff --git a/lib/cpp/src/thrift/server/TThreadPoolServer.cpp b/lib/cpp/src/thrift/server/TThreadPoolServer.cpp +index 0530d8d..d6b73dc 100644 +--- a/lib/cpp/src/thrift/server/TThreadPoolServer.cpp ++++ b/lib/cpp/src/thrift/server/TThreadPoolServer.cpp +@@ -194,19 +194,28 @@ void TThreadPoolServer::serve() { + } + } + +- // If stopped manually, join the existing threads +- if (stop_) { +- try { +- serverTransport_->close(); +- threadManager_->join(); +- } catch (TException& tx) { +- string errStr = string("TThreadPoolServer: Exception shutting down: ") + tx.what(); +- GlobalOutput(errStr.c_str()); ++ { ++ Guard g(threadManager_->shutdown_mutex_); ++ // If stopped manually, join the existing threads ++ if (stop_) { ++ try { ++ serverTransport_->close(); ++ threadManager_->join(); ++ } catch (TException& tx) { ++ string errStr = string("TThreadPoolServer: Exception shutting down: ") + tx.what(); ++ GlobalOutput(errStr.c_str()); ++ } ++ stop_ = false; + } +- stop_ = false; + } + } + ++void TThreadPoolServer::stop() { ++ threadManager_->shutdown_mutex_.lock(); ++ stop_ = true; ++ serverTransport_->interrupt(); ++} ++ + int64_t TThreadPoolServer::getTimeout() const { + return timeout_; + } +diff --git a/lib/cpp/src/thrift/server/TThreadPoolServer.h b/lib/cpp/src/thrift/server/TThreadPoolServer.h +index ad7e7ef..9b89846 100644 +--- a/lib/cpp/src/thrift/server/TThreadPoolServer.h ++++ b/lib/cpp/src/thrift/server/TThreadPoolServer.h +@@ -24,6 +24,7 @@ + #include <thrift/server/TServer.h> + #include <thrift/transport/TServerTransport.h> + ++ + #include <boost/shared_ptr.hpp> + + namespace apache { +@@ -113,10 +114,7 @@ public: + + virtual void setTimeout(int64_t value); + +- virtual void stop() { +- stop_ = true; +- serverTransport_->interrupt(); +- } ++ virtual void stop(); + + virtual int64_t getTaskExpiration() const; diff --git a/gnuradio-runtime/lib/controlport/thrift/thrift.conf.example b/gnuradio-runtime/lib/controlport/thrift/thrift.conf.example new file mode 100644 index 0000000000..71cc506249 --- /dev/null +++ b/gnuradio-runtime/lib/controlport/thrift/thrift.conf.example @@ -0,0 +1,4 @@ +[thrift] +port = 9090 +nthreads = 2 +buffersize = 1434 diff --git a/gnuradio-runtime/lib/controlport/thrift/thrift_application_base.cc b/gnuradio-runtime/lib/controlport/thrift/thrift_application_base.cc new file mode 100644 index 0000000000..282ed9fc63 --- /dev/null +++ b/gnuradio-runtime/lib/controlport/thrift/thrift_application_base.cc @@ -0,0 +1,23 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 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. + */ + +#include <gnuradio/thrift_application_base.h> diff --git a/gnuradio-runtime/lib/prefs.cc b/gnuradio-runtime/lib/prefs.cc index b7fcaada9d..b303ffdaf9 100644 --- a/gnuradio-runtime/lib/prefs.cc +++ b/gnuradio-runtime/lib/prefs.cc @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2006,2013 Free Software Foundation, Inc. + * Copyright 2006,2013,2015 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -46,7 +46,10 @@ namespace gr { prefs::prefs() { - _read_files(); + std::string config = _read_files(_sys_prefs_filenames()); + + // Convert the string into a map + _convert_to_map(config); } prefs::~prefs() @@ -83,13 +86,12 @@ namespace gr { return fnames; } - void - prefs::_read_files() + std::string + prefs::_read_files(const std::vector<std::string> &filenames) { std::string config; - std::vector<std::string> filenames = _sys_prefs_filenames(); - std::vector<std::string>::iterator sitr; + std::vector<std::string>::const_iterator sitr; char tmp[1024]; for(sitr = filenames.begin(); sitr != filenames.end(); sitr++) { fs::ifstream fin(*sitr); @@ -142,8 +144,7 @@ namespace gr { fin.close(); } - // Convert the string into a map - _convert_to_map(config); + return config; } void @@ -188,6 +189,17 @@ namespace gr { } } + void + prefs::add_config_file(const std::string &configfile) + { + std::vector<std::string> filenames; + filenames.push_back(configfile); + + std::string config = _read_files(filenames); + _convert_to_map(config); + } + + std::string prefs::to_string() { diff --git a/gnuradio-runtime/python/gnuradio/ctrlport/CMakeLists.txt b/gnuradio-runtime/python/gnuradio/ctrlport/CMakeLists.txt index 1d5a292429..f40f253a72 100644 --- a/gnuradio-runtime/python/gnuradio/ctrlport/CMakeLists.txt +++ b/gnuradio-runtime/python/gnuradio/ctrlport/CMakeLists.txt @@ -27,10 +27,53 @@ install( COMPONENT "runtime_python" ) + GR_PYTHON_INSTALL( FILES + ${CMAKE_CURRENT_SOURCE_DIR}/__init__.py ${CMAKE_CURRENT_SOURCE_DIR}/GrDataPlotter.py ${CMAKE_CURRENT_SOURCE_DIR}/monitor.py + ${CMAKE_CURRENT_SOURCE_DIR}/GNURadioControlPortClient.py + ${CMAKE_CURRENT_SOURCE_DIR}/RPCConnection.py + DESTINATION ${GR_PYTHON_DIR}/gnuradio/ctrlport/ + COMPONENT "runtime_python" +) + +GR_PYTHON_INSTALL( + FILES + ${CMAKE_CURRENT_SOURCE_DIR}/gr-perf-monitorx + ${CMAKE_CURRENT_SOURCE_DIR}/gr-ctrlport-monitor + DESTINATION ${GR_RUNTIME_DIR} + PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE + COMPONENT "runtime_python" +) + +if(THRIFT_FOUND) + +EXECUTE_PROCESS( + COMMAND ${THRIFT_BIN} --gen py -out ${CMAKE_CURRENT_BINARY_DIR}/ ${CMAKE_SOURCE_DIR}/gnuradio-runtime/lib/controlport/thrift/gnuradio.thrift + OUTPUT_VARIABLE THRIFT_PY_OUTPUT + ERROR_VARIABLE THRIFT_PY_ERROR + ) + +GR_PYTHON_INSTALL( + FILES + ${CMAKE_CURRENT_SOURCE_DIR}/RPCConnectionThrift.py DESTINATION ${GR_PYTHON_DIR}/gnuradio/ctrlport/ COMPONENT "runtime_python" ) + +GR_PYTHON_INSTALL( + FILES + ${CMAKE_CURRENT_BINARY_DIR}/GNURadio/__init__.py + ${CMAKE_CURRENT_BINARY_DIR}/GNURadio/constants.py + ${CMAKE_CURRENT_BINARY_DIR}/GNURadio/ControlPort.py + ${CMAKE_CURRENT_BINARY_DIR}/GNURadio/ControlPort-remote + ${CMAKE_CURRENT_BINARY_DIR}/GNURadio/StreamReceiver.py + ${CMAKE_CURRENT_BINARY_DIR}/GNURadio/StreamReceiver-remote + ${CMAKE_CURRENT_BINARY_DIR}/GNURadio/ttypes.py + DESTINATION ${GR_PYTHON_DIR}/gnuradio/ctrlport/GNURadio + COMPONENT "runtime_python" +) + +endif(THRIFT_FOUND) diff --git a/gnuradio-runtime/python/gnuradio/ctrlport/GNURadioControlPortClient.py b/gnuradio-runtime/python/gnuradio/ctrlport/GNURadioControlPortClient.py new file mode 100644 index 0000000000..87d2cf5658 --- /dev/null +++ b/gnuradio-runtime/python/gnuradio/ctrlport/GNURadioControlPortClient.py @@ -0,0 +1,132 @@ +# +# Copyright 2015 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 this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# + +""" +Python Client classes for interfacing with the GNU Radio ControlPort interface +and for accessing Performance Counters. + +While ControlPort and these client classes are designed to support multiple +Remote Procedure Call (RPC) transports, the Apache Thrift middle-ware RPC +is currently the only supported transport. + +""" + +import exceptions + +""" +GNURadioControlPortClient is the main class for creating a GNU Radio +ControlPort client application for all transports. + +Two constructors are provided for creating a connection to ControlPort. + +""" + +class GNURadioControlPortClient(): + """ + Constructor for creating a ControlPort connection to a specified host / port + + Args: + host: hostname of the connection. Specifying None (default) will + select the loopback interface. + + port: port number to use for the connection. Specifying None (default) + will select the specified RPC transport's default port number, if + the transport has a default. + + rpcmethod: This string specifies the RPC transport to use for the + client connection. The default implementation currently uses + the Apache Thrift RPC transport. The value specified here must + be one of the transport keys listed in the RPCMethods dictionary + above + + callback: This optional parameter is a callback function that will be passed + a reference to the Client implementation for the RPC transport specified + by rpcmethod. The callback will be executed after the client has been + constructed, but before __init__ returns. + + blockingcallback: This optional parameter is a callback function with + no parameters that will be executed after callback() is executed, + but before __init__ returns. It is useful if your application + requires that a blocking function be called to start the application, + such as QtGui.QApplication.exec_ + + """ + + def __init__(self, host = None, port = None, rpcmethod = 'thrift', callback = None, blockingcallback = None): + __init__([host, port], rpcmethod, callback, blockingcallback) + + """ + Constructor for creating a ControlPort from a tuple of command line arguments (i.e. sys.argv) + + Args: + argv: List of command line arguments. Future implementations may parse the argument list + for OptionParser style key / value pairs, however the current implementation + simply takes argv[1] and argv[2] as the connection hostname and port, respectively. + + Example Usage: + + In the following QT client example, the ControlPort host and port are specified to + the Client application as the first two command line arguments. The MAINWindow class is + of the type QtGui.QMainWindow, and is the main window for the QT application. MyApp + is a simple helper class for starting the application. + + class MAINWindow(QtGui.QMainWindow): + ... QT Application implementation ... + + class MyApp(object): + def __init__(self, args): + from GNURadioControlPortClient import GNURadioControlPortClient + GNURadioControlPortClient(args, 'thrift', self.run, QtGui.QApplication(sys.argv).exec_) + + def run(self, client): + MAINWindow(client).show() + + MyApp(sys.argv) + + + """ + + def __init__(self, argv = [], rpcmethod = 'thrift', callback = None, blockingcallback = None): + if len(argv) > 1: host = argv[1] + else: host = None + + if len(argv) > 2: port = argv[2] + else: port = None + + self.client = None + + from gnuradio.ctrlport.RPCConnection import RPCMethods + if RPCMethods.has_key(rpcmethod): + from gnuradio.ctrlport.RPCConnectionThrift import RPCConnectionThrift + if rpcmethod == 'thrift': + #print("making RPCConnectionThrift") + self.client = RPCConnectionThrift(host, port) + #print("made %s" % self.client) + + #print("making callback call") + if not callback is None: + callback(self.client) + + #print("making blockingcallback call") + if not blockingcallback is None: + blockingcallback() + else: + print("Unsupported RPC method: ", rpcmethod) + raise exceptions.ValueError() diff --git a/gnuradio-runtime/python/gnuradio/ctrlport/GrDataPlotter.py b/gnuradio-runtime/python/gnuradio/ctrlport/GrDataPlotter.py index 661705d613..c5bfd0a8cb 100644 --- a/gnuradio-runtime/python/gnuradio/ctrlport/GrDataPlotter.py +++ b/gnuradio-runtime/python/gnuradio/ctrlport/GrDataPlotter.py @@ -23,7 +23,7 @@ from gnuradio import gr from gnuradio import blocks from gnuradio import filter -from gnuradio.ctrlport import GNURadio +from gnuradio.ctrlport.GNURadio import ControlPort import sys, time, struct try: @@ -442,7 +442,7 @@ class GrDataPlotterValueTable: units = str(knobprops[itemKey].units) descr = str(knobprops[itemKey].description) - if(type(v) == GNURadio.complex): + if(type(v) == ControlPort.complex): v = v.re + v.im*1j # If it's a byte stream, Python thinks it's a string. # Unpack and convert to floats for plotting. @@ -468,7 +468,7 @@ class GrDataPlotterValueTable: for k in knobs.keys(): if k not in foundKeys: v = knobs[k].value - if(type(v) == GNURadio.complex): + if(type(v) == ControlPort.complex): v = v.re + v.im*1j # If it's a byte stream, Python thinks it's a string. # Unpack and convert to floats for plotting. diff --git a/gnuradio-runtime/python/gnuradio/ctrlport/RPCConnection.py b/gnuradio-runtime/python/gnuradio/ctrlport/RPCConnection.py new file mode 100644 index 0000000000..e14cc0cea7 --- /dev/null +++ b/gnuradio-runtime/python/gnuradio/ctrlport/RPCConnection.py @@ -0,0 +1,115 @@ +# +# Copyright 2015 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 this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# + +import exceptions + +""" +RPCMethods is a dictionary listing RPC transports currently supported +by this client. + +Args: + function: the function whose parameter list will be examined + excluded_args: function arguments that are NOT to be added to the dictionary (sequence of strings) + options: result of command argument parsing (optparse.Values) +""" + +RPCMethods = {'thrift': 'Apache Thrift', + #'ice': 'Zeroc ICE' + } + + +""" +Base class for RPC transport clients + +Methods that all RPC clients should implement include: + + def newConnection(host,port): Method for re-establishing a new client + connection to a different host / port + + def properties([]): Given a list of ControlPort property names, + or an empty list to specify all currently registered properties, + this method returns a dictionary of metadata describing the + the specified properties. The dictionary key contains the name + of each returned properties. + + def getKnobs([]): Given a list of ControlPort property names, + or an empty list to specify all currently registered properties, + this method returns a dictionary of the current value of + the specified properties. + + def getRe([]): Given a list of regular expression strings, + this method returns a dictionary of the current value of + the all properties with names that match the specified + expressions. + + def setKnobs({}): Given a dictionary of ControlPort property + key / value pairs, this method requests that ControlPort + attempt to set the specified named properties to the + value given. Success in setting each property to the + value specified requires that the property be registered + as a 'setable' ControlPort property, that the client have the + requisite privilege level to set the property, and + the underlying Block's implementation in handling + the set request. + +Args: + method: name of the RPC transport + port: port number of the connection + host: hostname of the connection +""" + +class RPCConnection(object): + def __init__(self, method, port, host=None): + (self.method, self.port) = (method, port) + if host is None: self.host = '127.0.0.1' + else: self.host = host + + def __str__(self): + return "%s connection on %s:%s"%(self.getName(), self.getHost(), self.getPort()) + + def getName(self): + return RPCMethods[self.method] + + def getHost(self): + return self.host + + def getPort(self): + return self.port + + def newConnection(self, host=None, port=None): + raise exceptions.NotImplementedError() + + def properties(self, *args): + raise exceptions.NotImplementedError() + + def getKnobs(self, *args): + raise exceptions.NotImplementedError() + + def getRe(self,*args): + raise exceptions.NotImplementedError() + + def setKnobs(self,*args): + raise exceptions.NotImplementedError() + + def shutdown(self): + raise exceptions.NotImplementedError() + + def printProperties(self, props): + raise exceptions.NotImplementedError() diff --git a/gnuradio-runtime/python/gnuradio/ctrlport/RPCConnectionThrift.py b/gnuradio-runtime/python/gnuradio/ctrlport/RPCConnectionThrift.py new file mode 100644 index 0000000000..9a2a302af5 --- /dev/null +++ b/gnuradio-runtime/python/gnuradio/ctrlport/RPCConnectionThrift.py @@ -0,0 +1,208 @@ +#!/usr/bin/env python +# +# Copyright 2015 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 thrift import Thrift +from thrift.transport import TSocket +from thrift.transport import TTransport +from thrift.protocol import TBinaryProtocol +from gnuradio.ctrlport.GNURadio import ControlPort +from gnuradio.ctrlport import RPCConnection +from gnuradio import gr +import sys + +class ThriftRadioClient: + def __init__(self, host, port): + self.tsocket = TSocket.TSocket(host, port) + self.transport = TTransport.TBufferedTransport(self.tsocket) + self.protocol = TBinaryProtocol.TBinaryProtocol(self.transport) + + self.radio = ControlPort.Client(self.protocol) + self.transport.open() + + def __del__(self): + self.radio.shutdown() + self.transport.close() + + def getRadio(self, host, port): + return self.radio + +""" +RPC Client interface for the Apache Thrift middle-ware RPC transport. + +Args: + port: port number of the connection + host: hostname of the connection +""" + +class RPCConnectionThrift(RPCConnection.RPCConnection): + class Knob(): + def __init__(self, key, value=None, ktype=0): + (self.key, self.value, self.ktype) = (key, value, ktype) + + def __repr__(self): + return "({0} = {1})".format(self.key, self.value) + + def __init__(self, host=None, port=None): + from gnuradio.ctrlport.GNURadio import ttypes + self.BaseTypes = ttypes.BaseTypes + self.KnobBase = ttypes.KnobBase + + # If not set by the user, get the port number from the thrift + # config file, if one is set. Defaults to 9090 otherwise. + if port is None: + p = gr.prefs() + thrift_config_file = p.get_string("ControlPort", "config", ""); + if(len(thrift_config_file) > 0): + p.add_config_file(thrift_config_file) + port = p.get_long("thrift", "port", 9090) + else: + port = 9090 + else: + port = int(port) + + super(RPCConnectionThrift, self).__init__(method='thrift', port=port, host=host) + self.newConnection(host, port) + + self.unpack_dict = { + self.BaseTypes.BOOL: lambda k,b: self.Knob(k, b.value.a_bool, self.BaseTypes.BOOL), + self.BaseTypes.BYTE: lambda k,b: self.Knob(k, b.value.a_byte, self.BaseTypes.BYTE), + self.BaseTypes.SHORT: lambda k,b: self.Knob(k, b.value.a_short, self.BaseTypes.SHORT), + self.BaseTypes.INT: lambda k,b: self.Knob(k, b.value.a_int, self.BaseTypes.INT), + self.BaseTypes.LONG: lambda k,b: self.Knob(k, b.value.a_long, self.BaseTypes.LONG), + self.BaseTypes.DOUBLE: lambda k,b: self.Knob(k, b.value.a_double, self.BaseTypes.DOUBLE), + self.BaseTypes.STRING: lambda k,b: self.Knob(k, b.value.a_string, self.BaseTypes.STRING), + self.BaseTypes.COMPLEX: lambda k,b: self.Knob(k, b.value.a_complex, self.BaseTypes.COMPLEX), + self.BaseTypes.F32VECTOR: lambda k,b: self.Knob(k, b.value.a_f32vector, self.BaseTypes.F32VECTOR), + self.BaseTypes.F64VECTOR: lambda k,b: self.Knob(k, b.value.a_f64vector, self.BaseTypes.F64VECTOR), + self.BaseTypes.S64VECTOR: lambda k,b: self.Knob(k, b.value.a_s64vector, self.BaseTypes.S64VECTOR), + self.BaseTypes.S32VECTOR: lambda k,b: self.Knob(k, b.value.a_s32vector, self.BaseTypes.S32VECTOR), + self.BaseTypes.S16VECTOR: lambda k,b: self.Knob(k, b.value.a_s16vector, self.BaseTypes.S16VECTOR), + self.BaseTypes.S8VECTOR: lambda k,b: self.Knob(k, b.value.a_s8vector, self.BaseTypes.S8VECTOR), + self.BaseTypes.C32VECTOR: lambda k,b: self.Knob(k, b.value.a_c32vector, self.BaseTypes.C32VECTOR), + } + + self.pack_dict = { + self.BaseTypes.BOOL: lambda k: ttypes.Knob(type=k.ktype, value=ttypes.KnobBase(a_bool = k.value)), + self.BaseTypes.BYTE: lambda k: ttypes.Knob(type=k.ktype, value=ttypes.KnobBase(a_byte = k.value)), + self.BaseTypes.SHORT: lambda k: ttypes.Knob(type=k.ktype, value=ttypes.KnobBase(a_short = k.value)), + self.BaseTypes.INT: lambda k: ttypes.Knob(type=k.ktype, value=ttypes.KnobBase(a_int = k.value)), + self.BaseTypes.LONG: lambda k: ttypes.Knob(type=k.ktype, value=ttypes.KnobBase(a_long = k.value)), + self.BaseTypes.DOUBLE: lambda k: ttypes.Knob(type=k.ktype, value=ttypes.KnobBase(a_double = k.value)), + self.BaseTypes.STRING: lambda k: ttypes.Knob(type=k.ktype, value=ttypes.KnobBase(a_string = k.value)), + self.BaseTypes.COMPLEX: lambda k: ttypes.Knob(type=k.ktype, value=ttypes.KnobBase(a_complex = k.value)), + self.BaseTypes.F32VECTOR: lambda k: ttypes.Knob(type=k.ktype, value=ttypes.KnobBase(a_f32vector = k.value)), + self.BaseTypes.F64VECTOR: lambda k: ttypes.Knob(type=k.ktype, value=ttypes.KnobBase(a_f64vector = k.value)), + self.BaseTypes.S64VECTOR: lambda k: ttypes.Knob(type=k.ktype, value=ttypes.KnobBase(a_s64vector = k.value)), + self.BaseTypes.S32VECTOR: lambda k: ttypes.Knob(type=k.ktype, value=ttypes.KnobBase(a_s32vector = k.value)), + self.BaseTypes.S16VECTOR: lambda k: ttypes.Knob(type=k.ktype, value=ttypes.KnobBase(a_s16vector = k.value)), + self.BaseTypes.S8VECTOR: lambda k: ttypes.Knob(type=k.ktype, value=ttypes.KnobBase(a_s8vector = k.value)), + self.BaseTypes.C32VECTOR: lambda k: ttypes.Knob(type=k.ktype, value=ttypes.KnobBase(a_c32vector = k.value)), + } + + def unpackKnob(self, key, knob): + f = self.unpack_dict.get(knob.type, None) + if(f): + return f(key, knob) + else: + sys.stderr.write("unpackKnobs: Incorrect Knob type: {0}\n".format(knob.type)) + raise exceptions.ValueError + + def packKnob(self, knob): + f = self.pack_dict.get(knob.ktype, None) + if(f): + return f(knob) + else: + sys.stderr.write("packKnobs: Incorrect Knob type: {0}\n".format(knob.type)) + raise exceptions.ValueError + + def newConnection(self, host=None, port=None): + try: + self.thriftclient = ThriftRadioClient(self.getHost(), self.getPort()) + except TTransport.TTransportException: + sys.stderr.write("Could not connect to ControlPort endpoint at {0}:{1}.\n\n".format(host, port)) + sys.exit(1) + + def properties(self, *args): + knobprops = self.thriftclient.radio.properties(*args) + for key, knobprop in knobprops.iteritems(): + #print("key:", key, "value:", knobprop, "type:", knobprop.type) + knobprops[key].min = self.unpackKnob(key, knobprop.min) + knobprops[key].max = self.unpackKnob(key, knobprop.max) + knobprops[key].defaultvalue = self.unpackKnob(key, knobprop.defaultvalue) + return knobprops + + def getKnobs(self, *args): + result = {} + for key, knob in self.thriftclient.radio.getKnobs(*args).iteritems(): + #print("key:", key, "value:", knob, "type:", knob.type) + result[key] = self.unpackKnob(key, knob) + + # If complex, convert to Python complex + # FIXME: better list iterator way to handle this? + if(knob.type == self.BaseTypes.C32VECTOR): + for i in xrange(len(result[key].value)): + result[key].value[i] = complex(result[key].value[i].re, + result[key].value[i].im) + return result + + def getKnobsRaw(self, *args): + result = {} + for key, knob in self.thriftclient.radio.getKnobs(*args).iteritems(): + #print("key:", key, "value:", knob, "type:", knob.type) + result[key] = knob + return result + + def getRe(self,*args): + result = {} + for key, knob in self.thriftclient.radio.getRe(*args).iteritems(): + result[key] = self.unpackKnob(key, knob) + return result + + def setKnobs(self, *args): + if(type(*args) == dict): + a = dict(*args) + result = {} + for key, knob in a.iteritems(): + result[key] = self.packKnob(knob) + self.thriftclient.radio.setKnobs(result) + elif(type(*args) == list or type(*args) == tuple): + a = list(*args) + result = {} + for k in a: + result[k.key] = self.packKnob(k) + self.thriftclient.radio.setKnobs(result) + else: + sys.stderr.write("setKnobs: Invalid type; must be dict, list, or tuple\n") + + def shutdown(self): + self.thriftclient.radio.shutdown() + + def printProperties(self, props): + info = "" + info += "Item:\t\t{0}\n".format(props.description) + info += "units:\t\t{0}\n".format(props.units) + info += "min:\t\t{0}\n".format(props.min.value) + info += "max:\t\t{0}\n".format(props.max.value) + info += "default:\t\t{0}\n".format(props.defaultvalue.value) + info += "Type Code:\t0x{0:x}\n".format(props.type) + info += "Disp Code:\t0x{0:x}\n".format(props.display) + return info diff --git a/gnuradio-runtime/python/gnuradio/ctrlport/gr-ctrlport-monitor b/gnuradio-runtime/python/gnuradio/ctrlport/gr-ctrlport-monitor new file mode 100644 index 0000000000..c866776355 --- /dev/null +++ b/gnuradio-runtime/python/gnuradio/ctrlport/gr-ctrlport-monitor @@ -0,0 +1,771 @@ +#!/usr/bin/env python +# +# Copyright 2012,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. +# + +from PyQt4 import QtCore,Qt +import PyQt4.QtGui as QtGui +import os, sys, time, struct + +from gnuradio import gr, ctrlport +from gnuradio.ctrlport.GrDataPlotter import * + +class RateDialog(QtGui.QDialog): + def __init__(self, delay, parent=None): + super(RateDialog, self).__init__(parent) + self.gridLayout = QtGui.QGridLayout(self) + self.setWindowTitle("Update Delay (ms)"); + self.delay = QtGui.QLineEdit(self); + self.delay.setText(str(delay)); + self.buttonBox = QtGui.QDialogButtonBox(QtGui.QDialogButtonBox.Ok | QtGui.QDialogButtonBox.Cancel) + self.gridLayout.addWidget(self.delay); + self.gridLayout.addWidget(self.buttonBox); + self.buttonBox.accepted.connect(self.accept) + self.buttonBox.rejected.connect(self.reject) + def accept(self): + self.done(1); + def reject(self): + self.done(0); + +class MAINWindow(QtGui.QMainWindow): + def minimumSizeHint(self): + return Qtgui.QSize(800,600) + + def __init__(self, radioclient): + + super(MAINWindow, self).__init__() + self.radioclient = radioclient + self.updateRate = 1000; + self.conns = [] + self.plots = [] + self.knobprops = [] + + self.mdiArea = QtGui.QMdiArea() + self.mdiArea.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded) + self.mdiArea.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded) + self.setCentralWidget(self.mdiArea) + + self.mdiArea.subWindowActivated.connect(self.updateMenus) + self.windowMapper = QtCore.QSignalMapper(self) + self.windowMapper.mapped[QtGui.QWidget].connect(self.setActiveSubWindow) + + self.createActions() + self.createMenus() + self.createToolBars() + self.createStatusBar() + self.updateMenus() + + self.setWindowTitle("GNU Radio Control Port Monitor") + self.setUnifiedTitleAndToolBarOnMac(True) + + self.newCon(radioclient) + icon = QtGui.QIcon(ctrlport.__path__[0] + "/icon.png" ) + self.setWindowIcon(icon) + + # Locally turn off ControlPort export from GR. This prevents + # our GR-based plotters from launching their own ControlPort + # instance (and possibly causing a port collision if one has + # been specified). + os.environ['GR_CONF_CONTROLPORT_ON'] = 'False' + + def setUpdateRate(self,nur): + self.updateRate = int(nur); + for c in self.conns: + c.updateRate = self.updateRate; + c.timer.setInterval(self.updateRate); + + def newCon(self, csomeBool): + child = MForm(self.radioclient, len(self.conns), parent = self, dialogprompt = not csomeBool) + if(child.radioclient is not None): + child.setWindowTitle(str(child.radioclient)) + self.mdiArea.addSubWindow(child) + self.mdiArea.currentSubWindow().showMaximized() + self.conns.append(child) + self.plots.append([]) + + def propertiesMenu(self, key, radio, uid): + title = str(radio) + + props = radio.properties([key]) + + pmin,pmax = get_minmax(props[key]) + + # Use display option mask of item to set up available plot + # types and default options. + disp = self.knobprops[uid][key].display + cplx = disp & gr.DISPOPTCPLX | disp & gr.DISPXY + strip = disp & gr.DISPOPTSTRIP + stem = disp & gr.DISPOPTSTEM + log = disp & gr.DISPOPTLOG + scatter = disp & gr.DISPOPTSCATTER + + def newUpdaterProxy(): + self.newUpdater(key, radio) + + def newPlotterFProxy(): + self.newPlotF(key, uid, title, pmin, pmax, + log, strip, stem) + + def newPlotterCProxy(): + self.newPlotC(key, uid, title, pmin, pmax, + log, strip, stem) + + def newPlotterConstProxy(): + self.newPlotConst(key, uid, title, pmin, pmax, + scatter, strip) + + def newPlotterPsdFProxy(): + self.newPlotPsdF(key, uid, title) + + def newPlotterPsdCProxy(): + self.newPlotPsdC(key, uid, title) + + def newPlotterRasterFProxy(): + self.newPlotRasterF(key, uid, title, pmin, pmax) + + def newPlotterRasterBProxy(): + self.newPlotRasterB(key, uid, title, pmin, pmax) + + menu = QtGui.QMenu(self) + menu.setTitle("Item Actions") + menu.setTearOffEnabled(False) + + # object properties + menu.addAction("Properties", newUpdaterProxy) + + # displays available + if(cplx == 0): + menu.addAction("Plot Time", newPlotterFProxy) + menu.addAction("Plot PSD", newPlotterPsdFProxy) + menu.addAction("Plot Raster (real)", newPlotterRasterFProxy) + #menu.addAction("Plot Raster (bits)", newPlotterRasterBProxy) + else: + menu.addAction("Plot Time", newPlotterCProxy) + menu.addAction("Plot PSD", newPlotterPsdCProxy) + menu.addAction("Plot Constellation", newPlotterConstProxy) + + menu.popup(QtGui.QCursor.pos()) + + def newUpdater(self, key, radio): + updater = UpdaterWindow(key, radio, None) + updater.setWindowTitle("Updater: " + key) + updater.setModal(False) + updater.exec_() + + def newSub(self, e): + tag = str(e.text(0)) + tree = e.treeWidget().parent() + uid = tree.uid + knobprop = self.knobprops[uid][tag] + + strr = str(tree.radioclient) + print(strr) +# r = strr.split(" ") + title = strr #title = "{0}:{1}".format(r[3], r[5]) + pmin,pmax = get_minmax(knobprop) + + disp = knobprop.display + if(disp & gr.DISPTIME): + strip = disp & gr.DISPOPTSTRIP + stem = disp & gr.DISPOPTSTEM + log = disp & gr.DISPOPTLOG + if(disp & gr.DISPOPTCPLX == 0): + self.newPlotF(tag, uid, title, pmin, pmax, + log, strip, stem) + else: + self.newPlotC(tag, uid, title, pmin, pmax, + log, strip, stem) + + elif(disp & gr.DISPXY): + scatter = disp & gr.DISPOPTSCATTER + self.newPlotConst(tag, uid, title, pmin, pmax, scatter) + + elif(disp & gr.DISPPSD): + if(disp & gr.DISPOPTCPLX == 0): + self.newPlotPsdF(tag, uid, title) + else: + self.newPlotPsdC(tag, uid, title) + + def startDrag(self, e): + drag = QtGui.QDrag(self) + mime_data = QtCore.QMimeData() + + tag = str(e.text(0)) + tree = e.treeWidget().parent() + knobprop = self.knobprops[tree.uid][tag] + disp = knobprop.display + iscomplex = (disp & gr.DISPOPTCPLX) or (disp & gr.DISPXY) + + if(disp != gr.DISPNULL): + data = "PlotData:::{0}:::{1}".format(tag, iscomplex) + else: + data = "OtherData:::{0}:::{1}".format(tag, iscomplex) + + mime_data.setText(data) + drag.setMimeData(mime_data) + + drop = drag.start() + + def createPlot(self, plot, uid, title): + plot.start() + self.plots[uid].append(plot) + + self.mdiArea.addSubWindow(plot) + plot.setWindowTitle("{0}: {1}".format(title, plot.name())) + self.connect(plot.qwidget(), + QtCore.SIGNAL('destroyed(QObject*)'), + self.destroyPlot) + + # when the plot is updated via drag-and-drop, we need to be + # notified of the new qwidget that's created so we can + # properly destroy it. + plot.plotupdated.connect(self.plotUpdated) + + plot.show() + + def plotUpdated(self, q): + # the plot has been updated with a new qwidget; make sure this + # gets dies to the destroyPlot function. + for i, plots in enumerate(self.plots): + for p in plots: + if(p == q): + #plots.remove(p) + #plots.append(q) + self.connect(q.qwidget(), + QtCore.SIGNAL('destroyed(QObject*)'), + self.destroyPlot) + break + + def destroyPlot(self, obj): + for plots in self.plots: + for p in plots: + if p.qwidget() == obj: + plots.remove(p) + break + + def newPlotConst(self, tag, uid, title="", pmin=None, pmax=None, + scatter=False, stripchart=False): + plot = GrDataPlotterConst(tag, 32e6, pmin, pmax, stripchart) + plot.scatter(scatter) + self.createPlot(plot, uid, title) + + def newPlotF(self, tag, uid, title="", pmin=None, pmax=None, + logy=False, stripchart=False, stem=False): + plot = GrDataPlotterF(tag, 32e6, pmin, pmax, stripchart) + plot.semilogy(logy) + plot.stem(stem) + self.createPlot(plot, uid, title) + + def newPlotC(self, tag, uid, title="", pmin=None, pmax=None, + logy=False, stripchart=False, stem=False): + plot = GrDataPlotterC(tag, 32e6, pmin, pmax, stripchart) + plot.semilogy(logy) + plot.stem(stem) + self.createPlot(plot, uid, title) + + def newPlotPsdF(self, tag, uid, title="", pmin=None, pmax=None): + plot = GrDataPlotterPsdF(tag, 32e6, pmin, pmax) + self.createPlot(plot, uid, title) + + def newPlotPsdC(self, tag, uid, title="", pmin=None, pmax=None): + plot = GrDataPlotterPsdC(tag, 32e6, pmin, pmax) + self.createPlot(plot, uid, title) + + def newPlotRasterF(self, tag, uid, title="", pmin=None, pmax=None): + plot = GrTimeRasterF(tag, 32e6, pmin, pmax) + self.createPlot(plot, uid, title) + + def newPlotRasterB(self, tag, uid, title="", pmin=None, pmax=None): + plot = GrTimeRasterB(tag, 32e6, pmin, pmax) + self.createPlot(plot, uid, title) + + def update(self, knobs, uid): + #sys.stderr.write("KNOB KEYS: {0}\n".format(knobs.keys())) + for plot in self.plots[uid]: + data = [] + for n in plot.knobnames: + d = knobs[n].value + # TODO: FIX COMPLEX! +# if(type(d) == GNURadio.complex): +# d = [d.re, d.im] + + # If it's a byte stream, Python thinks it's a string. + # Unpack and convert to floats for plotting. + if(type(d) == str and n.find('probe2_b') == 0): + d = struct.unpack(len(d)*'b', d) + d = [float(di) for di in d] + + data.append(d) + plot.update(data) + plot.stop() + plot.wait() + plot.start() + + def setActiveSubWindow(self, window): + if window: + self.mdiArea.setActiveSubWindow(window) + + + def createActions(self): + self.newConAct = QtGui.QAction("&New Connection", + self, shortcut=QtGui.QKeySequence.New, + statusTip="Create a new file", triggered=self.newCon) + + self.exitAct = QtGui.QAction("E&xit", self, shortcut="Ctrl+Q", + statusTip="Exit the application", + triggered=QtGui.qApp.closeAllWindows) + + self.closeAct = QtGui.QAction("Cl&ose", self, shortcut="Ctrl+F4", + statusTip="Close the active window", + triggered=self.mdiArea.closeActiveSubWindow) + + self.closeAllAct = QtGui.QAction("Close &All", self, + statusTip="Close all the windows", + triggered=self.mdiArea.closeAllSubWindows) + + self.urAct = QtGui.QAction("Update Rate", self, shortcut="F5", + statusTip="Change Update Rate", + triggered=self.updateRateShow) + + qks = QtGui.QKeySequence(QtCore.Qt.CTRL + QtCore.Qt.Key_T); + self.tileAct = QtGui.QAction("&Tile", self, + statusTip="Tile the windows", + triggered=self.mdiArea.tileSubWindows, + shortcut=qks) + + qks = QtGui.QKeySequence(QtCore.Qt.CTRL + QtCore.Qt.Key_C); + self.cascadeAct = QtGui.QAction("&Cascade", self, + statusTip="Cascade the windows", shortcut=qks, + triggered=self.mdiArea.cascadeSubWindows) + + self.nextAct = QtGui.QAction("Ne&xt", self, + shortcut=QtGui.QKeySequence.NextChild, + statusTip="Move the focus to the next window", + triggered=self.mdiArea.activateNextSubWindow) + + self.previousAct = QtGui.QAction("Pre&vious", self, + shortcut=QtGui.QKeySequence.PreviousChild, + statusTip="Move the focus to the previous window", + triggered=self.mdiArea.activatePreviousSubWindow) + + self.separatorAct = QtGui.QAction(self) + self.separatorAct.setSeparator(True) + + self.aboutAct = QtGui.QAction("&About", self, + statusTip="Show the application's About box", + triggered=self.about) + + self.aboutQtAct = QtGui.QAction("About &Qt", self, + statusTip="Show the Qt library's About box", + triggered=QtGui.qApp.aboutQt) + + def createMenus(self): + self.fileMenu = self.menuBar().addMenu("&File") + self.fileMenu.addAction(self.newConAct) + self.fileMenu.addAction(self.urAct) + self.fileMenu.addSeparator() + self.fileMenu.addAction(self.exitAct) + + self.windowMenu = self.menuBar().addMenu("&Window") + self.updateWindowMenu() + self.windowMenu.aboutToShow.connect(self.updateWindowMenu) + + self.menuBar().addSeparator() + + self.helpMenu = self.menuBar().addMenu("&Help") + self.helpMenu.addAction(self.aboutAct) + self.helpMenu.addAction(self.aboutQtAct) + + def updateRateShow(self): + askrate = RateDialog(self.updateRate, self); + if askrate.exec_(): + ur = float(str(askrate.delay.text())); + self.setUpdateRate(ur); + return; + else: + return; + + def createToolBars(self): + self.fileToolBar = self.addToolBar("File") + self.fileToolBar.addAction(self.newConAct) + self.fileToolBar.addAction(self.urAct) + + self.fileToolBar = self.addToolBar("Window") + self.fileToolBar.addAction(self.tileAct) + self.fileToolBar.addAction(self.cascadeAct) + + def createStatusBar(self): + self.statusBar().showMessage("Ready") + + + def activeMdiChild(self): + activeSubWindow = self.mdiArea.activeSubWindow() + if activeSubWindow: + return activeSubWindow.widget() + return None + + def updateMenus(self): + hasMdiChild = (self.activeMdiChild() is not None) + self.closeAct.setEnabled(hasMdiChild) + self.closeAllAct.setEnabled(hasMdiChild) + self.tileAct.setEnabled(hasMdiChild) + self.cascadeAct.setEnabled(hasMdiChild) + self.nextAct.setEnabled(hasMdiChild) + self.previousAct.setEnabled(hasMdiChild) + self.separatorAct.setVisible(hasMdiChild) + + def updateWindowMenu(self): + self.windowMenu.clear() + self.windowMenu.addAction(self.closeAct) + self.windowMenu.addAction(self.closeAllAct) + self.windowMenu.addSeparator() + self.windowMenu.addAction(self.tileAct) + self.windowMenu.addAction(self.cascadeAct) + self.windowMenu.addSeparator() + self.windowMenu.addAction(self.nextAct) + self.windowMenu.addAction(self.previousAct) + self.windowMenu.addAction(self.separatorAct) + + def about(self): + about_info = \ +'''Copyright 2012 Free Software Foundation, Inc.\n +This program is part of GNU Radio.\n +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.\n +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.\n +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.''' + + QtGui.QMessageBox.about(None, "gr-ctrlport-monitor", about_info) + + +class ConInfoDialog(QtGui.QDialog): + def __init__(self, parent=None): + super(ConInfoDialog, self).__init__(parent) + + self.gridLayout = QtGui.QGridLayout(self) + + + self.host = QtGui.QLineEdit(self); + self.port = QtGui.QLineEdit(self); + self.host.setText("localhost"); + self.port.setText("43243"); + + self.buttonBox = QtGui.QDialogButtonBox(QtGui.QDialogButtonBox.Ok | QtGui.QDialogButtonBox.Cancel) + + self.gridLayout.addWidget(self.host); + self.gridLayout.addWidget(self.port); + self.gridLayout.addWidget(self.buttonBox); + + self.buttonBox.accepted.connect(self.accept) + self.buttonBox.rejected.connect(self.reject) + + + def accept(self): + self.done(1); + + def reject(self): + self.done(0); + + +class UpdaterWindow(QtGui.QDialog): + def __init__(self, key, radio, parent): + QtGui.QDialog.__init__(self, parent) + + self.key = key; + self.radio = radio + + self.resize(300,200) + self.layout = QtGui.QVBoxLayout() + + self.props = radio.properties([key])[key] + info = radio.printProperties(self.props) + + self.infoLabel = QtGui.QLabel(info) + self.layout.addWidget(self.infoLabel) + + # Test here to make sure that a 'set' function exists + try: + radio.setKnobs(radio.getKnobs([key])) + has_set = True + except: + has_set = False + + + if(has_set is False): + self.cancelButton = QtGui.QPushButton("Ok") + self.cancelButton.connect(self.cancelButton, QtCore.SIGNAL('clicked()'), self.reject) + + self.buttonlayout = QtGui.QHBoxLayout() + self.buttonlayout.addWidget(self.cancelButton) + self.layout.addLayout(self.buttonlayout) + + else: # we have a set function + self.textInput = QtGui.QLineEdit() + self.layout.addWidget(self.textInput) + + self.applyButton = QtGui.QPushButton("Apply") + self.setButton = QtGui.QPushButton("OK") + self.cancelButton = QtGui.QPushButton("Cancel") + + rv = radio.getKnobs([key]) + val = rv[key].value + if(type(val) == ControlPort.complex): + val = val.re + val.im*1j + + self.textInput.setText(str(val)) + self.sv = rv[key] + + self.applyButton.connect(self.applyButton, QtCore.SIGNAL('clicked()'), self._apply) + self.setButton.connect(self.setButton, QtCore.SIGNAL('clicked()'), self._set) + self.cancelButton.connect(self.cancelButton, QtCore.SIGNAL('clicked()'), self.reject) + + self.is_num = ((type(self.sv.value)==float) or (type(self.sv.value)==int)) + if(self.is_num): + self.sliderlayout = QtGui.QHBoxLayout() + + self.slider = QtGui.QSlider(QtCore.Qt.Horizontal) + + self.sliderlayout.addWidget(QtGui.QLabel(str(self.props.min.value))) + self.sliderlayout.addWidget(self.slider) + self.sliderlayout.addWidget(QtGui.QLabel(str(self.props.max.value))) + + self.steps = 10000 + self.valspan = self.props.max.value - self.props.min.value + + self.slider.setRange(0, 10000) + self._set_slider_value(self.sv.value) + + self.connect(self.slider, QtCore.SIGNAL("sliderReleased()"), self._slide) + + self.layout.addLayout(self.sliderlayout) + else: + self._set_slider_value = None + + self.buttonlayout = QtGui.QHBoxLayout() + self.buttonlayout.addWidget(self.applyButton) + self.buttonlayout.addWidget(self.setButton) + self.buttonlayout.addWidget(self.cancelButton) + self.layout.addLayout(self.buttonlayout) + + # set layout and go... + self.setLayout(self.layout) + + def _set_slider_value(self, val): + self.slider.setValue(self.steps*(val-self.props.min.value)/self.valspan) + + def _slide(self): + val = (self.slider.value()*self.valspan + self.props.min.value)/float(self.steps) + self.textInput.setText(str(val)) + + def _apply(self): + if(type(self.sv.value) == str): + val = str(self.textInput.text()) + elif(type(self.sv.value) == int): + val = int(round(float(self.textInput.text()))) + elif(type(self.sv.value) == float): + val = float(self.textInput.text()) + elif(type(self.sv.value) == ControlPort.complex): + t = str(self.textInput.text()) + t = complex(t.strip("(").strip(")").replace(" ", "")) + val = ControlPort.complex() + val.re = t.real + val.im = t.imag + else: + sys.stderr.write("set type not supported! ({0})\n".format(type(self.sv.value))) + return + + self.sv.value = val + km = {} + km[self.key] = self.sv + self.radio.setKnobs(km) + if self._set_slider_value: + self._set_slider_value(self.sv.value) + + def _set(self): + self._apply() + self.done(0) + + +class MForm(QtGui.QWidget): + def update(self): + # TODO: revisit this try-except block, figure out what it's doing, and if we need to keep it. at very lease makes debugging dificult + if True: #try: + st = time.time(); + knobs = self.radioclient.getKnobs([]) + ft = time.time(); + latency = ft-st; + self.parent.statusBar().showMessage("Current GNU Radio Control Port Query Latency: %f ms"%(latency*1000)) + +# except Exception, e: +# sys.stderr.write("ctrlport-monitor: radio.get threw exception ({0}).\n".format(e)) +# if(type(self.parent) is MAINWindow): +# # Find window of connection +# remove = [] +# for p in self.parent.mdiArea.subWindowList(): +# if self.parent.conns[self.uid] == p.widget(): +# remove.append(p) +# +# # Find any subplot windows of connection +# for p in self.parent.mdiArea.subWindowList(): +# for plot in self.parent.plots[self.uid]: +# if plot.qwidget() == p.widget(): +# remove.append(p) +# +# # Clean up local references to these +# self.parent.conns.remove(self.parent.conns[self.uid]) +# self.parent.plots.remove(self.parent.plots[self.uid]) +# +# # Remove subwindows for connection and plots +# for r in remove: +# self.parent.mdiArea.removeSubWindow(r) +# +# # Clean up self +# self.close() +# else: +# sys.exit(1) +# return + + tableitems = knobs.keys() + + #UPDATE TABLE: + #try: + self.table.updateItems(knobs, self.knobprops) + #except: + # self.knobprops = self.radioclient.properties([]) + # print("knobsprops1:", len(self.knobprops)) + + #UPDATE PLOTS + self.parent.update(knobs, self.uid) + + + def __init__(self, radioclient, uid=0, updateRate=2000, parent=None, dialogprompt = False): + + super(MForm, self).__init__() + self.radioclient = radioclient +# print("before radioclient.getHost()", radioclient.getHost(), radioclient.getPort(), "prompt", prompt) + if(dialogprompt or radioclient.getHost() is None or radioclient.getPort() is None): +# print("before ConInfoDialog") + askinfo = ConInfoDialog(self); + if askinfo.exec_(): + host = str(askinfo.host.text()); + port = str(askinfo.port.text()); +# print("before radioclient.newConnection host: %s port: %s"%(host,port)) + newradio = self.radioclient.newConnection(host, port) + if newradio is None: + print("Error making a %s connection to %s:%s from %s" % (radioclient.getName(), host, port, radioclient)) + else: + self.radioclient = newradio + + else: + self.radioclient = Nonclient = None + return + + + self.uid = uid + self.parent = parent + self.horizontalLayout = QtGui.QVBoxLayout(self) + self.gridLayout = QtGui.QGridLayout() + + self.knobprops = self.radioclient.properties([]) + #print("props5:", self.knobprops) + self.parent.knobprops.append(self.knobprops) + self.resize(775,500) + self.timer = QtCore.QTimer() + self.constupdatediv = 0 + self.tableupdatediv = 0 + plotsize=250 + + # make table + self.table = GrDataPlotterValueTable(uid, self, 0, 0, 400, 200) + sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Preferred) + self.table.treeWidget.setSizePolicy(sizePolicy) + self.table.treeWidget.setEditTriggers(QtGui.QAbstractItemView.EditKeyPressed) + self.table.treeWidget.setSortingEnabled(True) + self.table.treeWidget.setDragEnabled(True) + + # add things to layouts + self.horizontalLayout.addWidget(self.table.treeWidget) + + # set up timer + self.connect(self.timer, QtCore.SIGNAL('timeout()'), self.update) + self.updateRate = updateRate; + self.timer.start(self.updateRate) + + # set up context menu .. + self.table.treeWidget.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) + self.table.treeWidget.customContextMenuRequested.connect(self.openMenu) + + # Set up double-click to launch default plotter + self.connect(self.table.treeWidget, + QtCore.SIGNAL('itemDoubleClicked(QTreeWidgetItem*, int)'), + self.parent.newSub); + + # Allow drag/drop event from table item to plotter + self.connect(self.table.treeWidget, + QtCore.SIGNAL('itemPressed(QTreeWidgetItem*, int)'), + self.parent.startDrag) + + def openMenu(self, pos): + index = self.table.treeWidget.selectedIndexes() + item = self.table.treeWidget.itemFromIndex(index[0]) + itemname = str(item.text(0)) + self.parent.propertiesMenu(itemname, self.radioclient, self.uid) + + +def get_minmax(p): + pmin = p.min.value + pmax = p.max.value + + # Find min/max or real or imag for GNURadio::complex + # TODO: fix complex + if(type(pmin) == ControlPort.complex): + pmin = min(pmin.re, pmin.im) + if(type(pmax) == ControlPort.complex): + pmax = max(pmax.re, pmax.im) + + # If it's a byte stream, Python thinks it's a string. + try: + if(type(pmin) == str): + pmin = struct.unpack('b', pmin)[0] + if(type(pmax) == str): + pmax = struct.unpack('b', pmax)[0] + except struct.error: + pmin = [] + pmax = [] + + if pmin == []: + pmin = None + else: + pmin = 1.1*float(pmin) + if pmax == []: + pmax = None + else: + pmax = 1.1*float(pmax) + + return pmin, pmax + +class MyApp(object): + def __init__(self, args): + from gnuradio.ctrlport.GNURadioControlPortClient import GNURadioControlPortClient + GNURadioControlPortClient(args, 'thrift', self.run, QtGui.QApplication(sys.argv).exec_) + + def run(self, client): + MAINWindow(client).show() + +MyApp(sys.argv) diff --git a/gnuradio-runtime/python/gnuradio/ctrlport/gr-perf-monitorx b/gnuradio-runtime/python/gnuradio/ctrlport/gr-perf-monitorx new file mode 100644 index 0000000000..cebc00dcf4 --- /dev/null +++ b/gnuradio-runtime/python/gnuradio/ctrlport/gr-perf-monitorx @@ -0,0 +1,875 @@ +#!/usr/bin/env python +# +# Copyright 2012-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. +# + +import random,math,operator +import networkx as nx +import matplotlib +matplotlib.use("QT4Agg") +import matplotlib.pyplot as plt +from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas +from matplotlib.backends.backend_qt4agg import NavigationToolbar2QTAgg as NavigationToolbar +from matplotlib.figure import Figure + +from PyQt4 import QtCore,Qt,Qwt5 +import PyQt4.QtGui as QtGui +import sys, time, re, pprint +import itertools + +from gnuradio import gr, ctrlport +from gnuradio.ctrlport.GrDataPlotter import * + +class MAINWindow(QtGui.QMainWindow): + def minimumSizeHint(self): + return QtGui.QSize(800,600) + + def __init__(self, radioclient): + + super(MAINWindow, self).__init__() + self.radioclient = radioclient + self.conns = [] + self.plots = [] + self.knobprops = [] + + self.mdiArea = QtGui.QMdiArea() + self.mdiArea.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded) + self.mdiArea.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded) + self.setCentralWidget(self.mdiArea) + + self.mdiArea.subWindowActivated.connect(self.updateMenus) + self.windowMapper = QtCore.QSignalMapper(self) + self.windowMapper.mapped[QtGui.QWidget].connect(self.setActiveSubWindow) + + self.createActions() + self.createMenus() + self.createToolBars() + self.createStatusBar() + self.updateMenus() + + self.setWindowTitle("GNU Radio Performance Monitor") + self.setUnifiedTitleAndToolBarOnMac(True) + + self.newCon(radioclient) + + icon = QtGui.QIcon(ctrlport.__path__[0] + "/icon.png" ) + self.setWindowIcon(icon) + + def newSubWindow(self, window, title): + child = window; + child.setWindowTitle(title) + self.mdiArea.addSubWindow(child) + self.conns.append(child) + child.show(); + self.mdiArea.currentSubWindow().showMaximized() + + def newCon(self, csomeBool): + child = MForm(self.radioclient, len(self.conns), self, dialogprompt = not csomeBool) + if(child.radioclient is not None): + child.setWindowTitle(str(child.radioclient)) + self.mdiArea.addSubWindow(child) + self.mdiArea.currentSubWindow().showMaximized() + + self.conns.append(child) + self.plots.append([]) + + def update(self, knobs, uid): + #sys.stderr.write("KNOB KEYS: {0}\n".format(knobs.keys())) + for plot in self.plots[uid]: + data = knobs[plot.name()].value + plot.update(data) + plot.stop() + plot.wait() + plot.start() + + def setActiveSubWindow(self, window): + if window: + self.mdiArea.setActiveSubWindow(window) + + + def createActions(self): + self.newConAct = QtGui.QAction("&New Connection", + self, shortcut=QtGui.QKeySequence.New, + statusTip="Create a new file", triggered=self.newCon) + + self.exitAct = QtGui.QAction("E&xit", self, shortcut="Ctrl+Q", + statusTip="Exit the application", + triggered=QtGui.qApp.closeAllWindows) + + self.closeAct = QtGui.QAction("Cl&ose", self, shortcut="Ctrl+F4", + statusTip="Close the active window", + triggered=self.mdiArea.closeActiveSubWindow) + + self.closeAllAct = QtGui.QAction("Close &All", self, + statusTip="Close all the windows", + triggered=self.mdiArea.closeAllSubWindows) + + qks = QtGui.QKeySequence(QtCore.Qt.CTRL + QtCore.Qt.Key_T); + self.tileAct = QtGui.QAction("&Tile", self, + statusTip="Tile the windows", + triggered=self.mdiArea.tileSubWindows, + shortcut=qks) + + qks = QtGui.QKeySequence(QtCore.Qt.CTRL + QtCore.Qt.Key_C); + self.cascadeAct = QtGui.QAction("&Cascade", self, + statusTip="Cascade the windows", shortcut=qks, + triggered=self.mdiArea.cascadeSubWindows) + + self.nextAct = QtGui.QAction("Ne&xt", self, + shortcut=QtGui.QKeySequence.NextChild, + statusTip="Move the focus to the next window", + triggered=self.mdiArea.activateNextSubWindow) + + self.previousAct = QtGui.QAction("Pre&vious", self, + shortcut=QtGui.QKeySequence.PreviousChild, + statusTip="Move the focus to the previous window", + triggered=self.mdiArea.activatePreviousSubWindow) + + self.separatorAct = QtGui.QAction(self) + self.separatorAct.setSeparator(True) + + self.aboutAct = QtGui.QAction("&About", self, + statusTip="Show the application's About box", + triggered=self.about) + + self.aboutQtAct = QtGui.QAction("About &Qt", self, + statusTip="Show the Qt library's About box", + triggered=QtGui.qApp.aboutQt) + + def createMenus(self): + self.fileMenu = self.menuBar().addMenu("&File") + self.fileMenu.addAction(self.newConAct) + self.fileMenu.addSeparator() + self.fileMenu.addAction(self.exitAct) + + self.windowMenu = self.menuBar().addMenu("&Window") + self.updateWindowMenu() + self.windowMenu.aboutToShow.connect(self.updateWindowMenu) + + self.menuBar().addSeparator() + + self.helpMenu = self.menuBar().addMenu("&Help") + self.helpMenu.addAction(self.aboutAct) + self.helpMenu.addAction(self.aboutQtAct) + + def createToolBars(self): + self.fileToolBar = self.addToolBar("File") + self.fileToolBar.addAction(self.newConAct) + + self.fileToolBar = self.addToolBar("Window") + self.fileToolBar.addAction(self.tileAct) + self.fileToolBar.addAction(self.cascadeAct) + + def createStatusBar(self): + self.statusBar().showMessage("Ready") + + + def activeMdiChild(self): + activeSubWindow = self.mdiArea.activeSubWindow() + if activeSubWindow: + return activeSubWindow.widget() + return None + + def updateMenus(self): + hasMdiChild = (self.activeMdiChild() is not None) + self.closeAct.setEnabled(hasMdiChild) + self.closeAllAct.setEnabled(hasMdiChild) + self.tileAct.setEnabled(hasMdiChild) + self.cascadeAct.setEnabled(hasMdiChild) + self.nextAct.setEnabled(hasMdiChild) + self.previousAct.setEnabled(hasMdiChild) + self.separatorAct.setVisible(hasMdiChild) + + def updateWindowMenu(self): + self.windowMenu.clear() + self.windowMenu.addAction(self.closeAct) + self.windowMenu.addAction(self.closeAllAct) + self.windowMenu.addSeparator() + self.windowMenu.addAction(self.tileAct) + self.windowMenu.addAction(self.cascadeAct) + self.windowMenu.addSeparator() + self.windowMenu.addAction(self.nextAct) + self.windowMenu.addAction(self.previousAct) + self.windowMenu.addAction(self.separatorAct) + + def about(self): + about_info = \ +'''Copyright 2012 Free Software Foundation, Inc.\n +This program is part of GNU Radio.\n +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.\n +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.\n +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.''' + + QtGui.QMessageBox.about(None, "gr-perf-monitorx", about_info) + + +class ConInfoDialog(QtGui.QDialog): + def __init__(self, parent=None): + super(ConInfoDialog, self).__init__(parent) + + self.gridLayout = QtGui.QGridLayout(self) + + + self.host = QtGui.QLineEdit(self); + self.port = QtGui.QLineEdit(self); + self.host.setText("localhost"); + self.port.setText("43243"); + + self.buttonBox = QtGui.QDialogButtonBox(QtGui.QDialogButtonBox.Ok | + QtGui.QDialogButtonBox.Cancel) + + self.gridLayout.addWidget(self.host); + self.gridLayout.addWidget(self.port); + self.gridLayout.addWidget(self.buttonBox); + + self.buttonBox.accepted.connect(self.accept) + self.buttonBox.rejected.connect(self.reject) + + + def accept(self): + self.done(1); + + def reject(self): + self.done(0); + + +class DataTable(QtGui.QWidget): + def update(self): + print "update" + + def closeEvent(self, event): + self.timer = None + + def __init__(self, radioclient, G): + QtGui.QWidget.__init__( self) + + self.layout = QtGui.QVBoxLayout(self) + self.hlayout = QtGui.QHBoxLayout() + self.layout.addLayout(self.hlayout) + + self.G = G + self.radioclient = radioclient + + self._keymap = None + + self.disp = None + + # Create a combobox to set the type of statistic we want. + self._statistic = "Instantaneous" + self._statistics_table = {"Instantaneous": "", + "Average": "avg ", + "Variance": "var "} + self.stattype = QtGui.QComboBox() + self.stattype.addItem("Instantaneous") + self.stattype.addItem("Average") + self.stattype.addItem("Variance") + self.stattype.setMaximumWidth(200) + self.hlayout.addWidget(self.stattype) + self.stattype.currentIndexChanged.connect(self.stat_changed) + + # Create a checkbox to toggle sorting of graphs + self._sort = False + self.checksort = QtGui.QCheckBox("Sort") + self.checksort.setCheckState(self._sort) + self.hlayout.addWidget(self.checksort); + self.checksort.stateChanged.connect(self.checksort_changed) + + # set up table + self.perfTable = Qt.QTableWidget() + self.perfTable.setColumnCount(2) + self.perfTable.verticalHeader().hide() + self.perfTable.setHorizontalHeaderLabels( ["Block Name", "Percent Runtime"] ) + self.perfTable.horizontalHeader().setStretchLastSection(True) + self.perfTable.setSortingEnabled(True) + nodes = self.G.nodes(data=True) + + # set up plot + self.f = plt.figure(figsize=(10,8), dpi=90) + self.sp = self.f.add_subplot(111) + self.sp.autoscale_view(True,True,True) + self.sp.set_autoscale_on(True) + self.canvas = FigureCanvas(self.f) + + # set up tabs + self.tabber = QtGui.QTabWidget(); + self.layout.addWidget(self.tabber); + self.tabber.addTab(self.perfTable,"Table View"); + self.tabber.addTab(self.canvas, "Graph View"); + + # set up timer + self.timer = QtCore.QTimer() + self.connect(self.timer, QtCore.SIGNAL('timeout()'), self.update) + self.timer.start(500) + + for i in range(0,len(nodes)): + self.perfTable.setItem( + i,0, + Qt.QTableWidgetItem(nodes[i][0])) + + def table_update(self,data): + for k in data.keys(): + weight = data[k] + existing = self.perfTable.findItems(str(k),QtCore.Qt.MatchFixedString) + if(len(existing) == 0): + i = self.perfTable.rowCount(); + self.perfTable.setRowCount( i+1) + self.perfTable.setItem( i,0, Qt.QTableWidgetItem(str(k))) + self.perfTable.setItem( i,1, Qt.QTableWidgetItem(str(weight))) + else: + self.perfTable.setItem( self.perfTable.row(existing[0]),1, Qt.QTableWidgetItem(str(weight))) + + def stat_changed(self, index): + self._statistic = str(self.stattype.currentText()) + + def checksort_changed(self, state): + self._sort = state > 0 + +class DataTableBuffers(DataTable): + def __init__(self, radioclient, G): + super(DataTableBuffers, self).__init__(radioclient, G) + self.perfTable.setHorizontalHeaderLabels( ["Block Name", "Percent Buffer Full"] ) + + def update(self): + nodes = self.G.nodes(); + + # get buffer fullness for all blocks + kl = map(lambda x: "%s::%soutput %% full" % \ + (x, self._statistics_table[self._statistic]), + nodes); + buf_knobs = self.radioclient.getKnobs(kl) + + # strip values out of ctrlport response + buffer_fullness = dict(zip( + map(lambda x: x.split("::")[0], buf_knobs.keys()), + map(lambda x: x.value, buf_knobs.values()))) + + blockport_fullness = {} + for blk in buffer_fullness: + bdata = buffer_fullness[blk] + if bdata: + for port in range(0,len(bdata)): + blockport_fullness["%s:%d"%(blk,port)] = bdata[port] + + if(self.perfTable.isVisible()): + self.table_update(blockport_fullness); + + else: + if(self._sort): + sorted_fullness = sorted(blockport_fullness.iteritems(), + key=operator.itemgetter(1)) + self._keymap = map(operator.itemgetter(0), sorted_fullness) + else: + if self._keymap: + sorted_fullness = len(self._keymap)*['',] + for b in blockport_fullness: + sorted_fullness[self._keymap.index(b)] = (b, blockport_fullness[b]) + else: + sorted_fullness = blockport_fullness.items() + + if(not self.disp): + self.disp = self.sp.bar(range(0,len(sorted_fullness)), + map(lambda x: x[1], sorted_fullness), + alpha=0.5) + self.sp.set_ylabel("% Buffers Full"); + self.sp.set_xticks( map(lambda x: x+0.5, range(0,len(sorted_fullness)))) + self.sp.set_xticklabels(map(lambda x: " " + x, map(lambda x: x[0], sorted_fullness)), + rotation="vertical", verticalalignment="bottom") + else: + self.sp.set_xticklabels(map(lambda x: " " + x, map(lambda x: x[0], sorted_fullness)), + rotation="vertical", verticalalignment="bottom") + for r,w in zip(self.disp, sorted_fullness): + r.set_height(w[1]) + + self.canvas.draw() + +class DataTableRuntimes(DataTable): + def __init__(self, radioclient, G): + super(DataTableRuntimes, self).__init__( radioclient, G) + + def update(self): + nodes = self.G.nodes(); + + # get work time for all blocks + kl = map(lambda x: "%s::%swork time" % \ + (x, self._statistics_table[self._statistic]), + nodes); + wrk_knobs = self.radioclient.getKnobs(kl) + + # strip values out of ctrlport response + total_work = sum(map(lambda x: x.value, wrk_knobs.values())) + if(total_work == 0): + total_work = 1 + work_times = dict(zip( + map(lambda x: x.split("::")[0], wrk_knobs.keys()), + map(lambda x: x.value/total_work, wrk_knobs.values()))) + + # update table view + if(self.perfTable.isVisible()): + self.table_update(work_times) + + else: + if(self._sort): + sorted_work = sorted(work_times.iteritems(), key=operator.itemgetter(1)) + self._keymap = map(operator.itemgetter(0), sorted_work) + else: + if self._keymap: + sorted_work = len(self._keymap)*['',] + for b in work_times: + sorted_work[self._keymap.index(b)] = (b, work_times[b]) + else: + sorted_work = work_times.items() + + f = plt.figure(self.f.number) + if(not self.disp): + self.disp = self.sp.bar(range(0,len(sorted_work)), + map(lambda x: x[1], sorted_work), + alpha=0.5) + self.sp.set_ylabel("% Runtime"); + self.sp.set_xticks( map(lambda x: x+0.5, range(0,len(sorted_work)))) + self.sp.set_xticklabels( map(lambda x: " " + x[0], sorted_work), + rotation="vertical", verticalalignment="bottom" ) + else: + self.sp.set_xticklabels( map(lambda x: " " + x[0], sorted_work), + rotation="vertical", verticalalignment="bottom" ) + for r,w in zip(self.disp, sorted_work): + r.set_height(w[1]) + + self.canvas.draw() + +class MForm(QtGui.QWidget): + def update(self): + try: + try: + # update current clock type + self.prevent_clock_change = True; + kl1 = None; + if(self.clockKey == None): + kl1 = self.radioclient.getRe([".*perfcounter_clock"]) + else: + kl1 = self.radioclient.getKnobs([self.clockKey]) + self.clockKey = kl1.keys()[0] + self.currClock = kl1[self.clockKey].value + self.clockSelIdx = self.clocks.values().index(self.currClock) + self.clockSel.setCurrentIndex(self.clockSelIdx) + self.prevent_clock_change = False + except: + print "WARNING: Failed to get current clock setting!" + + nodes_stream = self.G_stream.nodes() + nodes_msg = self.G_msg.nodes() + + # get current buffer depths of all output buffers + kl = map(lambda x: "%s::%soutput %% full" % \ + (x, self._statistics_table[self._statistic]), + nodes_stream); + + st = time.time() + buf_knobs = self.radioclient.getKnobs(kl) + td1 = time.time() - st; + + # strip values out of ctrlport response + buf_vals = dict(zip( + map(lambda x: x.split("::")[0], buf_knobs.keys()), + map(lambda x: x.value, buf_knobs.values()))) + + # get work time for all blocks + kl = map(lambda x: "%s::%swork time" % \ + (x, self._statistics_table[self._statistic]), + nodes_stream); + st = time.time() + wrk_knobs = self.radioclient.getKnobs(kl) + td2 = time.time() - st; + + # strip values out of ctrlport response + total_work = sum(map(lambda x: x.value, wrk_knobs.values())) + if(total_work == 0): + total_work = 1 + work_times = dict(zip( + map(lambda x: x.split("::")[0], wrk_knobs.keys()), + map(lambda x: x.value/total_work, wrk_knobs.values()))) + work_times_padded = dict(zip( + self.G.nodes(), + [0.1]*len(self.G.nodes()))) + work_times_padded.update(work_times) + + for n in nodes_stream: + # ne is the list of edges away from this node! + ne = self.G.edges([n],True); + #for e in ne: # iterate over edges from this block + for e in ne: # iterate over edges from this block + # get the right output buffer/port weight for each edge + sourceport = e[2]["sourceport"]; + if(e[2]["type"] == "stream"): + newweight = buf_vals[n][sourceport] + e[2]["weight"] = newweight; + + for n in nodes_msg: + ne = self.G.edges([n],True); + for e in ne: # iterate over edges from this block + sourceport = e[2]["sourceport"]; + if(e[2]["type"] == "msg"): + newweight = 0.01; + e[2]["weight"] = newweight; + + # set updated weights + #self.node_weights = map(lambda x: 20+2000*work_times[x], nodes_stream); + self.node_weights = map(lambda x: 20+2000*work_times_padded[x], self.G.nodes()); + self.edge_weights = map(lambda x: 100.0*x[2]["weight"], self.G.edges(data=True)); + + # draw graph updates + self.updateGraph(); + + latency = td1 + td2; + self.parent.statusBar().showMessage("Current GNU Radio Control Port Query Latency: %f ms"%\ + (latency*1000)) + + except Exception, e: + sys.stderr.write("gr-perf-monitorx: radio.getKnobs threw exception ({0}).\n".format(e)) + if(type(self.parent) is MAINWindow): + # Find window of connection + remove = [] + for p in self.parent.mdiArea.subWindowList(): + if self.parent.conns[self.uid] == p.widget(): + remove.append(p) + + # Remove subwindows for connection and plots + for r in remove: + self.parent.mdiArea.removeSubWindow(r) + + # Clean up self + self.close() + else: + sys.exit(1) + return + + def rtt(self): + self.parent.newSubWindow( DataTableRuntimes(self.radioclient, self.G_stream), "Runtime Table" ); + + def bpt(self): + self.parent.newSubWindow( DataTableBuffers(self.radioclient, self.G_stream), "Buffers Table" ); + + def resetPCs(self): + knobs = [] + for b in self.blocks_list: + knobs += [self.radioclient.Knob(b + "::reset_perf_counters"),] + k = self.radioclient.setKnobs(knobs) + + def toggleFlowgraph(self): + if self.pauseFGAct.isChecked(): + self.pauseFlowgraph() + else: + self.unpauseFlowgraph() + + def pauseFlowgraph(self): + knobs = [self.radioclient.Knob(self.top_block + "::lock"), + self.radioclient.Knob(self.top_block + "::stop")] + k = self.radioclient.setKnobs(knobs) + + def unpauseFlowgraph(self): + knobs = [self.radioclient.Knob(self.top_block + "::unlock")] + k = self.radioclient.setKnobs(knobs) + + def stat_changed(self, index): + self._statistic = str(self.stattype.currentText()) + + def update_clock(self, clkidx): + if(self.prevent_clock_change): + return; + idx = self.clockSel.currentIndex(); + clk = self.clocks.values()[idx] +# print "UPDATE CLOCK!!! %d -> %d"%(idx,clk); + k = self.radioclient.getKnobs([self.clockKey]); + k[self.clockKey].value = clk; + km = {}; + km[self.clockKey] = k[self.clockKey]; + self.radioclient.setKnobs(km); + + def __init__(self, radioclient, uid=0, parent=None, dialogprompt = False): + + super(MForm, self).__init__() + self.radioclient = radioclient +# print("before radioclient.getHost()", radioclient.getHost(), radioclient.getPort(), "prompt", prompt) + if(dialogprompt or radioclient.getHost() is None or radioclient.getPort() is None): +# print("before ConInfoDialog") + askinfo = ConInfoDialog(self); + if askinfo.exec_(): + host = str(askinfo.host.text()); + port = str(askinfo.port.text()); +# print("before radioclient.newConnection host: %s port: %s"%(host,port)) + newradio = self.radioclient.newConnection(host, port) + if newradio is None: + print("Error making a %s connection to %s:%s from %s" % (radioclient.getName(), host, port, radioclient)) + else: + self.radioclient = newradio + + else: + self.radioclient = None + return + + self.uid = uid + self.parent = parent + + self.layoutTop = QtGui.QVBoxLayout(self) + self.ctlBox = QtGui.QHBoxLayout(); + self.layout = QtGui.QHBoxLayout() + + self.layoutTop.addLayout(self.ctlBox); + self.layoutTop.addLayout(self.layout); + + self.rttAct = QtGui.QAction("Runtime Table", + self, statusTip="Runtime Table", triggered=self.rtt) + self.rttBut = Qt.QToolButton() + self.rttBut.setDefaultAction(self.rttAct); + self.ctlBox.addWidget(self.rttBut); + + self.bptAct = QtGui.QAction("Buffer Table", + self, statusTip="Buffer Table", triggered=self.bpt) + self.bptBut = Qt.QToolButton() + self.bptBut.setDefaultAction(self.bptAct); + self.ctlBox.addWidget(self.bptBut); + + self.resetPCsAct = QtGui.QAction("Reset", self, + statusTip="Reset all Performance Counters", + triggered=self.resetPCs) + self.resetPCsBut = Qt.QToolButton() + self.resetPCsBut.setDefaultAction(self.resetPCsAct); + self.ctlBox.addWidget(self.resetPCsBut); + + self.pauseFGAct = QtGui.QAction("Pause", self, + statusTip="Pause the Flowgraph", + triggered=self.toggleFlowgraph) + self.pauseFGAct.setCheckable(True) + self.pauseFGBut = Qt.QToolButton() + self.pauseFGBut.setDefaultAction(self.pauseFGAct); + self.ctlBox.addWidget(self.pauseFGBut); + + self.prevent_clock_change = True; + self.clockKey = None; + self.clocks = {"MONOTONIC":1, "THREAD":3}; + self.clockSel = QtGui.QComboBox(self); + map(lambda x: self.clockSel.addItem(x), self.clocks.keys()); + self.ctlBox.addWidget(self.clockSel); + self.clockSel.currentIndexChanged.connect(self.update_clock); + self.prevent_clock_change = False; + + self._statistic = "Instantaneous" + self._statistics_table = {"Instantaneous": "", + "Average": "avg ", + "Variance": "var "} + self.stattype = QtGui.QComboBox() + self.stattype.addItem("Instantaneous") + self.stattype.addItem("Average") + self.stattype.addItem("Variance") + self.stattype.setMaximumWidth(200) + self.ctlBox.addWidget(self.stattype); + self.stattype.currentIndexChanged.connect(self.stat_changed) + +# self.setLayout(self.layout); + + self.radio = radioclient + self.knobprops = self.radio.properties([]) + self.parent.knobprops.append(self.knobprops) + + self.timer = QtCore.QTimer() + self.constupdatediv = 0 + self.tableupdatediv = 0 + plotsize=250 + + + # Set up the graph of blocks + input_name = lambda x: x+"::avg input % full" + output_name = lambda x: x+"::avg output % full" + wtime_name = lambda x: x+"::avg work time" + nout_name = lambda x: x+"::avg noutput_items" + nprod_name = lambda x: x+"::avg nproduced" + + tmplist = [] + knobs = self.radio.getKnobs([]) + edgelist = None + msgedgelist = None + for k in knobs: + propname = k.split("::") + blockname = propname[0] + keyname = propname[1] + if(keyname == "edge list"): + edgelist = knobs[k].value + self.top_block = blockname + elif(keyname == "msg edges list"): + msgedgelist = knobs[k].value + elif(blockname not in tmplist): + # only take gr_blocks (no hier_block2) + if(knobs.has_key(input_name(blockname))): + tmplist.append(blockname) + + + if not edgelist: + sys.stderr.write("Could not find list of edges from flowgraph. " + \ + "Make sure the option 'edges_list' is enabled " + \ + "in the ControlPort configuration.\n\n") + sys.exit(1) + + self.blocks_list = tmplist + edges = edgelist.split("\n")[0:-1] + msgedges = msgedgelist.split("\n")[0:-1] + + edgepairs_stream = []; + edgepairs_msg = []; + + # add stream connections + for e in edges: + _e = e.split("->") + edgepairs_stream.append( (_e[0].split(":")[0], _e[1].split(":")[0], + {"type":"stream", "sourceport":int(_e[0].split(":")[1])}) ); + + # add msg connections + for e in msgedges: + _e = e.split("->") + edgepairs_msg.append( (_e[0].split(":")[0], _e[1].split(":")[0], + {"type":"msg", "sourceport":_e[0].split(":")[1]}) ); + + self.G = nx.MultiDiGraph(); + self.G_stream = nx.MultiDiGraph(); + self.G_msg = nx.MultiDiGraph(); + + self.G.add_edges_from(edgepairs_stream); + self.G.add_edges_from(edgepairs_msg); + + self.G_stream.add_edges_from(edgepairs_stream); + self.G_msg.add_edges_from(edgepairs_msg); + + n_edges = self.G.edges(data=True); + for e in n_edges: + e[2]["weight"] = 5+random.random()*10; + + self.G.clear(); + self.G.add_edges_from(n_edges); + + + self.f = plt.figure(figsize=(10,8), dpi=90) + self.sp = self.f.add_subplot(111); + self.sp.autoscale_view(True,True,True); + self.sp.set_autoscale_on(True) + + self.canvas = FigureCanvas(self.f) + self.layout.addWidget(self.canvas); + + self.pos = nx.graphviz_layout(self.G); + #self.pos = nx.pygraphviz_layout(self.G); + #self.pos = nx.spectral_layout(self.G); + #self.pos = nx.circular_layout(self.G); + #self.pos = nx.shell_layout(self.G); + #self.pos = nx.spring_layout(self.G); + + # generate weights and plot + self.update(); + + # set up timer + self.timer = QtCore.QTimer() + self.connect(self.timer, QtCore.SIGNAL('timeout()'), self.update) + self.timer.start(1000) + + # Set up mouse callback functions to move blocks around. + self._grabbed = False + self._current_block = '' + self.f.canvas.mpl_connect('button_press_event', + self.button_press) + self.f.canvas.mpl_connect('motion_notify_event', + self.mouse_move) + self.f.canvas.mpl_connect('button_release_event', + self.button_release) + + def button_press(self, event): + x, y = event.xdata, event.ydata + thrsh = 100 + + if(x is not None and y is not None): + nearby = map(lambda z: math.sqrt( math.pow(x-z[0],2) + math.pow(y-z[1],2)), self.pos.values()) + i = nearby.index(min(nearby)) + if(abs(self.pos.values()[i][0] - x) < thrsh and + abs(self.pos.values()[i][1]-y) < thrsh): + self._current_block = self.pos.keys()[i] + #print "MOVING BLOCK: ", self._current_block + #print "CUR POS: ", self.pos.values()[i] + self._grabbed = True + + def mouse_move(self, event): + if self._grabbed: + x, y = event.xdata, event.ydata + if(x is not None and y is not None): + #print "NEW POS: ", (x,y) + self.pos[self._current_block] = (x,y) + self.updateGraph(); + + def button_release(self, event): + self._grabbed = False + + + def openMenu(self, pos): + index = self.table.treeWidget.selectedIndexes() + item = self.table.treeWidget.itemFromIndex(index[0]) + itemname = str(item.text(0)) + self.parent.propertiesMenu(itemname, self.radioclient, self.uid) + + def updateGraph(self): + + self.canvas.updateGeometry() + self.sp.clear(); + plt.figure(self.f.number) + plt.subplot(111); + nx.draw(self.G, self.pos, + edge_color=self.edge_weights, + node_color='#A0CBE2', + width=map(lambda x: 3+math.log(x), self.edge_weights), + node_shape="s", + node_size=self.node_weights, + #edge_cmap=plt.cm.Blues, + edge_cmap=plt.cm.Reds, + ax=self.sp, + arrows=False + ) + nx.draw_networkx_labels(self.G, self.pos, + font_size=12) + + self.canvas.draw(); + self.canvas.show(); + + +class MyApp(object): + def __init__(self, args): + p = gr.prefs() + cp_on = p.get_bool("ControlPort", "on", False) + cp_edges = p.get_bool("ControlPort", "edges_list", False) + pcs_on = p.get_bool("PerfCounters", "on", False) + pcs_exported = p.get_bool("PerfCounters", "export", False) + if(not (pcs_on and cp_on and pcs_exported and cp_edges)): + print("Configuration has not turned on all of the appropriate ControlPort features:") + print("\t[ControlPort] on = {0}".format(cp_on)) + print("\t[ControlPort] edges_list = {0}".format(cp_edges)) + print("\t[PerfCounters] on = {0}".format(pcs_on)) + print("\t[PerfCounters] export = {0}".format(pcs_exported)) + exit(1) + + from gnuradio.ctrlport.GNURadioControlPortClient import GNURadioControlPortClient + GNURadioControlPortClient(args, 'thrift', self.run, QtGui.QApplication(sys.argv).exec_) + + def run(self, client): + MAINWindow(client).show() + +MyApp(sys.argv) diff --git a/gnuradio-runtime/python/gnuradio/ctrlport/monitor.py b/gnuradio-runtime/python/gnuradio/ctrlport/monitor.py index 8bb26d93a1..f651be2449 100644 --- a/gnuradio-runtime/python/gnuradio/ctrlport/monitor.py +++ b/gnuradio-runtime/python/gnuradio/ctrlport/monitor.py @@ -48,9 +48,9 @@ class monitor: print "monitor::endpoints() = %s" % (gr.rpcmanager_get().endpoints()) try: cmd = map(lambda a: [self.tool, - re.search("\d+\.\d+\.\d+\.\d+",a).group(0), - re.search("-p (\d+)",a).group(1)], - gr.rpcmanager_get().endpoints())[0] + re.search("-h (\S+|\d+\.\d+\.\d+\.\d+)",a).group(1), + re.search("-p (\d+)",a).group(1)], + gr.rpcmanager_get().endpoints())[0] print "running: %s"%(str(cmd)) self.proc = subprocess.Popen(cmd); self.started = True diff --git a/gnuradio-runtime/python/gnuradio/gr/qa_tag_utils.py b/gnuradio-runtime/python/gnuradio/gr/qa_tag_utils.py index 1a08ac5ae6..55b62a12ac 100755 --- a/gnuradio-runtime/python/gnuradio/gr/qa_tag_utils.py +++ b/gnuradio-runtime/python/gnuradio/gr/qa_tag_utils.py @@ -76,6 +76,38 @@ class test_tag_utils (gr_unittest.TestCase): self.assertTrue(pmt.equal(t_tuple.value, value)) self.assertEqual(t_tuple.offset, offset) + def test_003(self): + offsets = (6, 3, 8) + key = pmt.string_to_symbol('key') + srcid = pmt.string_to_symbol('qa_tag_utils') + tags = [] + + for k in offsets: + t = gr.tag_t() + t.offset = k + t.key = key + t.value = pmt.from_long(k) + t.srcid = srcid + tags.append(t) + + for k, t in zip(sorted(offsets), + sorted(tags, key=gr.tag_t_offset_compare_key())): + self.assertEqual(t.offset, k) + self.assertTrue(pmt.equal(t.key, key)) + self.assertTrue(pmt.equal(t.value, pmt.from_long(k))) + self.assertTrue(pmt.equal(t.srcid, srcid)) + + tmin = min(tags, key=gr.tag_t_offset_compare_key()) + self.assertEqual(tmin.offset, min(offsets)) + self.assertTrue(pmt.equal(tmin.key, key)) + self.assertTrue(pmt.equal(tmin.value, pmt.from_long(min(offsets)))) + self.assertTrue(pmt.equal(tmin.srcid, srcid)) + + tmax = max(tags, key=gr.tag_t_offset_compare_key()) + self.assertEqual(tmax.offset, max(offsets)) + self.assertTrue(pmt.equal(tmax.key, key)) + self.assertTrue(pmt.equal(tmax.value, pmt.from_long(max(offsets)))) + self.assertTrue(pmt.equal(tmax.srcid, srcid)) if __name__ == '__main__': diff --git a/gnuradio-runtime/python/gnuradio/gr/tag_utils.py b/gnuradio-runtime/python/gnuradio/gr/tag_utils.py index dc36e05250..a7745428c7 100644 --- a/gnuradio-runtime/python/gnuradio/gr/tag_utils.py +++ b/gnuradio-runtime/python/gnuradio/gr/tag_utils.py @@ -108,3 +108,36 @@ def python_to_tag(tag_struct): return tag else: return None + +def tag_t_offset_compare_key(): + """ + Convert a tag_t_offset_compare function into a key=function + This method is modeled after functools.cmp_to_key(_func_). + It can be used by functions that accept a key function, such as + sorted(), min(), max(), etc. to compare tags by their offsets, + e.g., sorted(tag_list, key=gr.tag_t_offset_compare_key()). + """ + class K(object): + def __init__(self, obj, *args): + self.obj = obj + def __lt__(self, other): + # x.offset < y.offset + return gr.tag_t_offset_compare(self.obj, other.obj) + def __gt__(self, other): + # y.offset < x.offset + return gr.tag_t_offset_compare(other.obj, self.obj) + def __eq__(self, other): + # not (x.offset < y.offset) and not (y.offset < x.offset) + return not gr.tag_t_offset_compare(self.obj, other.obj) and \ + not gr.tag_t_offset_compare(other.obj, self.obj) + def __le__(self, other): + # not (y.offset < x.offset) + return not gr.tag_t_offset_compare(other.obj, self.obj) + def __ge__(self, other): + # not (x.offset < y.offset) + return not gr.tag_t_offset_compare(self.obj, other.obj) + def __ne__(self, other): + # (x.offset < y.offset) or (y.offset < x.offset) + return gr.tag_t_offset_compare(self.obj, other.obj) or \ + gr.tag_t_offset_compare(other.obj, self.obj) + return K diff --git a/gnuradio-runtime/python/gnuradio/gr/top_block.py b/gnuradio-runtime/python/gnuradio/gr/top_block.py index f449d98489..2efcbd9aae 100644 --- a/gnuradio-runtime/python/gnuradio/gr/top_block.py +++ b/gnuradio-runtime/python/gnuradio/gr/top_block.py @@ -63,11 +63,13 @@ class _top_block_waiter(_threading.Thread): top_block_wait_unlocked(self.tb) self.event.set() - def wait(self): + def wait(self, handle_sigint=True): try: - while not self.event.isSet(): - self.event.wait(0.100) + while not self.event.wait(0.1): + pass except KeyboardInterrupt: + if not handle_sigint: + raise self.tb.stop() self.wait() @@ -98,6 +100,7 @@ class top_block(hier_block2): """ # not calling hier_block2.__init__, we set our own _impl self._impl = top_block_swig(name) + self.handle_sigint = True def start(self, max_noutput_items=10000000): """ @@ -128,7 +131,7 @@ class top_block(hier_block2): """ Wait for the flowgraph to finish running """ - _top_block_waiter(self._impl).wait() + _top_block_waiter(self._impl).wait(self.handle_sigint) def dot_graph(self): """ diff --git a/gnuradio-runtime/swig/gr_types.i b/gnuradio-runtime/swig/gr_types.i index 8ae953b904..e329a4ce9f 100644 --- a/gnuradio-runtime/swig/gr_types.i +++ b/gnuradio-runtime/swig/gr_types.i @@ -80,15 +80,19 @@ namespace std { %template(gr_vector_vector_complexf) std::vector< std::vector< std::complex<float> > >; %template(gr_vector_vector_complexd) std::vector< std::vector< std::complex<double> > >; -// Fix for Issue #529 -#ifdef SIZE_T_32 - // On 32-bit systems, whenever we see std::vector<size_t>, replace it - // with vector<unsigned int> +// Fix for Issue #529: replace std::vector<size_t> with its equivalent +// in element size, one of "unsigned int", "unsigned long", or +// "unsigned long long". The replacement depends on the sizeof each +// type, as determined in GrSwig.cmake GR_SWIG_MAKE. For SWIG >= +// 3.0.0, none of these will be defined because this issue seems to +// have been fixed. + +#if defined(SIZE_T_UINT) %apply std::vector<unsigned int> { std::vector<size_t> }; -#else - // On 64-bit systems, whenever we see std::vector<size_t>, replace it - // with vector<long unsigned int> - %apply std::vector<long unsigned int> { std::vector<size_t> }; +#elif defined(SIZE_T_UL) + %apply std::vector<unsigned long> { std::vector<size_t> }; +#elif defined(SIZE_T_ULL) + %apply std::vector<unsigned long long> { std::vector<size_t> }; #endif #endif /* SWIG_GR_TYPES_I */ diff --git a/gnuradio-runtime/swig/prefs.i b/gnuradio-runtime/swig/prefs.i index ac5fab7adc..4774146b69 100644 --- a/gnuradio-runtime/swig/prefs.i +++ b/gnuradio-runtime/swig/prefs.i @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2006,2013 Free Software Foundation, Inc. + * Copyright 2006,2015 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -25,6 +25,8 @@ class gr::prefs public: static gr::prefs *singleton(); + void add_config_file(const std::string &configfile); + virtual ~prefs(); std::string to_string(); diff --git a/gr-analog/examples/CMakeLists.txt b/gr-analog/examples/CMakeLists.txt index f0f55b50c8..acb0656b7f 100644 --- a/gr-analog/examples/CMakeLists.txt +++ b/gr-analog/examples/CMakeLists.txt @@ -25,3 +25,10 @@ GR_PYTHON_INSTALL(PROGRAMS DESTINATION ${GR_PKG_ANALOG_EXAMPLES_DIR} COMPONENT "analog_python" ) + +install( + FILES + noise_power.grc + DESTINATION ${GR_PKG_ANALOG_EXAMPLES_DIR} + COMPONENT "analog_python" +) diff --git a/gr-analog/examples/noise_power.grc b/gr-analog/examples/noise_power.grc new file mode 100644 index 0000000000..10a8c62aad --- /dev/null +++ b/gr-analog/examples/noise_power.grc @@ -0,0 +1,1675 @@ +<?xml version='1.0' encoding='ASCII'?> +<?grc format='1' created='3.7.7'?> +<flow_graph> + <timestamp>Sun May 10 20:26:24 2015</timestamp> + <block> + <key>options</key> + <param> + <key>id</key> + <value>noise_power</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>title</key> + <value></value> + </param> + <param> + <key>author</key> + <value></value> + </param> + <param> + <key>description</key> + <value></value> + </param> + <param> + <key>window_size</key> + <value>1280, 1024</value> + </param> + <param> + <key>generate_options</key> + <value>qt_gui</value> + </param> + <param> + <key>category</key> + <value>Custom</value> + </param> + <param> + <key>run_options</key> + <value>prompt</value> + </param> + <param> + <key>run</key> + <value>True</value> + </param> + <param> + <key>max_nouts</key> + <value>0</value> + </param> + <param> + <key>realtime_scheduling</key> + <value></value> + </param> + <param> + <key>thread_safe_setters</key> + <value></value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(8, 11)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>samp_rate</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>32000</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(176, 11)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>analog_fastnoise_source_x</key> + <param> + <key>id</key> + <value>analog_fastnoise_source_x_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>noise_type</key> + <value>analog.GR_GAUSSIAN</value> + </param> + <param> + <key>amp</key> + <value>noise</value> + </param> + <param> + <key>seed</key> + <value>0</value> + </param> + <param> + <key>samples</key> + <value>8192</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(8, 75)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>analog_noise_source_x</key> + <param> + <key>id</key> + <value>analog_noise_source_x_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>noise_type</key> + <value>analog.GR_GAUSSIAN</value> + </param> + <param> + <key>amp</key> + <value>noise</value> + </param> + <param> + <key>seed</key> + <value>0</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(8, 267)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_throttle</key> + <param> + <key>id</key> + <value>blocks_throttle_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>samples_per_second</key> + <value>samp_rate</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>ignoretag</key> + <value>True</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(208, 99)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_throttle</key> + <param> + <key>id</key> + <value>blocks_throttle_0_1</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>samples_per_second</key> + <value>samp_rate</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>ignoretag</key> + <value>True</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(208, 283)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_complex_to_mag_squared</key> + <param> + <key>id</key> + <value>blocks_complex_to_mag_squared_2</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(368, 104)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_complex_to_mag_squared</key> + <param> + <key>id</key> + <value>blocks_complex_to_mag_squared_1</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(368, 288)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>analog_fastnoise_source_x</key> + <param> + <key>id</key> + <value>analog_fastnoise_source_x_1</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>float</value> + </param> + <param> + <key>noise_type</key> + <value>analog.GR_GAUSSIAN</value> + </param> + <param> + <key>amp</key> + <value>noise</value> + </param> + <param> + <key>seed</key> + <value>0</value> + </param> + <param> + <key>samples</key> + <value>8192</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(8, 171)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>analog_noise_source_x</key> + <param> + <key>id</key> + <value>analog_noise_source_x_1</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>float</value> + </param> + <param> + <key>noise_type</key> + <value>analog.GR_GAUSSIAN</value> + </param> + <param> + <key>amp</key> + <value>noise</value> + </param> + <param> + <key>seed</key> + <value>0</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(8, 347)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_throttle</key> + <param> + <key>id</key> + <value>blocks_throttle_0_2</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>float</value> + </param> + <param> + <key>samples_per_second</key> + <value>samp_rate</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>ignoretag</key> + <value>True</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(208, 363)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_throttle</key> + <param> + <key>id</key> + <value>blocks_throttle_0_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>float</value> + </param> + <param> + <key>samples_per_second</key> + <value>samp_rate</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>ignoretag</key> + <value>True</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(208, 195)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_abs_xx</key> + <param> + <key>id</key> + <value>blocks_abs_xx_0_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>type</key> + <value>float</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(368, 200)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_multiply_xx</key> + <param> + <key>id</key> + <value>blocks_multiply_xx_0_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>float</value> + </param> + <param> + <key>num_inputs</key> + <value>2</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(480, 184)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_nlog10_ff</key> + <param> + <key>id</key> + <value>blocks_nlog10_ff_0_2</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>n</key> + <value>10</value> + </param> + <param> + <key>k</key> + <value>0</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(784, 355)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>single_pole_iir_filter_xx</key> + <param> + <key>id</key> + <value>single_pole_iir_filter_xx_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>float</value> + </param> + <param> + <key>alpha</key> + <value>0.001</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(592, 99)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>single_pole_iir_filter_xx</key> + <param> + <key>id</key> + <value>single_pole_iir_filter_xx_0_1</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>float</value> + </param> + <param> + <key>alpha</key> + <value>0.001</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(592, 283)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_nlog10_ff</key> + <param> + <key>id</key> + <value>blocks_nlog10_ff_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>n</key> + <value>10</value> + </param> + <param> + <key>k</key> + <value>0</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(784, 91)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_nlog10_ff</key> + <param> + <key>id</key> + <value>blocks_nlog10_ff_0_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>n</key> + <value>10</value> + </param> + <param> + <key>k</key> + <value>0</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(784, 187)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_nlog10_ff</key> + <param> + <key>id</key> + <value>blocks_nlog10_ff_0_1</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>n</key> + <value>10</value> + </param> + <param> + <key>k</key> + <value>0</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(784, 275)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>single_pole_iir_filter_xx</key> + <param> + <key>id</key> + <value>single_pole_iir_filter_xx_0_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>float</value> + </param> + <param> + <key>alpha</key> + <value>0.001</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(592, 195)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>single_pole_iir_filter_xx</key> + <param> + <key>id</key> + <value>single_pole_iir_filter_xx_0_2</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>float</value> + </param> + <param> + <key>alpha</key> + <value>0.001</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(592, 363)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_abs_xx</key> + <param> + <key>id</key> + <value>blocks_abs_xx_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>type</key> + <value>float</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(368, 368)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_multiply_xx</key> + <param> + <key>id</key> + <value>blocks_multiply_xx_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>float</value> + </param> + <param> + <key>num_inputs</key> + <value>2</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(480, 352)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>qtgui_number_sink</key> + <param> + <key>id</key> + <value>qtgui_number_sink_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>name</key> + <value>""</value> + </param> + <param> + <key>type</key> + <value>float</value> + </param> + <param> + <key>autoscale</key> + <value>False</value> + </param> + <param> + <key>avg</key> + <value>0.01</value> + </param> + <param> + <key>graph_type</key> + <value>qtgui.NUM_GRAPH_NONE</value> + </param> + <param> + <key>nconnections</key> + <value>4</value> + </param> + <param> + <key>min</key> + <value>-1</value> + </param> + <param> + <key>max</key> + <value>1</value> + </param> + <param> + <key>update_time</key> + <value>0.10</value> + </param> + <param> + <key>gui_hint</key> + <value></value> + </param> + <param> + <key>label1</key> + <value>Complex Fast</value> + </param> + <param> + <key>unit1</key> + <value></value> + </param> + <param> + <key>color1</key> + <value>("black", "black")</value> + </param> + <param> + <key>factor1</key> + <value>1</value> + </param> + <param> + <key>label2</key> + <value>Real Fast</value> + </param> + <param> + <key>unit2</key> + <value></value> + </param> + <param> + <key>color2</key> + <value>("black", "black")</value> + </param> + <param> + <key>factor2</key> + <value>1</value> + </param> + <param> + <key>label3</key> + <value>Complex Noise</value> + </param> + <param> + <key>unit3</key> + <value></value> + </param> + <param> + <key>color3</key> + <value>("black", "black")</value> + </param> + <param> + <key>factor3</key> + <value>1</value> + </param> + <param> + <key>label4</key> + <value>Real Noise</value> + </param> + <param> + <key>unit4</key> + <value></value> + </param> + <param> + <key>color4</key> + <value>("black", "black")</value> + </param> + <param> + <key>factor4</key> + <value>1</value> + </param> + <param> + <key>label5</key> + <value></value> + </param> + <param> + <key>unit5</key> + <value></value> + </param> + <param> + <key>color5</key> + <value>("black", "black")</value> + </param> + <param> + <key>factor5</key> + <value>1</value> + </param> + <param> + <key>label6</key> + <value></value> + </param> + <param> + <key>unit6</key> + <value></value> + </param> + <param> + <key>color6</key> + <value>("black", "black")</value> + </param> + <param> + <key>factor6</key> + <value>1</value> + </param> + <param> + <key>label7</key> + <value></value> + </param> + <param> + <key>unit7</key> + <value></value> + </param> + <param> + <key>color7</key> + <value>("black", "black")</value> + </param> + <param> + <key>factor7</key> + <value>1</value> + </param> + <param> + <key>label8</key> + <value></value> + </param> + <param> + <key>unit8</key> + <value></value> + </param> + <param> + <key>color8</key> + <value>("black", "black")</value> + </param> + <param> + <key>factor8</key> + <value>1</value> + </param> + <param> + <key>label9</key> + <value></value> + </param> + <param> + <key>unit9</key> + <value></value> + </param> + <param> + <key>color9</key> + <value>("black", "black")</value> + </param> + <param> + <key>factor9</key> + <value>1</value> + </param> + <param> + <key>label10</key> + <value></value> + </param> + <param> + <key>unit10</key> + <value></value> + </param> + <param> + <key>color10</key> + <value>("black", "black")</value> + </param> + <param> + <key>factor10</key> + <value>1</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(992, 208)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable_qtgui_range</key> + <param> + <key>id</key> + <value>noise</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>label</key> + <value>Noise Amplitude</value> + </param> + <param> + <key>value</key> + <value>1</value> + </param> + <param> + <key>start</key> + <value>0</value> + </param> + <param> + <key>stop</key> + <value>10</value> + </param> + <param> + <key>step</key> + <value>0.1</value> + </param> + <param> + <key>widget</key> + <value>counter_slider</value> + </param> + <param> + <key>orient</key> + <value>Qt.Horizontal</value> + </param> + <param> + <key>min_len</key> + <value>200</value> + </param> + <param> + <key>gui_hint</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(8, 435)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <connection> + <source_block_id>analog_fastnoise_source_x_0</source_block_id> + <sink_block_id>blocks_throttle_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>analog_fastnoise_source_x_1</source_block_id> + <sink_block_id>blocks_throttle_0_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>analog_noise_source_x_0</source_block_id> + <sink_block_id>blocks_throttle_0_1</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>analog_noise_source_x_1</source_block_id> + <sink_block_id>blocks_throttle_0_2</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>blocks_throttle_0</source_block_id> + <sink_block_id>blocks_complex_to_mag_squared_2</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>blocks_throttle_0_1</source_block_id> + <sink_block_id>blocks_complex_to_mag_squared_1</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>blocks_throttle_0_2</source_block_id> + <sink_block_id>blocks_abs_xx_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>blocks_throttle_0_0</source_block_id> + <sink_block_id>blocks_abs_xx_0_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>blocks_abs_xx_0</source_block_id> + <sink_block_id>blocks_multiply_xx_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>blocks_abs_xx_0</source_block_id> + <sink_block_id>blocks_multiply_xx_0</sink_block_id> + <source_key>0</source_key> + <sink_key>1</sink_key> + </connection> + <connection> + <source_block_id>blocks_abs_xx_0_0</source_block_id> + <sink_block_id>blocks_multiply_xx_0_0</sink_block_id> + <source_key>0</source_key> + <sink_key>1</sink_key> + </connection> + <connection> + <source_block_id>blocks_abs_xx_0_0</source_block_id> + <sink_block_id>blocks_multiply_xx_0_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>single_pole_iir_filter_xx_0</source_block_id> + <sink_block_id>blocks_nlog10_ff_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>single_pole_iir_filter_xx_0_0</source_block_id> + <sink_block_id>blocks_nlog10_ff_0_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>single_pole_iir_filter_xx_0_1</source_block_id> + <sink_block_id>blocks_nlog10_ff_0_1</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>single_pole_iir_filter_xx_0_2</source_block_id> + <sink_block_id>blocks_nlog10_ff_0_2</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>blocks_nlog10_ff_0</source_block_id> + <sink_block_id>qtgui_number_sink_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>blocks_nlog10_ff_0_0</source_block_id> + <sink_block_id>qtgui_number_sink_0</sink_block_id> + <source_key>0</source_key> + <sink_key>1</sink_key> + </connection> + <connection> + <source_block_id>blocks_nlog10_ff_0_1</source_block_id> + <sink_block_id>qtgui_number_sink_0</sink_block_id> + <source_key>0</source_key> + <sink_key>2</sink_key> + </connection> + <connection> + <source_block_id>blocks_nlog10_ff_0_2</source_block_id> + <sink_block_id>qtgui_number_sink_0</sink_block_id> + <source_key>0</source_key> + <sink_key>3</sink_key> + </connection> + <connection> + <source_block_id>blocks_multiply_xx_0_0</source_block_id> + <sink_block_id>single_pole_iir_filter_xx_0_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>blocks_multiply_xx_0</source_block_id> + <sink_block_id>single_pole_iir_filter_xx_0_2</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>blocks_complex_to_mag_squared_1</source_block_id> + <sink_block_id>single_pole_iir_filter_xx_0_1</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>blocks_complex_to_mag_squared_2</source_block_id> + <sink_block_id>single_pole_iir_filter_xx_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> +</flow_graph> diff --git a/gr-analog/grc/analog_pwr_squelch_xx.xml b/gr-analog/grc/analog_pwr_squelch_xx.xml index 32d9c0e947..a75f85cf10 100644 --- a/gr-analog/grc/analog_pwr_squelch_xx.xml +++ b/gr-analog/grc/analog_pwr_squelch_xx.xml @@ -34,11 +34,13 @@ <param> <name>Alpha</name> <key>alpha</key> + <value>1e-4</value> <type>real</type> </param> <param> <name>Ramp</name> <key>ramp</key> + <value>0</value> <type>int</type> </param> <param> diff --git a/gr-analog/include/gnuradio/analog/fastnoise_source_X.h.t b/gr-analog/include/gnuradio/analog/fastnoise_source_X.h.t index a6377ad7fb..850633979c 100644 --- a/gr-analog/include/gnuradio/analog/fastnoise_source_X.h.t +++ b/gr-analog/include/gnuradio/analog/fastnoise_source_X.h.t @@ -47,10 +47,15 @@ namespace gr { typedef boost::shared_ptr<@BASE_NAME@> sptr; /*! \brief Make a fast noise source - * \param type the random distribution to use (see gnuradio/analog/noise_type.h) - * \param ampl a scaling factor for the output; for Gaussian sources, this is the std. dev. - * \param seed seed for random generators. Note that for uniform and - * Gaussian distributions, this should be a negative number. + * \param type the random distribution to use (see + * gnuradio/analog/noise_type.h) + * \param ampl the standard deviation of a 1-d noise process. If + * this is the complex source, this parameter is split + * among the real and imaginary parts: + * <pre>(ampl/sqrt(2))x + j(ampl/sqrt(2))y</pre> + * \param seed seed for random generators. Note that for uniform + * and Gaussian distributions, this should be a negative + * number. * \param samples Number of samples to pre-generate */ static sptr make(noise_type_t type, float ampl, @@ -58,7 +63,17 @@ namespace gr { virtual @TYPE@ sample() = 0; virtual @TYPE@ sample_unbiased() = 0; + /*! + * Set the noise type. Nominally from the + * gr::analog::noise_type_t selections, but only GR_GAUSSIAN and + * GR_UNIFORM are currently available. + */ virtual void set_type(noise_type_t type) = 0; + + /*! + * Set the standard deviation (amplitude) of the 1-d noise + * process. + */ virtual void set_amplitude(float ampl) = 0; virtual noise_type_t type() const = 0; diff --git a/gr-analog/include/gnuradio/analog/noise_source_X.h.t b/gr-analog/include/gnuradio/analog/noise_source_X.h.t index 31e742a4ed..f619ca5146 100644 --- a/gr-analog/include/gnuradio/analog/noise_source_X.h.t +++ b/gr-analog/include/gnuradio/analog/noise_source_X.h.t @@ -47,14 +47,29 @@ namespace gr { typedef boost::shared_ptr<@BASE_NAME@> sptr; /*! Build a noise source - * \param type the random distribution to use (see gnuradio/analog/noise_type.h) - * \param ampl a scaling factor for the output; for Gaussian sources, this is the std. dev. - * \param seed seed for random generators. Note that for uniform and - * Gaussian distributions, this should be a negative number. + * \param type the random distribution to use (see + * gnuradio/analog/noise_type.h) + * \param ampl the standard deviation of a 1-d noise process. If + * this is the complex source, this parameter is split + * among the real and imaginary parts: + * <pre>(ampl/sqrt(2))x + j(ampl/sqrt(2))y</pre> + * \param seed seed for random generators. Note that for uniform + * and Gaussian distributions, this should be a negative + * number. */ static sptr make(noise_type_t type, float ampl, long seed=0); + /*! + * Set the noise type. Nominally from the + * gr::analog::noise_type_t selections, but only GR_GAUSSIAN and + * GR_UNIFORM are currently available. + */ virtual void set_type(noise_type_t type) = 0; + + /*! + * Set the standard deviation (amplitude) of the 1-d noise + * process. + */ virtual void set_amplitude(float ampl) = 0; virtual noise_type_t type() const = 0; diff --git a/gr-analog/include/gnuradio/analog/pwr_squelch_cc.h b/gr-analog/include/gnuradio/analog/pwr_squelch_cc.h index 6913d62934..324743d965 100644 --- a/gr-analog/include/gnuradio/analog/pwr_squelch_cc.h +++ b/gr-analog/include/gnuradio/analog/pwr_squelch_cc.h @@ -49,10 +49,14 @@ namespace gr { * \brief Make power-based squelch block. * * \param db threshold (in dB) for power squelch - * \param alpha Gain of averaging filter - * \param ramp sets response characteristic. + * \param alpha Gain of averaging filter. Defaults to 0.0001. + * \param ramp sets response characteristic. Defaults to 0. * \param gate if true, no output if no squelch tone. - * if false, output 0's if no squelch tone. + * if false, output 0's if no squelch tone (default). + * + * The block will emit a tag with the key pmt::intern("squelch_sob") + * with the value of pmt::PMT_NIL on the first item it passes, and with + * the key pmt::intern("squelch:eob") on the last item it passes. */ static sptr make(double db, double alpha=0.0001, int ramp=0, bool gate=false); diff --git a/gr-analog/include/gnuradio/analog/pwr_squelch_ff.h b/gr-analog/include/gnuradio/analog/pwr_squelch_ff.h index 46046eae07..a65cedaa57 100644 --- a/gr-analog/include/gnuradio/analog/pwr_squelch_ff.h +++ b/gr-analog/include/gnuradio/analog/pwr_squelch_ff.h @@ -49,10 +49,14 @@ namespace gr { * \brief Make power-based squelch block. * * \param db threshold (in dB) for power squelch - * \param alpha Gain of averaging filter - * \param ramp sets response characteristic. + * \param alpha Gain of averaging filter. Defaults to 0.0001. + * \param ramp sets response characteristic. Defaults to 0. * \param gate if true, no output if no squelch tone. - * if false, output 0's if no squelch tone. + * if false, output 0's if no squelch tone (default). + * + * The block will emit a tag with the key pmt::intern("squelch_sob") + * with the value of pmt::PMT_NIL on the first item it passes, and with + * the key pmt::intern("squelch:eob") on the last item it passes. */ static sptr make(double db, double alpha=0.0001, int ramp=0, bool gate=false); diff --git a/gr-analog/lib/fastnoise_source_X_impl.cc.t b/gr-analog/lib/fastnoise_source_X_impl.cc.t index c25230dc6a..21f963b65a 100644 --- a/gr-analog/lib/fastnoise_source_X_impl.cc.t +++ b/gr-analog/lib/fastnoise_source_X_impl.cc.t @@ -45,7 +45,11 @@ namespace gr { io_signature::make(0, 0, 0), io_signature::make(1, 1, sizeof(@TYPE@))), d_type(type), +#if @IS_COMPLEX@ // complex? + d_ampl(ampl/sqrtf(2.0f)), +#else d_ampl(ampl), +#endif d_rng(seed) { d_samples.resize(samples); @@ -68,7 +72,11 @@ namespace gr { @IMPL_NAME@::set_amplitude(float ampl) { gr::thread::scoped_lock l(d_setlock); +#if @IS_COMPLEX@ // complex? + d_ampl = ampl/sqrtf(2.0f); +#else d_ampl = ampl; +#endif generate(); } @@ -165,4 +173,3 @@ namespace gr { } /* namespace analog */ } /* namespace gr */ - diff --git a/gr-analog/lib/noise_source_X_impl.cc.t b/gr-analog/lib/noise_source_X_impl.cc.t index 960666f14d..d8c1b7eb1b 100644 --- a/gr-analog/lib/noise_source_X_impl.cc.t +++ b/gr-analog/lib/noise_source_X_impl.cc.t @@ -45,7 +45,11 @@ namespace gr { io_signature::make(0, 0, 0), io_signature::make(1, 1, sizeof(@TYPE@))), d_type(type), +#if @IS_COMPLEX@ // complex? + d_ampl(ampl/sqrtf(2.0f)), +#else d_ampl(ampl), +#endif d_rng(seed) { } @@ -65,7 +69,11 @@ namespace gr { @IMPL_NAME@::set_amplitude(float ampl) { gr::thread::scoped_lock l(d_setlock); +#if @IS_COMPLEX@ // complex? + d_ampl = ampl/sqrtf(2.0f); +#else d_ampl = ampl; +#endif } int @@ -129,4 +137,3 @@ namespace gr { } /* namespace analog */ } /* namespace gr */ - diff --git a/gr-analog/lib/squelch_base_cc_impl.cc b/gr-analog/lib/squelch_base_cc_impl.cc index 3255d3bde4..b5c153558b 100644 --- a/gr-analog/lib/squelch_base_cc_impl.cc +++ b/gr-analog/lib/squelch_base_cc_impl.cc @@ -32,8 +32,11 @@ namespace gr { squelch_base_cc_impl::squelch_base_cc_impl(const char *name, int ramp, bool gate) : block(name, - io_signature::make(1, 1, sizeof(float)), - io_signature::make(1, 1, sizeof(float))) + io_signature::make(1, 1, sizeof(float)), + io_signature::make(1, 1, sizeof(float))), + d_sob_key(pmt::intern("squelch_sob")), + d_eob_key(pmt::intern("squelch_eob")), + d_tag_next_unmuted(true) { set_ramp(ramp); set_gate(gate); @@ -92,48 +95,58 @@ namespace gr { gr::thread::scoped_lock l(d_setlock); for(int i = 0; i < noutput_items; i++) { - update_state(in[i]); - - // Adjust envelope based on current state - switch(d_state) { - case ST_MUTED: - if(!mute()) { - d_state = d_ramp ? ST_ATTACK : ST_UNMUTED; // If not ramping, go straight to unmuted - } - break; - - case ST_UNMUTED: - if(mute()) { - d_state = d_ramp ? ST_DECAY : ST_MUTED; // If not ramping, go straight to muted - } - break; - - case ST_ATTACK: - d_envelope = 0.5-std::cos(M_PI*(++d_ramped)/d_ramp)/2.0; // FIXME: precalculate window for speed - if(d_ramped >= d_ramp) { // use >= in case d_ramp is set to lower value elsewhere - d_state = ST_UNMUTED; - d_envelope = 1.0; - } - break; - - case ST_DECAY: - d_envelope = 0.5-std::cos(M_PI*(--d_ramped)/d_ramp)/2.0; // FIXME: precalculate window for speed - if(d_ramped == 0.0) { - d_state = ST_MUTED; - } - break; - }; - - // If unmuted, copy input times envelope to output - // Otherwise, if not gating, copy zero to output - if(d_state != ST_MUTED) { - out[j++] = in[i]*gr_complex(d_envelope, 0.0); - } - else { - if(!d_gate) { - out[j++] = 0.0; - } - } + update_state(in[i]); + + // Adjust envelope based on current state + switch(d_state) { + case ST_MUTED: + if(!mute()) { + d_state = d_ramp ? ST_ATTACK : ST_UNMUTED; // If not ramping, go straight to unmuted + if(d_state == ST_UNMUTED) + d_tag_next_unmuted = true; + } + break; + + case ST_UNMUTED: + if(d_tag_next_unmuted) { + d_tag_next_unmuted = false; + add_item_tag(0, nitems_written(0) + j, d_sob_key, pmt::PMT_NIL); + } + if(mute()) { + d_state = d_ramp ? ST_DECAY : ST_MUTED; // If not ramping, go straight to muted + if(d_state == ST_MUTED) + add_item_tag(0, nitems_written(0) + j, d_eob_key, pmt::PMT_NIL); + } + break; + + case ST_ATTACK: + d_envelope = 0.5-std::cos(M_PI*(++d_ramped)/d_ramp)/2.0; // FIXME: precalculate window for speed + if(d_ramped >= d_ramp) { // use >= in case d_ramp is set to lower value elsewhere + d_state = ST_UNMUTED; + d_tag_next_unmuted = true; + d_envelope = 1.0; + } + break; + + case ST_DECAY: + d_envelope = 0.5-std::cos(M_PI*(--d_ramped)/d_ramp)/2.0; // FIXME: precalculate window for speed + if(d_ramped == 0.0) { + d_state = ST_MUTED; + add_item_tag(0, nitems_written(0) + j, d_eob_key, pmt::PMT_NIL); + } + break; + }; + + // If unmuted, copy input times envelope to output + // Otherwise, if not gating, copy zero to output + if(d_state != ST_MUTED) { + out[j++] = in[i]*gr_complex(d_envelope, 0.0); + } + else { + if(!d_gate) { + out[j++] = 0.0; + } + } } consume_each(noutput_items); // Use all the inputs diff --git a/gr-analog/lib/squelch_base_cc_impl.h b/gr-analog/lib/squelch_base_cc_impl.h index 58802df91c..68ed1bb2b8 100644 --- a/gr-analog/lib/squelch_base_cc_impl.h +++ b/gr-analog/lib/squelch_base_cc_impl.h @@ -36,6 +36,8 @@ namespace gr { bool d_gate; double d_envelope; enum { ST_MUTED, ST_ATTACK, ST_UNMUTED, ST_DECAY } d_state; + const pmt::pmt_t d_sob_key, d_eob_key; + bool d_tag_next_unmuted; protected: virtual void update_state(const gr_complex &sample) {}; diff --git a/gr-analog/lib/squelch_base_ff_impl.cc b/gr-analog/lib/squelch_base_ff_impl.cc index a729fedb24..ea2d29bd97 100644 --- a/gr-analog/lib/squelch_base_ff_impl.cc +++ b/gr-analog/lib/squelch_base_ff_impl.cc @@ -26,14 +26,18 @@ #include "squelch_base_ff_impl.h" #include <gnuradio/io_signature.h> +#include <pmt/pmt.h> namespace gr { namespace analog { squelch_base_ff_impl::squelch_base_ff_impl(const char *name, int ramp, bool gate) : block(name, - io_signature::make(1, 1, sizeof(float)), - io_signature::make(1, 1, sizeof(float))) + io_signature::make(1, 1, sizeof(float)), + io_signature::make(1, 1, sizeof(float))), + d_sob_key(pmt::intern("squelch_sob")), + d_eob_key(pmt::intern("squelch_eob")), + d_tag_next_unmuted(true) { set_ramp(ramp); set_gate(gate); @@ -88,48 +92,61 @@ namespace gr { int j = 0; for(int i = 0; i < noutput_items; i++) { - update_state(in[i]); - - // Adjust envelope based on current state - switch(d_state) { - case ST_MUTED: - if(!mute()) - // If not ramping, go straight to unmuted - d_state = d_ramp ? ST_ATTACK : ST_UNMUTED; - break; - - case ST_UNMUTED: - if(mute()) - // If not ramping, go straight to muted - d_state = d_ramp ? ST_DECAY : ST_MUTED; - break; - - case ST_ATTACK: - // FIXME: precalculate window for speed - d_envelope = 0.5-std::cos(M_PI*(++d_ramped)/d_ramp)/2.0; - - // use >= in case d_ramp is set to lower value elsewhere - if(d_ramped >= d_ramp) { - d_state = ST_UNMUTED; - d_envelope = 1.0; - } - break; - - case ST_DECAY: - // FIXME: precalculate window for speed - d_envelope = 0.5-std::cos(M_PI*(--d_ramped)/d_ramp)/2.0; - if(d_ramped == 0.0) - d_state = ST_MUTED; - break; - }; - - // If unmuted, copy input times envelope to output - // Otherwise, if not gating, copy zero to output - if(d_state != ST_MUTED) - out[j++] = in[i]*d_envelope; - else - if(!d_gate) - out[j++] = 0.0; + update_state(in[i]); + + // Adjust envelope based on current state + switch(d_state) { + case ST_MUTED: + if(!mute()) { + // If not ramping, go straight to unmuted + d_state = d_ramp ? ST_ATTACK : ST_UNMUTED; + if(d_state == ST_UNMUTED) + d_tag_next_unmuted = true; + } + break; + + case ST_UNMUTED: + if(d_tag_next_unmuted) { + d_tag_next_unmuted = false; + add_item_tag(0, nitems_written(0) + j, d_sob_key, pmt::PMT_NIL); + } + if(mute()) { + // If not ramping, go straight to muted + d_state = d_ramp ? ST_DECAY : ST_MUTED; + if(d_state == ST_MUTED) + add_item_tag(0, nitems_written(0) + j, d_eob_key, pmt::PMT_NIL); + } + break; + + case ST_ATTACK: + // FIXME: precalculate window for speed + d_envelope = 0.5-std::cos(M_PI*(++d_ramped)/d_ramp)/2.0; + + // use >= in case d_ramp is set to lower value elsewhere + if(d_ramped >= d_ramp) { + d_state = ST_UNMUTED; + d_tag_next_unmuted = true; + d_envelope = 1.0; + } + break; + + case ST_DECAY: + // FIXME: precalculate window for speed + d_envelope = 0.5-std::cos(M_PI*(--d_ramped)/d_ramp)/2.0; + if(d_ramped == 0.0) { + d_state = ST_MUTED; + add_item_tag(0, nitems_written(0) + j, d_eob_key, pmt::PMT_NIL); + } + break; + }; + + // If unmuted, copy input times envelope to output + // Otherwise, if not gating, copy zero to output + if(d_state != ST_MUTED) + out[j++] = in[i]*d_envelope; + else + if(!d_gate) + out[j++] = 0.0; } consume_each(noutput_items); // Use all the inputs diff --git a/gr-analog/lib/squelch_base_ff_impl.h b/gr-analog/lib/squelch_base_ff_impl.h index 343dc5f610..b6a7efe609 100644 --- a/gr-analog/lib/squelch_base_ff_impl.h +++ b/gr-analog/lib/squelch_base_ff_impl.h @@ -24,6 +24,7 @@ #define INCLUDED_GR_SQUELCH_BASE_FF_IMPL_H #include <gnuradio/analog/squelch_base_ff.h> +#include <pmt/pmt.h> namespace gr { namespace analog { @@ -36,6 +37,8 @@ namespace gr { bool d_gate; double d_envelope; enum { ST_MUTED, ST_ATTACK, ST_UNMUTED, ST_DECAY } d_state; + const pmt::pmt_t d_sob_key, d_eob_key; + bool d_tag_next_unmuted; protected: virtual void update_state(const float &sample) {}; diff --git a/gr-audio/grc/audio_sink.xml b/gr-audio/grc/audio_sink.xml index 9a70006e72..727767b72e 100644 --- a/gr-audio/grc/audio_sink.xml +++ b/gr-audio/grc/audio_sink.xml @@ -8,7 +8,7 @@ <name>Audio Sink</name> <key>audio_sink</key> <category>Audio</category> - <throttle>1</throttle> + <flags>throttle</flags> <import>from gnuradio import audio</import> <make>audio.sink($samp_rate, $device_name, $ok_to_block)</make> <param> diff --git a/gr-audio/grc/audio_source.xml b/gr-audio/grc/audio_source.xml index 0cb73a3ae9..aaa3225e8b 100644 --- a/gr-audio/grc/audio_source.xml +++ b/gr-audio/grc/audio_source.xml @@ -8,7 +8,7 @@ <name>Audio Source</name> <key>audio_source</key> <category>Audio</category> - <throttle>1</throttle> + <flags>throttle</flags> <import>from gnuradio import audio</import> <make>audio.source($samp_rate, $device_name, $ok_to_block)</make> <param> diff --git a/gr-blocks/examples/CMakeLists.txt b/gr-blocks/examples/CMakeLists.txt index bb07cdc2b5..0ecf9d7a91 100644 --- a/gr-blocks/examples/CMakeLists.txt +++ b/gr-blocks/examples/CMakeLists.txt @@ -20,6 +20,7 @@ install( FILES matrix_multiplexer.grc + peak_detector2.grc vector_source_with_tags.grc DESTINATION ${GR_PKG_DATA_DIR}/examples/blocks COMPONENT "runtime_python" diff --git a/gr-blocks/examples/peak_detector2.grc b/gr-blocks/examples/peak_detector2.grc new file mode 100644 index 0000000000..c49febdce4 --- /dev/null +++ b/gr-blocks/examples/peak_detector2.grc @@ -0,0 +1,1045 @@ +<?xml version='1.0' encoding='ASCII'?> +<?grc format='1' created='3.7.8'?> +<flow_graph> + <timestamp>Wed Apr 8 18:17:58 2015</timestamp> + <block> + <key>options</key> + <param> + <key>id</key> + <value>test_peak2</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>title</key> + <value></value> + </param> + <param> + <key>author</key> + <value></value> + </param> + <param> + <key>description</key> + <value></value> + </param> + <param> + <key>window_size</key> + <value>1280, 1024</value> + </param> + <param> + <key>generate_options</key> + <value>qt_gui</value> + </param> + <param> + <key>category</key> + <value>Custom</value> + </param> + <param> + <key>run_options</key> + <value>run</value> + </param> + <param> + <key>run</key> + <value>True</value> + </param> + <param> + <key>max_nouts</key> + <value>0</value> + </param> + <param> + <key>realtime_scheduling</key> + <value></value> + </param> + <param> + <key>thread_safe_setters</key> + <value></value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(16, 11)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>factor</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>0.3</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(264, 11)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>alpha</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>0.001</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(440, 11)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>lookahead</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>int(samp_rate/1e3/1.1)</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(352, 11)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>samp_rate</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>100e3</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(176, 11)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>qtgui_time_sink_x</key> + <param> + <key>id</key> + <value>qtgui_time_sink_x_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>float</value> + </param> + <param> + <key>name</key> + <value>""</value> + </param> + <param> + <key>ylabel</key> + <value>Amplitude</value> + </param> + <param> + <key>yunit</key> + <value>""</value> + </param> + <param> + <key>size</key> + <value>512</value> + </param> + <param> + <key>srate</key> + <value>samp_rate</value> + </param> + <param> + <key>grid</key> + <value>True</value> + </param> + <param> + <key>autoscale</key> + <value>False</value> + </param> + <param> + <key>ymin</key> + <value>-1.5</value> + </param> + <param> + <key>ymax</key> + <value>1.5</value> + </param> + <param> + <key>nconnections</key> + <value>3</value> + </param> + <param> + <key>update_time</key> + <value>0.10</value> + </param> + <param> + <key>entags</key> + <value>True</value> + </param> + <param> + <key>gui_hint</key> + <value></value> + </param> + <param> + <key>tr_mode</key> + <value>qtgui.TRIG_MODE_AUTO</value> + </param> + <param> + <key>tr_slope</key> + <value>qtgui.TRIG_SLOPE_POS</value> + </param> + <param> + <key>tr_level</key> + <value>0.0</value> + </param> + <param> + <key>tr_delay</key> + <value>0</value> + </param> + <param> + <key>tr_chan</key> + <value>0</value> + </param> + <param> + <key>tr_tag</key> + <value>""</value> + </param> + <param> + <key>ctrlpanel</key> + <value>True</value> + </param> + <param> + <key>legend</key> + <value>True</value> + </param> + <param> + <key>label1</key> + <value>Input</value> + </param> + <param> + <key>width1</key> + <value>1</value> + </param> + <param> + <key>color1</key> + <value>"blue"</value> + </param> + <param> + <key>style1</key> + <value>1</value> + </param> + <param> + <key>marker1</key> + <value>-1</value> + </param> + <param> + <key>alpha1</key> + <value>1.0</value> + </param> + <param> + <key>label2</key> + <value>Peaks</value> + </param> + <param> + <key>width2</key> + <value>1</value> + </param> + <param> + <key>color2</key> + <value>"red"</value> + </param> + <param> + <key>style2</key> + <value>1</value> + </param> + <param> + <key>marker2</key> + <value>-1</value> + </param> + <param> + <key>alpha2</key> + <value>1.0</value> + </param> + <param> + <key>label3</key> + <value>Average</value> + </param> + <param> + <key>width3</key> + <value>1</value> + </param> + <param> + <key>color3</key> + <value>"green"</value> + </param> + <param> + <key>style3</key> + <value>1</value> + </param> + <param> + <key>marker3</key> + <value>-1</value> + </param> + <param> + <key>alpha3</key> + <value>1.0</value> + </param> + <param> + <key>label4</key> + <value></value> + </param> + <param> + <key>width4</key> + <value>1</value> + </param> + <param> + <key>color4</key> + <value>"black"</value> + </param> + <param> + <key>style4</key> + <value>1</value> + </param> + <param> + <key>marker4</key> + <value>-1</value> + </param> + <param> + <key>alpha4</key> + <value>1.0</value> + </param> + <param> + <key>label5</key> + <value></value> + </param> + <param> + <key>width5</key> + <value>1</value> + </param> + <param> + <key>color5</key> + <value>"cyan"</value> + </param> + <param> + <key>style5</key> + <value>1</value> + </param> + <param> + <key>marker5</key> + <value>-1</value> + </param> + <param> + <key>alpha5</key> + <value>1.0</value> + </param> + <param> + <key>label6</key> + <value></value> + </param> + <param> + <key>width6</key> + <value>1</value> + </param> + <param> + <key>color6</key> + <value>"magenta"</value> + </param> + <param> + <key>style6</key> + <value>1</value> + </param> + <param> + <key>marker6</key> + <value>-1</value> + </param> + <param> + <key>alpha6</key> + <value>1.0</value> + </param> + <param> + <key>label7</key> + <value></value> + </param> + <param> + <key>width7</key> + <value>1</value> + </param> + <param> + <key>color7</key> + <value>"yellow"</value> + </param> + <param> + <key>style7</key> + <value>1</value> + </param> + <param> + <key>marker7</key> + <value>-1</value> + </param> + <param> + <key>alpha7</key> + <value>1.0</value> + </param> + <param> + <key>label8</key> + <value></value> + </param> + <param> + <key>width8</key> + <value>1</value> + </param> + <param> + <key>color8</key> + <value>"dark red"</value> + </param> + <param> + <key>style8</key> + <value>1</value> + </param> + <param> + <key>marker8</key> + <value>-1</value> + </param> + <param> + <key>alpha8</key> + <value>1.0</value> + </param> + <param> + <key>label9</key> + <value></value> + </param> + <param> + <key>width9</key> + <value>1</value> + </param> + <param> + <key>color9</key> + <value>"dark green"</value> + </param> + <param> + <key>style9</key> + <value>1</value> + </param> + <param> + <key>marker9</key> + <value>-1</value> + </param> + <param> + <key>alpha9</key> + <value>1.0</value> + </param> + <param> + <key>label10</key> + <value></value> + </param> + <param> + <key>width10</key> + <value>1</value> + </param> + <param> + <key>color10</key> + <value>"blue"</value> + </param> + <param> + <key>style10</key> + <value>1</value> + </param> + <param> + <key>marker10</key> + <value>-1</value> + </param> + <param> + <key>alpha10</key> + <value>1.0</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(808, 152)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_char_to_float</key> + <param> + <key>id</key> + <value>blocks_char_to_float_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>scale</key> + <value>1</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(624, 83)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_peak_detector2_fb</key> + <param> + <key>id</key> + <value>blocks_peak_detector2_fb_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>threshold_factor_rise</key> + <value>factor</value> + </param> + <param> + <key>look_ahead</key> + <value>lookahead</value> + </param> + <param> + <key>alpha</key> + <value>alpha</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(408, 83)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_file_sink</key> + <param> + <key>id</key> + <value>blocks_file_sink_0_1</value> + </param> + <param> + <key>_enabled</key> + <value>False</value> + </param> + <param> + <key>file</key> + <value>flag.data</value> + </param> + <param> + <key>type</key> + <value>float</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>unbuffered</key> + <value>False</value> + </param> + <param> + <key>append</key> + <value>False</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(808, 51)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_file_sink</key> + <param> + <key>id</key> + <value>blocks_file_sink_0_0</value> + </param> + <param> + <key>_enabled</key> + <value>False</value> + </param> + <param> + <key>file</key> + <value>avg.data</value> + </param> + <param> + <key>type</key> + <value>float</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>unbuffered</key> + <value>False</value> + </param> + <param> + <key>append</key> + <value>False</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(784, 259)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_file_sink</key> + <param> + <key>id</key> + <value>blocks_file_sink_0</value> + </param> + <param> + <key>_enabled</key> + <value>False</value> + </param> + <param> + <key>file</key> + <value>in.data</value> + </param> + <param> + <key>type</key> + <value>float</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>unbuffered</key> + <value>False</value> + </param> + <param> + <key>append</key> + <value>False</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(408, 187)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable_qtgui_range</key> + <param> + <key>id</key> + <value>offset</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>label</key> + <value></value> + </param> + <param> + <key>value</key> + <value>0.1</value> + </param> + <param> + <key>start</key> + <value>-1.5</value> + </param> + <param> + <key>stop</key> + <value>1.5</value> + </param> + <param> + <key>step</key> + <value>0.1</value> + </param> + <param> + <key>widget</key> + <value>counter_slider</value> + </param> + <param> + <key>orient</key> + <value>Qt.Horizontal</value> + </param> + <param> + <key>min_len</key> + <value>200</value> + </param> + <param> + <key>gui_hint</key> + <value></value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(16, 235)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>analog_sig_source_x</key> + <param> + <key>id</key> + <value>analog_sig_source_x_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>float</value> + </param> + <param> + <key>samp_rate</key> + <value>samp_rate</value> + </param> + <param> + <key>waveform</key> + <value>analog.GR_SAW_WAVE</value> + </param> + <param> + <key>freq</key> + <value>1000</value> + </param> + <param> + <key>amp</key> + <value>1</value> + </param> + <param> + <key>offset</key> + <value>offset</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(16, 115)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_throttle</key> + <param> + <key>id</key> + <value>blocks_throttle_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>float</value> + </param> + <param> + <key>samples_per_second</key> + <value>samp_rate</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>ignoretag</key> + <value>True</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(224, 147)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <connection> + <source_block_id>blocks_char_to_float_0</source_block_id> + <sink_block_id>blocks_file_sink_0_1</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>blocks_peak_detector2_fb_0</source_block_id> + <sink_block_id>blocks_file_sink_0_0</sink_block_id> + <source_key>1</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>blocks_throttle_0</source_block_id> + <sink_block_id>qtgui_time_sink_x_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>blocks_char_to_float_0</source_block_id> + <sink_block_id>qtgui_time_sink_x_0</sink_block_id> + <source_key>0</source_key> + <sink_key>1</sink_key> + </connection> + <connection> + <source_block_id>blocks_peak_detector2_fb_0</source_block_id> + <sink_block_id>qtgui_time_sink_x_0</sink_block_id> + <source_key>1</source_key> + <sink_key>2</sink_key> + </connection> + <connection> + <source_block_id>blocks_throttle_0</source_block_id> + <sink_block_id>blocks_peak_detector2_fb_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>blocks_peak_detector2_fb_0</source_block_id> + <sink_block_id>blocks_char_to_float_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>blocks_throttle_0</source_block_id> + <sink_block_id>blocks_file_sink_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>analog_sig_source_x_0</source_block_id> + <sink_block_id>blocks_throttle_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> +</flow_graph> diff --git a/gr-blocks/grc/blocks_block_tree.xml b/gr-blocks/grc/blocks_block_tree.xml index cc7b4b8c6f..fb4e10d1ba 100644 --- a/gr-blocks/grc/blocks_block_tree.xml +++ b/gr-blocks/grc/blocks_block_tree.xml @@ -51,6 +51,8 @@ </cat> <cat> <name>Control Port</name> + <block>blocks_ctrlport_monitor</block> + <block>blocks_ctrlport_monitor_performance</block> <block>blocks_ctrlport_probe2_x</block> <block>blocks_ctrlport_probe2_c</block> <block>blocks_ctrlport_probe_c</block> diff --git a/gr-blocks/grc/blocks_ctrlport_performance.xml b/gr-blocks/grc/blocks_ctrlport_performance.xml new file mode 100644 index 0000000000..ab17c9e263 --- /dev/null +++ b/gr-blocks/grc/blocks_ctrlport_performance.xml @@ -0,0 +1,48 @@ +<?xml version="1.0"?> + +<!-- + Copyright 2012 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. +--> + +<block> + <name>CtrlPort Performance Monitor</name> + <key>blocks_ctrlport_monitor_performance</key> + <import>from gnuradio.ctrlport.monitor import *</import> + <make>not $en or monitor("gr-perf-monitorx")</make> + <param> + <name>Enabled</name> + <key>en</key> + <value></value> + <type>enum</type> + <option> + <name>True</name> + <key>True</key> + </option> + <option> + <name>False</name> + <key>False</key> + </option> + </param> + + <doc> + Place this in a graph to launch a QtPy GR CtrlPort Performance Monitor app. + </doc> + +</block> diff --git a/gr-blocks/grc/blocks_ctrlport_viewer.xml b/gr-blocks/grc/blocks_ctrlport_viewer.xml new file mode 100644 index 0000000000..1d5a2e5931 --- /dev/null +++ b/gr-blocks/grc/blocks_ctrlport_viewer.xml @@ -0,0 +1,48 @@ +<?xml version="1.0"?> + +<!-- + Copyright 2012 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. +--> + +<block> + <name>CtrlPort Monitor</name> + <key>blocks_ctrlport_monitor</key> + <import>from gnuradio.ctrlport.monitor import *</import> + <make>not $en or monitor()</make> + <param> + <name>Enabled</name> + <key>en</key> + <value></value> + <type>enum</type> + <option> + <name>True</name> + <key>True</key> + </option> + <option> + <name>False</name> + <key>False</key> + </option> + </param> + + <doc> + Place this in a graph to launch a QtPy GR CtrlPort Monitor app. + </doc> + +</block> diff --git a/gr-blocks/grc/blocks_peak_detector2_fb.xml b/gr-blocks/grc/blocks_peak_detector2_fb.xml index 584e7a1fb3..0b25e01680 100644 --- a/gr-blocks/grc/blocks_peak_detector2_fb.xml +++ b/gr-blocks/grc/blocks_peak_detector2_fb.xml @@ -38,4 +38,9 @@ <name>out</name> <type>byte</type> </source> + <source> + <name>debug</name> + <type>float</type> + <optional>1</optional> + </source> </block> diff --git a/gr-blocks/grc/blocks_throttle.xml b/gr-blocks/grc/blocks_throttle.xml index 790e195750..26f4aa768b 100644 --- a/gr-blocks/grc/blocks_throttle.xml +++ b/gr-blocks/grc/blocks_throttle.xml @@ -7,7 +7,7 @@ <block> <name>Throttle</name> <key>blocks_throttle</key> - <throttle>1</throttle> + <flags>throttle</flags> <import>from gnuradio import blocks</import> <make>blocks.throttle($type.size*$vlen, $samples_per_second,$ignoretag)</make> <callback>set_sample_rate($samples_per_second)</callback> diff --git a/gr-blocks/grc/blocks_udp_source.xml b/gr-blocks/grc/blocks_udp_source.xml index 3b434c107e..03dbb5781b 100644 --- a/gr-blocks/grc/blocks_udp_source.xml +++ b/gr-blocks/grc/blocks_udp_source.xml @@ -7,7 +7,7 @@ <block> <name>UDP Source</name> <key>blocks_udp_source</key> - <throttle>1</throttle> + <flags>throttle</flags> <import>from gnuradio import blocks</import> <make>blocks.udp_source($type.size*$vlen, $ipaddr, $port, $psize, $eof)</make> <callback>set_mtu($mtu)</callback> diff --git a/gr-blocks/include/gnuradio/blocks/peak_detector2_fb.h b/gr-blocks/include/gnuradio/blocks/peak_detector2_fb.h index da2d9fc740..541dd8aa09 100644 --- a/gr-blocks/include/gnuradio/blocks/peak_detector2_fb.h +++ b/gr-blocks/include/gnuradio/blocks/peak_detector2_fb.h @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2007,2013 Free Software Foundation, Inc. + * Copyright 2007,2013,2015 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -36,7 +36,7 @@ namespace gr { * \details * If a peak is detected, this block outputs a 1, or it outputs * 0's. A separate debug output may be connected, to view the - * internal EWMA described below. + * internal estimated mean described below. */ class BLOCKS_API peak_detector2_fb : virtual public sync_block { @@ -47,13 +47,21 @@ namespace gr { /*! * Build a peak detector block with float in, byte out. * - * \param threshold_factor_rise The threshold factor determins - * when a peak is present. An EWMA average of the signal is - * calculated and when the value of the signal goes over - * threshold_factor_rise*average, we call the peak. + * \param threshold_factor_rise The threshold factor determines + * when a peak is present. An average of the input signal + * is calculated (through a single-pole autoregressive + * filter) and when the value of the input signal goes + * over threshold_factor_rise*average, we assume we are + * in the neighborhood of a peak. The block will then + * find the position of the maximum within a window of + * look_ahead samples starting at the point where the + * threshold was crossed upwards. * \param look_ahead The look-ahead value is used when the - * threshold is found to locate the peak within this range. - * \param alpha The gain value of a single-pole moving average filter. + * threshold is crossed upwards to locate the peak within + * this range. + * \param alpha One minus the pole of a single-pole + * autoregressive filter that evaluates the average of + * the input signal. */ static sptr make(float threshold_factor_rise=7, int look_ahead=1000, float alpha=0.001); diff --git a/gr-blocks/lib/CMakeLists.txt b/gr-blocks/lib/CMakeLists.txt index cd164f219e..0f5d9fa2b6 100644 --- a/gr-blocks/lib/CMakeLists.txt +++ b/gr-blocks/lib/CMakeLists.txt @@ -251,18 +251,20 @@ GR_LIBRARY_FOO(gnuradio-blocks RUNTIME_COMPONENT "blocks_runtime" DEVEL_COMPONEN if(ENABLE_STATIC_LIBS) # Remove controlport-specific source files from staticlibs build if(ENABLE_GR_CTRLPORT) - list(REMOVE_ITEM gr_blocks_sources - ${blocks_ctrlport_sources} - ) + if(ICE_FOUND) + list(REMOVE_ITEM gr_blocks_sources + ${blocks_ctrlport_sources} + ) - # Remove GR_CTRLPORT set this target's definitions. - # Makes sure we don't try to use ControlPort stuff in source files - GET_DIRECTORY_PROPERTY(STATIC_DEFS COMPILE_DEFINITIONS) - list(REMOVE_ITEM STATIC_DEFS "GR_CTRLPORT") - SET_PROPERTY(DIRECTORY PROPERTY COMPILE_DEFINITIONS "${STATIC_DEFS}") + # Remove GR_CTRLPORT set this target's definitions. + # Makes sure we don't try to use ControlPort stuff in source files + GET_DIRECTORY_PROPERTY(STATIC_DEFS COMPILE_DEFINITIONS) + list(REMOVE_ITEM STATIC_DEFS "GR_CTRLPORT") + SET_PROPERTY(DIRECTORY PROPERTY COMPILE_DEFINITIONS "${STATIC_DEFS}") - # readd it to the target since we removed it from the directory-wide list. - SET_PROPERTY(TARGET gnuradio-blocks APPEND PROPERTY COMPILE_DEFINITIONS "GR_CTRLPORT") + # readd it to the target since we removed it from the directory-wide list. + SET_PROPERTY(TARGET gnuradio-blocks APPEND PROPERTY COMPILE_DEFINITIONS "GR_CTRLPORT") + endif(ICE_FOUND) endif(ENABLE_GR_CTRLPORT) add_library(gnuradio-blocks_static STATIC ${gr_blocks_sources}) diff --git a/gr-blocks/lib/ctrlport_probe2_b_impl.cc b/gr-blocks/lib/ctrlport_probe2_b_impl.cc index e6e2570ea6..996e997d96 100644 --- a/gr-blocks/lib/ctrlport_probe2_b_impl.cc +++ b/gr-blocks/lib/ctrlport_probe2_b_impl.cc @@ -63,39 +63,27 @@ namespace gr { ninput_items_required[i] = d_len; } - // boost::shared_mutex mutex_buffer; - // mutable boost::mutex mutex_notify; - // boost::condition_variable condition_buffer_ready; std::vector<signed char> ctrlport_probe2_b_impl::get() { - mutex_buffer.lock(); - d_buffer.clear(); - mutex_buffer.unlock(); - - // wait for condition - boost::mutex::scoped_lock lock(mutex_notify); - condition_buffer_ready.wait(lock); - - mutex_buffer.lock(); - std::vector<signed char> buf_copy = d_buffer; - assert(buf_copy.size() == d_len); - mutex_buffer.unlock(); - - return buf_copy; + return buffered_get.get(); } void ctrlport_probe2_b_impl::set_length(int len) { + gr::thread::scoped_lock guard(d_setlock); + if(len > 8191) { - std::cerr << "probe2_b: length " << len - << " exceeds maximum buffer size of 8191" << std::endl; + GR_LOG_WARN(d_logger, + boost::format("probe2_b: length %1% exceeds maximum" + " buffer size of 8191") % len); len = 8191; } d_len = len; - d_buffer.reserve(d_len); + d_buffer.resize(d_len); + d_index = 0; } int @@ -111,23 +99,22 @@ namespace gr { { const char *in = (const char*)input_items[0]; + gr::thread::scoped_lock guard(d_setlock); + // copy samples to get buffer if we need samples - mutex_buffer.lock(); - if(d_buffer.size() < d_len) { + if(d_index < d_len) { // copy smaller of remaining buffer space and num inputs to work() - int num_copy = std::min( (int)(d_len - d_buffer.size()), noutput_items ); + int num_copy = std::min( (int)(d_len - d_index), noutput_items ); - // TODO: convert this to a copy operator for speed... - for(int i = 0; i < num_copy; i++) { - d_buffer.push_back(in[i]); - } + memcpy(&d_buffer[d_index], in, num_copy*sizeof(char)); + d_index += num_copy; + } - // notify the waiting get() if we fill up the buffer - if(d_buffer.size() == d_len) { - condition_buffer_ready.notify_one(); - } + // notify the waiting get() if we fill up the buffer + if(d_index == d_len) { + buffered_get.offer_data(d_buffer); + d_index = 0; } - mutex_buffer.unlock(); return noutput_items; } diff --git a/gr-blocks/lib/ctrlport_probe2_b_impl.h b/gr-blocks/lib/ctrlport_probe2_b_impl.h index 155dd4c23c..165f0d33db 100644 --- a/gr-blocks/lib/ctrlport_probe2_b_impl.h +++ b/gr-blocks/lib/ctrlport_probe2_b_impl.h @@ -25,7 +25,7 @@ #include <gnuradio/blocks/ctrlport_probe2_b.h> #include <gnuradio/rpcregisterhelpers.h> -#include <boost/thread/shared_mutex.hpp> +#include <gnuradio/rpcbufferedget.h> namespace gr { namespace blocks { @@ -37,11 +37,10 @@ namespace gr { std::string d_desc; size_t d_len; unsigned int d_disp_mask; - boost::shared_mutex mutex_buffer; - mutable boost::mutex mutex_notify; - boost::condition_variable condition_buffer_ready; + size_t d_index; std::vector<signed char> d_buffer; + rpcbufferedget< std::vector<signed char> > buffered_get; public: ctrlport_probe2_b_impl(const std::string &id, const std::string &desc, @@ -66,4 +65,3 @@ namespace gr { } /* namespace gr */ #endif /* INCLUDED_CTRLPORT_PROBE2_C_IMPL_H */ - diff --git a/gr-blocks/lib/ctrlport_probe2_c_impl.cc b/gr-blocks/lib/ctrlport_probe2_c_impl.cc index aa038c0765..b8ed0af444 100644 --- a/gr-blocks/lib/ctrlport_probe2_c_impl.cc +++ b/gr-blocks/lib/ctrlport_probe2_c_impl.cc @@ -64,39 +64,27 @@ namespace gr { ninput_items_required[i] = d_len; } - // boost::shared_mutex mutex_buffer; - // mutable boost::mutex mutex_notify; - // boost::condition_variable condition_buffer_ready; std::vector<gr_complex> ctrlport_probe2_c_impl::get() { - mutex_buffer.lock(); - d_buffer.clear(); - mutex_buffer.unlock(); - - // wait for condition - boost::mutex::scoped_lock lock(mutex_notify); - condition_buffer_ready.wait(lock); - - mutex_buffer.lock(); - std::vector<gr_complex> buf_copy = d_buffer; - assert(buf_copy.size() == d_len); - mutex_buffer.unlock(); - - return buf_copy; + return buffered_get.get(); } void ctrlport_probe2_c_impl::set_length(int len) { + gr::thread::scoped_lock guard(d_setlock); + if(len > 8191) { - std::cerr << "probe2_c: length " << len - << " exceeds maximum buffer size of 8191" << std::endl; + GR_LOG_WARN(d_logger, + boost::format("probe2_c: length %1% exceeds maximum" + " buffer size of 8191") % len); len = 8191; } d_len = len; - d_buffer.reserve(d_len); + d_buffer.resize(d_len); + d_index = 0; } int @@ -112,23 +100,22 @@ namespace gr { { const gr_complex *in = (const gr_complex*)input_items[0]; + gr::thread::scoped_lock guard(d_setlock); + // copy samples to get buffer if we need samples - mutex_buffer.lock(); - if(d_buffer.size() < d_len) { + if(d_index < d_len) { // copy smaller of remaining buffer space and num inputs to work() - int num_copy = std::min( (int)(d_len - d_buffer.size()), noutput_items ); + int num_copy = std::min( (int)(d_len - d_index), noutput_items ); - // TODO: convert this to a copy operator for speed... - for(int i = 0; i < num_copy; i++) { - d_buffer.push_back(in[i]); - } + memcpy(&d_buffer[d_index], in, num_copy*sizeof(gr_complex)); + d_index += num_copy; + } - // notify the waiting get() if we fill up the buffer - if(d_buffer.size() == d_len) { - condition_buffer_ready.notify_one(); - } + // notify the waiting get() if we fill up the buffer + if(d_index == d_len) { + buffered_get.offer_data(d_buffer); + d_index = 0; } - mutex_buffer.unlock(); return noutput_items; } diff --git a/gr-blocks/lib/ctrlport_probe2_c_impl.h b/gr-blocks/lib/ctrlport_probe2_c_impl.h index 15ff0f4ea2..119738a481 100644 --- a/gr-blocks/lib/ctrlport_probe2_c_impl.h +++ b/gr-blocks/lib/ctrlport_probe2_c_impl.h @@ -25,7 +25,7 @@ #include <gnuradio/blocks/ctrlport_probe2_c.h> #include <gnuradio/rpcregisterhelpers.h> -#include <boost/thread/shared_mutex.hpp> +#include <gnuradio/rpcbufferedget.h> namespace gr { namespace blocks { @@ -37,11 +37,10 @@ namespace gr { std::string d_desc; size_t d_len; unsigned int d_disp_mask; - boost::shared_mutex mutex_buffer; - mutable boost::mutex mutex_notify; - boost::condition_variable condition_buffer_ready; + size_t d_index; std::vector<gr_complex> d_buffer; + rpcbufferedget< std::vector<gr_complex> > buffered_get; public: ctrlport_probe2_c_impl(const std::string &id, const std::string &desc, @@ -66,4 +65,3 @@ namespace gr { } /* namespace gr */ #endif /* INCLUDED_CTRLPORT_PROBE2_C_IMPL_H */ - diff --git a/gr-blocks/lib/ctrlport_probe2_f_impl.cc b/gr-blocks/lib/ctrlport_probe2_f_impl.cc index b53b2dc3cb..ff37401e88 100644 --- a/gr-blocks/lib/ctrlport_probe2_f_impl.cc +++ b/gr-blocks/lib/ctrlport_probe2_f_impl.cc @@ -62,39 +62,27 @@ namespace gr { ninput_items_required[i] = d_len; } - // boost::shared_mutex mutex_buffer; - // mutable boost::mutex mutex_notify; - // boost::condition_variable condition_buffer_ready; std::vector<float> ctrlport_probe2_f_impl::get() { - mutex_buffer.lock(); - d_buffer.clear(); - mutex_buffer.unlock(); - - // wait for condition - boost::mutex::scoped_lock lock(mutex_notify); - condition_buffer_ready.wait(lock); - - mutex_buffer.lock(); - std::vector<float> buf_copy = d_buffer; - assert(buf_copy.size() == d_len); - mutex_buffer.unlock(); - - return buf_copy; + return buffered_get.get(); } void ctrlport_probe2_f_impl::set_length(int len) { + gr::thread::scoped_lock guard(d_setlock); + if(len > 8191) { - std::cerr << "probe2_f: length " << len - << " exceeds maximum buffer size of 8191" << std::endl; + GR_LOG_WARN(d_logger, + boost::format("probe2_f: length %1% exceeds maximum" + " buffer size of 8191") % len); len = 8191; } d_len = len; - d_buffer.reserve(d_len); + d_buffer.resize(d_len); + d_index = 0; } int @@ -110,23 +98,22 @@ namespace gr { { const float *in = (const float*)input_items[0]; + gr::thread::scoped_lock guard(d_setlock); + // copy samples to get buffer if we need samples - mutex_buffer.lock(); - if(d_buffer.size() < d_len) { + if(d_index < d_len) { // copy smaller of remaining buffer space and num inputs to work() - int num_copy = std::min( (int)(d_len - d_buffer.size()), noutput_items ); + int num_copy = std::min( (int)(d_len - d_index), noutput_items ); - // TODO: convert this to a copy operator for speed... - for(int i = 0; i < num_copy; i++) { - d_buffer.push_back(in[i]); - } + memcpy(&d_buffer[d_index], in, num_copy*sizeof(float)); + d_index += num_copy; + } - // notify the waiting get() if we fill up the buffer - if(d_buffer.size() == d_len) { - condition_buffer_ready.notify_one(); - } + // notify the waiting get() if we fill up the buffer + if(d_index == d_len) { + buffered_get.offer_data(d_buffer); + d_index = 0; } - mutex_buffer.unlock(); return noutput_items; } diff --git a/gr-blocks/lib/ctrlport_probe2_f_impl.h b/gr-blocks/lib/ctrlport_probe2_f_impl.h index a4aa099237..6aec0789f4 100644 --- a/gr-blocks/lib/ctrlport_probe2_f_impl.h +++ b/gr-blocks/lib/ctrlport_probe2_f_impl.h @@ -25,7 +25,7 @@ #include <gnuradio/blocks/ctrlport_probe2_f.h> #include <gnuradio/rpcregisterhelpers.h> -#include <boost/thread/shared_mutex.hpp> +#include <gnuradio/rpcbufferedget.h> namespace gr { namespace blocks { @@ -37,11 +37,10 @@ namespace gr { std::string d_desc; size_t d_len; unsigned int d_disp_mask; - boost::shared_mutex mutex_buffer; - mutable boost::mutex mutex_notify; - boost::condition_variable condition_buffer_ready; + size_t d_index; std::vector<float> d_buffer; + rpcbufferedget< std::vector<float> > buffered_get; public: ctrlport_probe2_f_impl(const std::string &id, const std::string &desc, @@ -66,4 +65,3 @@ namespace gr { } /* namespace gr */ #endif /* INCLUDED_CTRLPORT_PROBE2_F_IMPL_H */ - diff --git a/gr-blocks/lib/ctrlport_probe2_i_impl.cc b/gr-blocks/lib/ctrlport_probe2_i_impl.cc index 77dca2ad0d..7e17d8e8fe 100644 --- a/gr-blocks/lib/ctrlport_probe2_i_impl.cc +++ b/gr-blocks/lib/ctrlport_probe2_i_impl.cc @@ -64,39 +64,27 @@ namespace gr { ninput_items_required[i] = d_len; } - // boost::shared_mutex mutex_buffer; - // mutable boost::mutex mutex_notify; - // boost::condition_variable condition_buffer_ready; std::vector<int> ctrlport_probe2_i_impl::get() { - mutex_buffer.lock(); - d_buffer.clear(); - mutex_buffer.unlock(); - - // wait for condition - boost::mutex::scoped_lock lock(mutex_notify); - condition_buffer_ready.wait(lock); - - mutex_buffer.lock(); - std::vector<int> buf_copy = d_buffer; - assert(buf_copy.size() == d_len); - mutex_buffer.unlock(); - - return buf_copy; + return buffered_get.get(); } void ctrlport_probe2_i_impl::set_length(int len) { + gr::thread::scoped_lock guard(d_setlock); + if(len > 8191) { - std::cerr << "probe2_i: length " << len - << " exceeds maximum buffer size of 8191" << std::endl; + GR_LOG_WARN(d_logger, + boost::format("probe2_i: length %1% exceeds maximum" + " buffer size of 8191") % len); len = 8191; } d_len = len; - d_buffer.reserve(d_len); + d_buffer.resize(d_len); + d_index = 0; } int @@ -112,23 +100,22 @@ namespace gr { { const int *in = (const int*)input_items[0]; + gr::thread::scoped_lock guard(d_setlock); + // copy samples to get buffer if we need samples - mutex_buffer.lock(); - if(d_buffer.size() < d_len) { + if(d_index < d_len) { // copy smaller of remaining buffer space and num inputs to work() - int num_copy = std::min( (int)(d_len - d_buffer.size()), noutput_items ); + int num_copy = std::min( (int)(d_len - d_index), noutput_items ); - // TODO: convert this to a copy operator for speed... - for(int i = 0; i < num_copy; i++) { - d_buffer.push_back(in[i]); - } + memcpy(&d_buffer[d_index], in, num_copy*sizeof(int)); + d_index += num_copy; + } - // notify the waiting get() if we fill up the buffer - if(d_buffer.size() == d_len) { - condition_buffer_ready.notify_one(); - } + // notify the waiting get() if we fill up the buffer + if(d_index == d_len) { + buffered_get.offer_data(d_buffer); + d_index = 0; } - mutex_buffer.unlock(); return noutput_items; } diff --git a/gr-blocks/lib/ctrlport_probe2_i_impl.h b/gr-blocks/lib/ctrlport_probe2_i_impl.h index 06493ac23a..2832af07ec 100644 --- a/gr-blocks/lib/ctrlport_probe2_i_impl.h +++ b/gr-blocks/lib/ctrlport_probe2_i_impl.h @@ -25,7 +25,7 @@ #include <gnuradio/blocks/ctrlport_probe2_i.h> #include <gnuradio/rpcregisterhelpers.h> -#include <boost/thread/shared_mutex.hpp> +#include <gnuradio/rpcbufferedget.h> namespace gr { namespace blocks { @@ -37,11 +37,10 @@ namespace gr { std::string d_desc; size_t d_len; unsigned int d_disp_mask; - boost::shared_mutex mutex_buffer; - mutable boost::mutex mutex_notify; - boost::condition_variable condition_buffer_ready; + size_t d_index; std::vector<int> d_buffer; + rpcbufferedget< std::vector<int> > buffered_get; public: ctrlport_probe2_i_impl(const std::string &id, const std::string &desc, @@ -66,4 +65,3 @@ namespace gr { } /* namespace gr */ #endif /* INCLUDED_CTRLPORT_PROBE2_I_IMPL_H */ - diff --git a/gr-blocks/lib/ctrlport_probe2_s_impl.cc b/gr-blocks/lib/ctrlport_probe2_s_impl.cc index 6a4ade462c..9924243db0 100644 --- a/gr-blocks/lib/ctrlport_probe2_s_impl.cc +++ b/gr-blocks/lib/ctrlport_probe2_s_impl.cc @@ -64,39 +64,27 @@ namespace gr { ninput_items_required[i] = d_len; } - // boost::shared_mutex mutex_buffer; - // mutable boost::mutex mutex_notify; - // boost::condition_variable condition_buffer_ready; std::vector<short> ctrlport_probe2_s_impl::get() { - mutex_buffer.lock(); - d_buffer.clear(); - mutex_buffer.unlock(); - - // wait for condition - boost::mutex::scoped_lock lock(mutex_notify); - condition_buffer_ready.wait(lock); - - mutex_buffer.lock(); - std::vector<short> buf_copy = d_buffer; - assert(buf_copy.size() == d_len); - mutex_buffer.unlock(); - - return buf_copy; + return buffered_get.get(); } void ctrlport_probe2_s_impl::set_length(int len) { + gr::thread::scoped_lock guard(d_setlock); + if(len > 8191) { - std::cerr << "probe2_s: length " << len - << " exceeds maximum buffer size of 8191" << std::endl; + GR_LOG_WARN(d_logger, + boost::format("probe2_s: length %1% exceeds maximum" + " buffer size of 8191") % len); len = 8191; } d_len = len; - d_buffer.reserve(d_len); + d_buffer.resize(d_len); + d_index = 0; } int @@ -112,23 +100,21 @@ namespace gr { { const short *in = (const short*)input_items[0]; + gr::thread::scoped_lock guard(d_setlock); + // copy samples to get buffer if we need samples - mutex_buffer.lock(); - if(d_buffer.size() < d_len) { + if(d_index < d_len) { // copy smaller of remaining buffer space and num inputs to work() - int num_copy = std::min( (int)(d_len - d_buffer.size()), noutput_items ); + int num_copy = std::min( (int)(d_len - d_index), noutput_items ); - // TODO: convert this to a copy operator for speed... - for(int i = 0; i < num_copy; i++) { - d_buffer.push_back(in[i]); - } + memcpy(&d_buffer[d_index], in, num_copy*sizeof(short)); + d_index += num_copy; + } - // notify the waiting get() if we fill up the buffer - if(d_buffer.size() == d_len) { - condition_buffer_ready.notify_one(); - } + // notify the waiting get() if we fill up the buffer + if(d_index == d_len) { + buffered_get.offer_data(d_buffer); } - mutex_buffer.unlock(); return noutput_items; } diff --git a/gr-blocks/lib/ctrlport_probe2_s_impl.h b/gr-blocks/lib/ctrlport_probe2_s_impl.h index 078dd56b73..a608a7898c 100644 --- a/gr-blocks/lib/ctrlport_probe2_s_impl.h +++ b/gr-blocks/lib/ctrlport_probe2_s_impl.h @@ -25,7 +25,7 @@ #include <gnuradio/blocks/ctrlport_probe2_s.h> #include <gnuradio/rpcregisterhelpers.h> -#include <boost/thread/shared_mutex.hpp> +#include <gnuradio/rpcbufferedget.h> namespace gr { namespace blocks { @@ -37,11 +37,10 @@ namespace gr { std::string d_desc; size_t d_len; unsigned int d_disp_mask; - boost::shared_mutex mutex_buffer; - mutable boost::mutex mutex_notify; - boost::condition_variable condition_buffer_ready; + size_t d_index; std::vector<short> d_buffer; + rpcbufferedget< std::vector<short> > buffered_get; public: ctrlport_probe2_s_impl(const std::string &id, const std::string &desc, @@ -66,4 +65,3 @@ namespace gr { } /* namespace gr */ #endif /* INCLUDED_CTRLPORT_PROBE2_S_IMPL_H */ - diff --git a/gr-blocks/lib/peak_detector2_fb_impl.cc b/gr-blocks/lib/peak_detector2_fb_impl.cc index 7ff7f542ec..dc13e66dbe 100644 --- a/gr-blocks/lib/peak_detector2_fb_impl.cc +++ b/gr-blocks/lib/peak_detector2_fb_impl.cc @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2007,2010,2013 Free Software Foundation, Inc. + * Copyright 2007,2010,2013,2015 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -45,15 +45,46 @@ namespace gr { : sync_block("peak_detector2_fb", io_signature::make(1, 1, sizeof(float)), io_signature::make2(1, 2, sizeof(char), sizeof(float))), - d_threshold_factor_rise(threshold_factor_rise), - d_look_ahead(look_ahead), d_alpha(alpha), d_avg(0.0f), d_found(false) + d_avg(0.0f), d_found(false) { + set_threshold_factor_rise(threshold_factor_rise); + set_look_ahead(look_ahead); + set_alpha(alpha); } peak_detector2_fb_impl::~peak_detector2_fb_impl() { } + void + peak_detector2_fb_impl::set_threshold_factor_rise(float thr) + { + gr::thread::scoped_lock lock(d_setlock); + d_threshold_factor_rise = thr; + invalidate(); + } + + void + peak_detector2_fb_impl::set_look_ahead(int look) + { + gr::thread::scoped_lock lock(d_setlock); + d_look_ahead = look; + invalidate(); + } + + void + peak_detector2_fb_impl::set_alpha(float alpha) + { + d_alpha = alpha; + } + + void + peak_detector2_fb_impl::invalidate() + { + d_found = false; + set_output_multiple(1); + } + int peak_detector2_fb_impl::work(int noutput_items, gr_vector_const_void_star &input_items, @@ -61,53 +92,53 @@ namespace gr { { float *iptr = (float *)input_items[0]; char *optr = (char *)output_items[0]; + float *sigout; + + if(output_items.size() == 2) + sigout = (float *)output_items[1]; memset(optr, 0, noutput_items*sizeof(char)); - for(int i = 0; i < noutput_items; i++) { - if(!d_found) { - // Have not yet detected presence of peak + gr::thread::scoped_lock lock(d_setlock); + + // have not crossed threshold yet + if(d_found==false) { + for(int i = 0; i < noutput_items; i++) { + d_avg = d_alpha*iptr[i] + (1.0f - d_alpha)*d_avg; + if(output_items.size() == 2) + sigout[i]=d_avg; if(iptr[i] > d_avg * (1.0f + d_threshold_factor_rise)) { d_found = true; - d_look_ahead_remaining = d_look_ahead; d_peak_val = -(float)INFINITY; - } - else { - d_avg = d_alpha*iptr[i] + (1.0f - d_alpha)*d_avg; + set_output_multiple(d_look_ahead); + return i; } } - else { - // Detected presence of peak + return noutput_items; + } // end d_found==false + + // can complete in this call + else if(noutput_items >= d_look_ahead) { + for(int i = 0; i < d_look_ahead; i++) { + d_avg = d_alpha*iptr[i] + (1.0f - d_alpha)*d_avg; + if(output_items.size() == 2) + sigout[i]=d_avg; if(iptr[i] > d_peak_val) { d_peak_val = iptr[i]; - d_peak_ind = i; - } - else if(d_look_ahead_remaining <= 0) { - optr[d_peak_ind] = 1; - d_found = false; - d_avg = iptr[i]; + d_peak_ind =i; } - - // Have not yet located peak, loop and keep searching. - d_look_ahead_remaining--; - } - - // Every iteration of the loop, write debugging signal out if - // connected: - if(output_items.size() == 2) { - float *sigout = (float *)output_items[1]; - sigout[i] = d_avg; } - } // loop - - if(!d_found) - return noutput_items; + optr[d_peak_ind] = 1; - // else if detected presence, keep searching during the next call to work. - int tmp = d_peak_ind; - d_peak_ind = 1; + // restart the search + invalidate(); + return d_look_ahead; + } // end can complete in this call - return tmp - 1; + // cannot complete in this call + else { + return 0; // ask for more + } } } /* namespace blocks */ diff --git a/gr-blocks/lib/peak_detector2_fb_impl.h b/gr-blocks/lib/peak_detector2_fb_impl.h index f5a8ac1a6b..4e16c93dac 100644 --- a/gr-blocks/lib/peak_detector2_fb_impl.h +++ b/gr-blocks/lib/peak_detector2_fb_impl.h @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2007,2013 Free Software Foundation, Inc. + * Copyright 2007,2013,2015 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -40,14 +40,16 @@ namespace gr { float d_avg; bool d_found; + void invalidate(); + public: peak_detector2_fb_impl(float threshold_factor_rise, int look_ahead, float alpha); ~peak_detector2_fb_impl(); - void set_threshold_factor_rise(float thr) { d_threshold_factor_rise = thr; } - void set_look_ahead(int look) { d_look_ahead = look; } - void set_alpha(float alpha) { d_alpha = alpha; } + void set_threshold_factor_rise(float thr); + void set_look_ahead(int look); + void set_alpha(float alpha); float threshold_factor_rise() { return d_threshold_factor_rise; } int look_ahead() { return d_look_ahead; } diff --git a/gr-blocks/python/blocks/CMakeLists.txt b/gr-blocks/python/blocks/CMakeLists.txt index 44977313cf..19d808b1dd 100644 --- a/gr-blocks/python/blocks/CMakeLists.txt +++ b/gr-blocks/python/blocks/CMakeLists.txt @@ -43,14 +43,14 @@ if(ENABLE_TESTING) include(GrTest) file(GLOB py_qa_test_files "qa_*.py") - # Force out the controlport QA tests if we've disabled it. - if(NOT ENABLE_GR_CTRLPORT) + # Force out the controlport QA tests if we have no backends to use. + if(CTRLPORT_BACKENDS EQUAL 0) list(REMOVE_ITEM py_qa_test_files ${CMAKE_CURRENT_SOURCE_DIR}/qa_cpp_py_binding.py ${CMAKE_CURRENT_SOURCE_DIR}/qa_cpp_py_binding_set.py ${CMAKE_CURRENT_SOURCE_DIR}/qa_ctrlport_probes.py ) - endif(NOT ENABLE_GR_CTRLPORT) + endif(CTRLPORT_BACKENDS EQUAL 0) foreach(py_qa_test_file ${py_qa_test_files}) get_filename_component(py_qa_test_name ${py_qa_test_file} NAME_WE) diff --git a/gr-blocks/python/blocks/qa_cpp_py_binding.py b/gr-blocks/python/blocks/qa_cpp_py_binding.py new file mode 100644 index 0000000000..23a5c9b826 --- /dev/null +++ b/gr-blocks/python/blocks/qa_cpp_py_binding.py @@ -0,0 +1,173 @@ +#!/usr/bin/env python +# +# Copyright 2012,2013,2015 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. +# + +# +# This program tests mixed python and c++ ctrlport exports in a single app +# + +import sys, time, random, numpy, re +from gnuradio import gr, gr_unittest, blocks + +from gnuradio.ctrlport import GNURadio +from gnuradio import ctrlport +import os + +def get1(): + return "success" + +def get2(): + return "failure" + +class inc_class: + def __init__(self): + self.val = 1 + def pp(self): + self.val = self.val+1 + return self.val + +get3 = inc_class() + +def get4(): + random.seed(0) + rv = random.random() + return rv + +def get5(): + numpy.random.seed(0) + samp_t = numpy.random.randn(24)+1j*numpy.random.randn(24); + samp_f = numpy.fft.fft(samp_t); + log_pow_f = 20*numpy.log10(numpy.abs(samp_f)) + rv = list(log_pow_f) + return rv; + +def get6(): + numpy.random.seed(0) + samp_t = numpy.random.randn(1024)+1j*numpy.random.randn(1024); + rv = list(samp_t) + return rv; + +class test_cpp_py_binding(gr_unittest.TestCase): + + def setUp(self): + self.tb = gr.top_block() + os.environ['GR_CONF_CONTROLPORT_ON'] = 'True' + + def tearDown(self): + self.tb = None + + def test_001(self): + v1 = gr.RPC_get_string("pyland", "v1", "unit_1_string", + "Python Exported String", "", "", "", + gr.DISPNULL) + v1.activate(get1) + + v2 = gr.RPC_get_string("pyland", "v2", "unit_2_string", + "Python Exported String", "", "", "", + gr.DISPNULL) + v2.activate(get2) + + v3 = gr.RPC_get_int("pyland", "v3", "unit_3_int", + "Python Exported Int", 0, 100, 1, + gr.DISPNULL) + v3.activate(get3.pp) + + v4 = gr.RPC_get_double("pyland", "time", "unit_4_time_double", + "Python Exported Double", 0, 1000, 1, + gr.DISPNULL) + v4.activate(get4) + + v5 = gr.RPC_get_vector_float("pyland", "fvec", "unit_5_float_vector", + "Python Exported Float Vector", [], [], [], + gr.DISPTIME | gr.DISPOPTCPLX) + v5.activate(get5) + + v6 = gr.RPC_get_vector_gr_complex("pyland", "cvec", "unit_6_gr_complex_vector", + "Python Exported Complex Vector", [], [], [], + gr.DISPXY | gr.DISPOPTSCATTER) + v6.activate(get6) + + # print some variables locally + val = get1() + rval = v1.get() + self.assertEqual(val, rval) + + val = get2() + rval = v2.get() + self.assertEqual(val, rval) + + val = get3.pp() + rval = v3.get() + self.assertEqual(val+1, rval) + + val = get4() + rval = v4.get() + self.assertEqual(val, rval) + + val = get5() + rval = v5.get() + self.assertComplexTuplesAlmostEqual(val, rval, 5) + + val = get6() + rval = v6.get() + self.assertComplexTuplesAlmostEqual(val, rval, 5) + + def test_002(self): + data = range(1,9) + + self.src = blocks.vector_source_c(data) + self.p1 = blocks.ctrlport_probe_c("aaa","C++ exported variable") + self.p2 = blocks.ctrlport_probe_c("bbb","C++ exported variable") + probe_name = self.p2.alias() + + self.tb.connect(self.src, self.p1) + self.tb.connect(self.src, self.p2) + self.tb.start() + + # Probes return complex values as list of floats with re, im + # Imaginary parts of this data set are 0. + expected_result = [1, 2, 3, 4, + 5, 6, 7, 8] + + # Make sure we have time for flowgraph to run + time.sleep(0.1) + + # Get available endpoint + ep = gr.rpcmanager_get().endpoints()[0] + hostname = re.search("-h (\S+|\d+\.\d+\.\d+\.\d+)", ep).group(1) + portnum = re.search("-p (\d+)", ep).group(1) + argv = [None, hostname, portnum] + + # Initialize a simple ControlPort client from endpoint + from gnuradio.ctrlport.GNURadioControlPortClient import GNURadioControlPortClient + radiosys = GNURadioControlPortClient(argv=argv, rpcmethod='thrift') + radio = radiosys.client + + # Get all exported knobs + ret = radio.getKnobs([probe_name + "::bbb"]) + for name in ret.keys(): + result = ret[name].value + self.assertEqual(result, expected_result) + + self.tb.stop() + +if __name__ == '__main__': + gr_unittest.run(test_cpp_py_binding, "test_cpp_py_binding.xml") diff --git a/gr-blocks/python/blocks/qa_cpp_py_binding_set.py b/gr-blocks/python/blocks/qa_cpp_py_binding_set.py new file mode 100644 index 0000000000..5b81de08f9 --- /dev/null +++ b/gr-blocks/python/blocks/qa_cpp_py_binding_set.py @@ -0,0 +1,151 @@ +#!/usr/bin/env python +# +# Copyright 2012,2013,2015 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. +# + +# +# This program tests mixed python and c++ GRCP sets in a single app +# + +import sys, time, random, numpy, re +from gnuradio import gr, gr_unittest, blocks + +from gnuradio.ctrlport import GNURadio +from gnuradio import ctrlport +import os + +class inc_class: + def __init__(self,val): + self.val = val; + + def _get(self): + #print "returning get (val = %s)"%(str(self.val)); + return self.val; + + def _set(self,val): + #print "updating val to %s"%(str(val)); + self.val = val; + return; + +getset1 = inc_class(10); +getset2 = inc_class(100.0); +getset3 = inc_class("test"); + +class test_cpp_py_binding_set(gr_unittest.TestCase): + def setUp(self): + self.tb = gr.top_block() + os.environ['GR_CONF_CONTROLPORT_ON'] = 'True' + + def tearDown(self): + self.tb = None + + def test_001(self): + + g1 = gr.RPC_get_int("pyland", "v1", "unit_1_int", + "Python Exported Int", 0, 100, 10, + gr.DISPNULL) + g1.activate(getset1._get) + s1 = gr.RPC_get_int("pyland", "v1", "unit_1_int", + "Python Exported Int", 0, 100, 10, + gr.DISPNULL) + s1.activate(getset1._set) + time.sleep(0.01) + + # test int variables + getset1._set(21) + val = getset1._get() + rval = g1.get() + self.assertEqual(val, rval) + + g2 = gr.RPC_get_float("pyland", "v2", "unit_2_float", + "Python Exported Float", -100, 1000.0, 100.0, + gr.DISPNULL) + g2.activate(getset2._get) + s2 = gr.RPC_get_float("pyland", "v2", "unit_2_float", + "Python Exported Float", -100, 1000.0, 100.0, + gr.DISPNULL) + s2.activate(getset2._set) + time.sleep(0.01) + + # test float variables + getset2._set(123.456) + val = getset2._get() + rval = g2.get() + self.assertAlmostEqual(val, rval, 4) + + g3 = gr.RPC_get_string("pyland", "v3", "unit_3_string", + "Python Exported String", "", "", "", + gr.DISPNULL) + g3.activate(getset3._get) + s3 = gr.RPC_get_string("pyland", "v3", "unit_3_string", + "Python Exported String", "", "", "", + gr.DISPNULL) + s3.activate(getset3._set) + time.sleep(0.01) + + # test string variables + getset3._set("third test") + val = getset3._get() + rval = g3.get() + self.assertEqual(val, rval) + + + def test_002(self): + data = range(1, 10) + + self.src = blocks.vector_source_c(data, True) + self.p = blocks.nop(gr.sizeof_gr_complex) + self.p.set_ctrlport_test(0); + probe_info = self.p.alias() + + self.tb.connect(self.src, self.p) + + # Get available endpoint + ep = gr.rpcmanager_get().endpoints()[0] + hostname = re.search("-h (\S+|\d+\.\d+\.\d+\.\d+)", ep).group(1) + portnum = re.search("-p (\d+)", ep).group(1) + argv = [None, hostname, portnum] + + # Initialize a simple ControlPort client from endpoint + from gnuradio.ctrlport.GNURadioControlPortClient import GNURadioControlPortClient + radiosys = GNURadioControlPortClient(argv=argv, rpcmethod='thrift') + radio = radiosys.client + + self.tb.start() + + # Make sure we have time for flowgraph to run + time.sleep(0.1) + + # Get all exported knobs + key_name_test = probe_info+"::test" + ret = radio.getKnobs([key_name_test,]) + + ret[key_name_test].value = 10 + radio.setKnobs({key_name_test: ret[key_name_test]}) + + ret = radio.getKnobs([]) + result_test = ret[key_name_test].value + self.assertEqual(result_test, 10) + + self.tb.stop() + self.tb.wait() + +if __name__ == '__main__': + gr_unittest.run(test_cpp_py_binding_set, "test_cpp_py_binding_set.xml") diff --git a/gr-blocks/python/blocks/qa_ctrlport_probes.py b/gr-blocks/python/blocks/qa_ctrlport_probes.py index 91d96010fd..c678846df0 100644 --- a/gr-blocks/python/blocks/qa_ctrlport_probes.py +++ b/gr-blocks/python/blocks/qa_ctrlport_probes.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright 2013 Free Software Foundation, Inc. +# Copyright 2013,2015 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -22,33 +22,225 @@ import sys, time, random, numpy from gnuradio import gr, gr_unittest, blocks +import os, struct, re -import os, struct +from gnuradio.ctrlport.GNURadioControlPortClient import GNURadioControlPortClient class test_ctrlport_probes(gr_unittest.TestCase): def setUp(self): - self.tb = gr.top_block() os.environ['GR_CONF_CONTROLPORT_ON'] = 'True' + self.tb = gr.top_block() def tearDown(self): self.tb = None - def xtest_001(self): - pass + def test_001(self): + data = range(1,9) + + self.src = blocks.vector_source_c(data, True) + self.probe = blocks.ctrlport_probe2_c("samples","Complex", + len(data), gr.DISPNULL) + probe_name = self.probe.alias() + + self.tb.connect(self.src, self.probe) + self.tb.start() + + + # Probes return complex values as list of floats with re, im + # Imaginary parts of this data set are 0. + expected_result = [1, 2, 3, 4, + 5, 6, 7, 8] + + # Make sure we have time for flowgraph to run + time.sleep(0.1) + + # Get available endpoint + ep = gr.rpcmanager_get().endpoints()[0] + hostname = re.search("-h (\S+|\d+\.\d+\.\d+\.\d+)", ep).group(1) + portnum = re.search("-p (\d+)", ep).group(1) + argv = [None, hostname, portnum] + + # Initialize a simple ControlPort client from endpoint + from gnuradio.ctrlport.GNURadioControlPortClient import GNURadioControlPortClient + radiosys = GNURadioControlPortClient(argv=argv, rpcmethod='thrift') + radio = radiosys.client + + # Get all exported knobs + ret = radio.getKnobs([probe_name + "::samples"]) + for name in ret.keys(): + # Get data in probe, which might be offset; find the + # beginning and unwrap. + result = ret[name].value + i = result.index(complex(1.0, 0.0)) + result = result[i:] + result[0:i] + self.assertComplexTuplesAlmostEqual(expected_result, result, 4) + + self.tb.stop() + self.tb.wait() + def test_002(self): - pass + data = range(1,9) + + self.src = blocks.vector_source_f(data, True) + self.probe = blocks.ctrlport_probe2_f("samples","Floats", + len(data), gr.DISPNULL) + probe_name = self.probe.alias() + + self.tb.connect(self.src, self.probe) + self.tb.start() + + expected_result = [1, 2, 3, 4, 5, 6, 7, 8,] + + # Make sure we have time for flowgraph to run + time.sleep(0.1) + + # Get available endpoint + ep = gr.rpcmanager_get().endpoints()[0] + hostname = re.search("-h (\S+|\d+\.\d+\.\d+\.\d+)", ep).group(1) + portnum = re.search("-p (\d+)", ep).group(1) + argv = [None, hostname, portnum] + # Initialize a simple ControlPort client from endpoint + from gnuradio.ctrlport.GNURadioControlPortClient import GNURadioControlPortClient + radiosys = GNURadioControlPortClient(argv=argv, rpcmethod='thrift') + radio = radiosys.client + + # Get all exported knobs + ret = radio.getKnobs([probe_name + "::samples"]) + for name in ret.keys(): + # Get data in probe, which might be offset; find the + # beginning and unwrap. + result = ret[name].value + i = result.index(1.0) + result = result[i:] + result[0:i] + self.assertEqual(expected_result, result) + + self.tb.stop() + self.tb.wait() def test_003(self): - pass + data = range(1,9) + + self.src = blocks.vector_source_i(data, True) + self.probe = blocks.ctrlport_probe2_i("samples","Integers", + len(data), gr.DISPNULL) + probe_name = self.probe.alias() + + self.tb.connect(self.src, self.probe) + self.tb.start() + + expected_result = [1, 2, 3, 4, 5, 6, 7, 8,] + + # Make sure we have time for flowgraph to run + time.sleep(0.1) + + # Get available endpoint + ep = gr.rpcmanager_get().endpoints()[0] + hostname = re.search("-h (\S+|\d+\.\d+\.\d+\.\d+)", ep).group(1) + portnum = re.search("-p (\d+)", ep).group(1) + argv = [None, hostname, portnum] + + # Initialize a simple ControlPort client from endpoint + from gnuradio.ctrlport.GNURadioControlPortClient import GNURadioControlPortClient + radiosys = GNURadioControlPortClient(argv=argv, rpcmethod='thrift') + radio = radiosys.client + + # Get all exported knobs + ret = radio.getKnobs([probe_name + "::samples"]) + for name in ret.keys(): + # Get data in probe, which might be offset; find the + # beginning and unwrap. + result = ret[name].value + i = result.index(1.0) + result = result[i:] + result[0:i] + self.assertEqual(expected_result, result) + + self.tb.stop() + self.tb.wait() + def test_004(self): - pass + data = range(1,9) + + self.src = blocks.vector_source_s(data, True) + self.probe = blocks.ctrlport_probe2_s("samples","Shorts", + len(data), gr.DISPNULL) + probe_name = self.probe.alias() + + self.tb.connect(self.src, self.probe) + self.tb.start() + + expected_result = [1, 2, 3, 4, 5, 6, 7, 8,] + + # Make sure we have time for flowgraph to run + time.sleep(0.1) + + # Get available endpoint + ep = gr.rpcmanager_get().endpoints()[0] + hostname = re.search("-h (\S+|\d+\.\d+\.\d+\.\d+)", ep).group(1) + portnum = re.search("-p (\d+)", ep).group(1) + argv = [None, hostname, portnum] + + # Initialize a simple ControlPort client from endpoint + from gnuradio.ctrlport.GNURadioControlPortClient import GNURadioControlPortClient + radiosys = GNURadioControlPortClient(argv=argv, rpcmethod='thrift') + radio = radiosys.client + + # Get all exported knobs + ret = radio.getKnobs([probe_name + "::samples"]) + for name in ret.keys(): + # Get data in probe, which might be offset; find the + # beginning and unwrap. + result = ret[name].value + i = result.index(1.0) + result = result[i:] + result[0:i] + self.assertEqual(expected_result, result) + + self.tb.stop() + self.tb.wait() def test_005(self): - pass + data = range(1,9) + + self.src = blocks.vector_source_b(data, True) + self.probe = blocks.ctrlport_probe2_b("samples","Bytes", + len(data), gr.DISPNULL) + probe_name = self.probe.alias() + + self.tb.connect(self.src, self.probe) + self.tb.start() + + expected_result = [1, 2, 3, 4, 5, 6, 7, 8,] + + # Make sure we have time for flowgraph to run + time.sleep(0.1) + + # Get available endpoint + ep = gr.rpcmanager_get().endpoints()[0] + hostname = re.search("-h (\S+|\d+\.\d+\.\d+\.\d+)", ep).group(1) + portnum = re.search("-p (\d+)", ep).group(1) + argv = [None, hostname, portnum] + + # Initialize a simple ControlPort client from endpoint + from gnuradio.ctrlport.GNURadioControlPortClient import GNURadioControlPortClient + radiosys = GNURadioControlPortClient(argv=argv, rpcmethod='thrift') + radio = radiosys.client + + # Get all exported knobs + ret = radio.getKnobs([probe_name + "::samples"]) + for name in ret.keys(): + # Get data in probe, which might be offset; find the + # beginning and unwrap. + result = ret[name].value + result = list(struct.unpack(len(result)*'b', result)) + i = result.index(1) + result = result[i:] + result[0:i] + self.assertEqual(expected_result, result) + + self.tb.stop() + self.tb.wait() if __name__ == '__main__': gr_unittest.run(test_ctrlport_probes, "test_ctrlport_probes.xml") diff --git a/gr-blocks/python/blocks/qa_peak_detector2.py b/gr-blocks/python/blocks/qa_peak_detector2.py index 475897eac2..d6fd4fe95f 100644 --- a/gr-blocks/python/blocks/qa_peak_detector2.py +++ b/gr-blocks/python/blocks/qa_peak_detector2.py @@ -30,18 +30,20 @@ class test_peak_detector2(gr_unittest.TestCase): def tearDown(self): self.tb = None - def test_regen1(self): + def test_peak1(self): + #print "\n\nTEST 1" tb = self.tb - data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, - 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] + n=10 + data = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 9, 8, 7, 6, 5, 4, 3, 2, 1, 0,)+n*(0,) expected_result = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)+n*(0,) src = blocks.vector_source_f(data, False) - regen = blocks.peak_detector2_fb() + regen = blocks.peak_detector2_fb(7.0, 25, 0.001) dst = blocks.vector_sink_b() tb.connect(src, regen) @@ -52,5 +54,80 @@ class test_peak_detector2(gr_unittest.TestCase): self.assertEqual(expected_result, dst_data) + def test_peak2(self): + #print "\n\nTEST 2" + tb = self.tb + + n=10 + data = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 9, 8, 7, 6, 5, 4, 3, 2, 1, 0,)+n*(0,) + + expected_result = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)+n*(0,) + + + src = blocks.vector_source_f(data, False) + regen = blocks.peak_detector2_fb(7.0, 1000, 0.001) # called with a LONG window + dst = blocks.vector_sink_b() + + tb.connect(src, regen) + tb.connect(regen, dst) + tb.run() + + dst_data = dst.data() + + # here we know that the block will terminate prematurely, so we compare only part of the expected_result + self.assertEqual(expected_result[0:len(dst_data)], dst_data) + + + def test_peak3(self): + #print "\n\nTEST 3" + tb = self.tb + + l = 8100 + m = 100 + n = 10 + data = l*(0,)+ (10,)+ m*(0,)+(100,)+ n*(0,) + expected_result = l*(0,)+ (0,)+ m*(0,)+(1,)+ n*(0,) + + + src = blocks.vector_source_f(data, False) + regen = blocks.peak_detector2_fb(7.0, 105, 0.001) + dst = blocks.vector_sink_b() + + tb.connect(src, regen) + tb.connect(regen, dst) + tb.run() + + dst_data = dst.data() + + self.assertEqual(expected_result, dst_data) + + + def test_peak4(self): + #print "\n\nTEST 4" + tb = self.tb + + l = 8100 + m = 100 + n = 10 + data = l*(0,)+ (10,)+ m*(0,)+(100,)+ n*(0,) + expected_result = l*(0,)+ (0,)+ m*(0,)+(1,)+ n*(0,) + + + src = blocks.vector_source_f(data, False) + regen = blocks.peak_detector2_fb(7.0, 150, 0.001) + dst = blocks.vector_sink_b() + + tb.connect(src, regen) + tb.connect(regen, dst) + tb.run() + + dst_data = dst.data() + + # here we know that the block will terminate prematurely, so we compare only part of the expected_result + self.assertEqual(expected_result[0:len(dst_data)], dst_data) + + if __name__ == '__main__': gr_unittest.run(test_peak_detector2, "test_peak_detector2.xml") diff --git a/gr-digital/examples/CMakeLists.txt b/gr-digital/examples/CMakeLists.txt index 8faad96708..38ee443ab7 100644 --- a/gr-digital/examples/CMakeLists.txt +++ b/gr-digital/examples/CMakeLists.txt @@ -31,6 +31,13 @@ GR_PYTHON_INSTALL(PROGRAMS COMPONENT "digital_python" ) +install( + FILES + burst_shaper.grc + DESTINATION ${GR_PKG_DIGITAL_EXAMPLES_DIR} + COMPONENT "digital_python" +) + # Narrowband GR_PYTHON_INSTALL(PROGRAMS narrowband/transmit_path.py @@ -82,6 +89,7 @@ install( demod/dpsk_loopback.grc demod/gfsk_loopback.grc demod/test_corr_and_sync.grc + demod/test_corr_est.grc demod/uhd_corr_and_sync_tx.grc demod/uhd_corr_and_sync_rx.grc DESTINATION ${GR_PKG_DIGITAL_EXAMPLES_DIR}/demod diff --git a/gr-digital/examples/burst_shaper.grc b/gr-digital/examples/burst_shaper.grc new file mode 100644 index 0000000000..35a98a3267 --- /dev/null +++ b/gr-digital/examples/burst_shaper.grc @@ -0,0 +1,880 @@ +<?xml version='1.0' encoding='ASCII'?> +<?grc format='1' created='3.7.8'?> +<flow_graph> + <timestamp>Fri Apr 17 12:31:57 2015</timestamp> + <block> + <key>options</key> + <param> + <key>id</key> + <value>burst_shaper</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>title</key> + <value></value> + </param> + <param> + <key>author</key> + <value></value> + </param> + <param> + <key>description</key> + <value></value> + </param> + <param> + <key>window_size</key> + <value>1280, 1024</value> + </param> + <param> + <key>generate_options</key> + <value>no_gui</value> + </param> + <param> + <key>category</key> + <value>Custom</value> + </param> + <param> + <key>run_options</key> + <value>run</value> + </param> + <param> + <key>run</key> + <value>True</value> + </param> + <param> + <key>max_nouts</key> + <value>0</value> + </param> + <param> + <key>realtime_scheduling</key> + <value></value> + </param> + <param> + <key>thread_safe_setters</key> + <value></value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(10, 10)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>samp_rate</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>32000</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(392, 11)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>window_taps</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>fft.window.hann(10)</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(232, 11)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>import</key> + <param> + <key>id</key> + <value>import_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>import</key> + <value>import pmt</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(8, 99)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>import</key> + <param> + <key>id</key> + <value>import_0_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>import</key> + <value>from gnuradio import fft</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(96, 99)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_vector_source_x</key> + <param> + <key>id</key> + <value>blocks_vector_source_x_0_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>float</value> + </param> + <param> + <key>vector</key> + <value>[1.0, -1.0]*15</value> + </param> + <param> + <key>tags</key> + <value>[gr.python_to_tag({'offset':0, 'key':pmt.intern('packet_len'), 'value':pmt.from_long(20), 'srcid':pmt.intern('vector_source')})]</value> + </param> + <param> + <key>repeat</key> + <value>False</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(8, 171)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_vector_source_x</key> + <param> + <key>id</key> + <value>blocks_vector_source_x_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>vector</key> + <value>[complex(1.0), complex(-1.0)]*15</value> + </param> + <param> + <key>tags</key> + <value>[gr.python_to_tag({'offset':0, 'key':pmt.intern('packet_len'), 'value':pmt.from_long(20), 'srcid':pmt.intern('vector_source')})]</value> + </param> + <param> + <key>repeat</key> + <value>False</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(8, 307)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_tagged_stream_to_pdu</key> + <param> + <key>id</key> + <value>blocks_tagged_stream_to_pdu_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>float</value> + </param> + <param> + <key>tag</key> + <value>packet_len</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(632, 163)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_message_debug</key> + <param> + <key>id</key> + <value>blocks_message_debug_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(888, 168)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_message_debug</key> + <param> + <key>id</key> + <value>blocks_message_debug_0_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(888, 304)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_tag_debug</key> + <param> + <key>id</key> + <value>blocks_tag_debug_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>float</value> + </param> + <param> + <key>name</key> + <value>Float</value> + </param> + <param> + <key>filter</key> + <value>"packet_len"</value> + </param> + <param> + <key>num_inputs</key> + <value>1</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>display</key> + <value>True</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(632, 211)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_tagged_stream_to_pdu</key> + <param> + <key>id</key> + <value>blocks_tagged_stream_to_pdu_1</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>tag</key> + <value>packet_len</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(632, 299)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>digital_burst_shaper_xx</key> + <param> + <key>id</key> + <value>digital_burst_shaper_xx_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>float</value> + </param> + <param> + <key>window</key> + <value>window_taps</value> + </param> + <param> + <key>pre_padding</key> + <value>5</value> + </param> + <param> + <key>post_padding</key> + <value>5</value> + </param> + <param> + <key>insert_phasing</key> + <value>False</value> + </param> + <param> + <key>length_tag_name</key> + <value>"packet_len"</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(232, 155)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_throttle</key> + <param> + <key>id</key> + <value>blocks_throttle_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>float</value> + </param> + <param> + <key>samples_per_second</key> + <value>samp_rate</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>ignoretag</key> + <value>True</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(456, 187)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>digital_burst_shaper_xx</key> + <param> + <key>id</key> + <value>digital_burst_shaper_xx_0_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>window</key> + <value>window_taps</value> + </param> + <param> + <key>pre_padding</key> + <value>5</value> + </param> + <param> + <key>post_padding</key> + <value>5</value> + </param> + <param> + <key>insert_phasing</key> + <value>False</value> + </param> + <param> + <key>length_tag_name</key> + <value>"packet_len"</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(232, 291)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_throttle</key> + <param> + <key>id</key> + <value>blocks_throttle_0_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>samples_per_second</key> + <value>samp_rate</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>ignoretag</key> + <value>True</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(456, 323)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_tag_debug</key> + <param> + <key>id</key> + <value>blocks_tag_debug_0_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>name</key> + <value>Complex</value> + </param> + <param> + <key>filter</key> + <value>"packet_len"</value> + </param> + <param> + <key>num_inputs</key> + <value>1</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>display</key> + <value>True</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(632, 347)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <connection> + <source_block_id>blocks_throttle_0</source_block_id> + <sink_block_id>blocks_tagged_stream_to_pdu_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>blocks_vector_source_x_0_0</source_block_id> + <sink_block_id>digital_burst_shaper_xx_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>digital_burst_shaper_xx_0</source_block_id> + <sink_block_id>blocks_throttle_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>digital_burst_shaper_xx_0_0</source_block_id> + <sink_block_id>blocks_throttle_0_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>blocks_vector_source_x_0</source_block_id> + <sink_block_id>digital_burst_shaper_xx_0_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>blocks_tagged_stream_to_pdu_1</source_block_id> + <sink_block_id>blocks_message_debug_0_0</sink_block_id> + <source_key>pdus</source_key> + <sink_key>print</sink_key> + </connection> + <connection> + <source_block_id>blocks_tagged_stream_to_pdu_0</source_block_id> + <sink_block_id>blocks_message_debug_0</sink_block_id> + <source_key>pdus</source_key> + <sink_key>print</sink_key> + </connection> + <connection> + <source_block_id>blocks_throttle_0</source_block_id> + <sink_block_id>blocks_tag_debug_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>blocks_throttle_0_0</source_block_id> + <sink_block_id>blocks_tagged_stream_to_pdu_1</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>blocks_throttle_0_0</source_block_id> + <sink_block_id>blocks_tag_debug_0_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> +</flow_graph> diff --git a/gr-digital/examples/demod/test_corr_est.grc b/gr-digital/examples/demod/test_corr_est.grc new file mode 100644 index 0000000000..6237565a4b --- /dev/null +++ b/gr-digital/examples/demod/test_corr_est.grc @@ -0,0 +1,3500 @@ +<?xml version='1.0' encoding='ASCII'?> +<?grc format='1' created='3.7.7'?> +<flow_graph> + <timestamp>Fri Jul 11 16:54:10 2014</timestamp> + <block> + <key>options</key> + <param> + <key>id</key> + <value>test_corr_est</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>title</key> + <value></value> + </param> + <param> + <key>author</key> + <value></value> + </param> + <param> + <key>description</key> + <value></value> + </param> + <param> + <key>window_size</key> + <value>2000,2000</value> + </param> + <param> + <key>generate_options</key> + <value>qt_gui</value> + </param> + <param> + <key>category</key> + <value>Custom</value> + </param> + <param> + <key>run_options</key> + <value>prompt</value> + </param> + <param> + <key>run</key> + <value>True</value> + </param> + <param> + <key>max_nouts</key> + <value>0</value> + </param> + <param> + <key>realtime_scheduling</key> + <value></value> + </param> + <param> + <key>thread_safe_setters</key> + <value></value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(10, 10)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>data</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>[0]*4+[random.getrandbits(8) for i in range(payload_size)]</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(16, 251)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>rrc_taps</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>firdes.root_raised_cosine(nfilts, nfilts, 1.0/float(sps), eb, 5*sps*nfilts)</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(1075, 73)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>nfilts</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>32</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(1074, 9)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>payload_size</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>992</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(101, 73)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>bb_filter</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>firdes.root_raised_cosine(sps, sps, 1, eb, 101)</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(429, 8)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>sps</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>4</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(278, 72)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>matched_filter</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>firdes.root_raised_cosine(nfilts, nfilts, 1, eb, int(11*sps*nfilts))</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(429, 72)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>samp_rate</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>100000</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(11, 72)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>gap</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>20000</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(202, 72)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>eb</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>0.35</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(346, 72)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>preamble</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>[0xac, 0xdd, 0xa4, 0xe2, 0xf2, 0x8c, 0x20, 0xfc]</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(279, 8)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>rxmod</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>digital.generic_mod(constel, False, sps, True, eb, False, False)</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(8, 427)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>channels_channel_model</key> + <param> + <key>id</key> + <value>channels_channel_model_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>noise_voltage</key> + <value>noise</value> + </param> + <param> + <key>freq_offset</key> + <value>freq_offset</value> + </param> + <param> + <key>epsilon</key> + <value>time_offset</value> + </param> + <param> + <key>taps</key> + <value>1.0</value> + </param> + <param> + <key>seed</key> + <value>0</value> + </param> + <param> + <key>block_tags</key> + <value>False</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(772, 158)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_throttle</key> + <param> + <key>id</key> + <value>blocks_throttle_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>samples_per_second</key> + <value>samp_rate</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>ignoretag</key> + <value>True</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(586, 190)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_null_source</key> + <param> + <key>id</key> + <value>blocks_null_source_0_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>num_outputs</key> + <value>1</value> + </param> + <param> + <key>bus_conns</key> + <value>[[0,],]</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(402, 322)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable_qtgui_range</key> + <param> + <key>id</key> + <value>phase</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>label</key> + <value>Phase offset</value> + </param> + <param> + <key>value</key> + <value>0</value> + </param> + <param> + <key>start</key> + <value>-2*scipy.pi</value> + </param> + <param> + <key>stop</key> + <value>2*scipy.pi</value> + </param> + <param> + <key>step</key> + <value>0.1</value> + </param> + <param> + <key>widget</key> + <value>slider</value> + </param> + <param> + <key>orient</key> + <value>Qt.Horizontal</value> + </param> + <param> + <key>min_len</key> + <value>200</value> + </param> + <param> + <key>gui_hint</key> + <value>3,1,1,1</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(692, 7)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable_qtgui_range</key> + <param> + <key>id</key> + <value>time_offset</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>label</key> + <value>Timing Offset</value> + </param> + <param> + <key>value</key> + <value>1</value> + </param> + <param> + <key>start</key> + <value>0.995</value> + </param> + <param> + <key>stop</key> + <value>1.005</value> + </param> + <param> + <key>step</key> + <value>0.00001</value> + </param> + <param> + <key>widget</key> + <value>slider</value> + </param> + <param> + <key>orient</key> + <value>Qt.Horizontal</value> + </param> + <param> + <key>min_len</key> + <value>200</value> + </param> + <param> + <key>gui_hint</key> + <value>4,1,1,1</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(950, 8)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable_qtgui_range</key> + <param> + <key>id</key> + <value>noise</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>label</key> + <value>Noise</value> + </param> + <param> + <key>value</key> + <value>0</value> + </param> + <param> + <key>start</key> + <value>0</value> + </param> + <param> + <key>stop</key> + <value>1</value> + </param> + <param> + <key>step</key> + <value>0.005</value> + </param> + <param> + <key>widget</key> + <value>slider</value> + </param> + <param> + <key>orient</key> + <value>Qt.Horizontal</value> + </param> + <param> + <key>min_len</key> + <value>200</value> + </param> + <param> + <key>gui_hint</key> + <value>3,0,1,1</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(584, 7)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>digital_pfb_clock_sync_xxx</key> + <param> + <key>id</key> + <value>digital_pfb_clock_sync_xxx_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>ccf</value> + </param> + <param> + <key>sps</key> + <value>sps</value> + </param> + <param> + <key>loop_bw</key> + <value>2*3.14/100.0</value> + </param> + <param> + <key>taps</key> + <value>rrc_taps</value> + </param> + <param> + <key>filter_size</key> + <value>nfilts</value> + </param> + <param> + <key>init_phase</key> + <value>0</value> + </param> + <param> + <key>max_dev</key> + <value>0.5</value> + </param> + <param> + <key>osps</key> + <value>1</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(790, 289)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_sub_xx</key> + <param> + <key>id</key> + <value>blocks_sub_xx_0</value> + </param> + <param> + <key>_enabled</key> + <value>False</value> + </param> + <param> + <key>type</key> + <value>float</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>num_inputs</key> + <value>2</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(1125, 617)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable_qtgui_range</key> + <param> + <key>id</key> + <value>delay</value> + </param> + <param> + <key>_enabled</key> + <value>False</value> + </param> + <param> + <key>label</key> + <value>delay</value> + </param> + <param> + <key>value</key> + <value>90</value> + </param> + <param> + <key>start</key> + <value>0</value> + </param> + <param> + <key>stop</key> + <value>200</value> + </param> + <param> + <key>step</key> + <value>1</value> + </param> + <param> + <key>widget</key> + <value>counter_slider</value> + </param> + <param> + <key>orient</key> + <value>Qt.Horizontal</value> + </param> + <param> + <key>min_len</key> + <value>200</value> + </param> + <param> + <key>gui_hint</key> + <value>5,0,1,2</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(875, 571)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_char_to_float</key> + <param> + <key>id</key> + <value>blocks_char_to_float_0</value> + </param> + <param> + <key>_enabled</key> + <value>False</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>scale</key> + <value>1</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(752, 517)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_unpack_k_bits_bb</key> + <param> + <key>id</key> + <value>blocks_unpack_k_bits_bb_0</value> + </param> + <param> + <key>_enabled</key> + <value>False</value> + </param> + <param> + <key>k</key> + <value>8</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(576, 517)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_stream_mux</key> + <param> + <key>id</key> + <value>blocks_stream_mux_0</value> + </param> + <param> + <key>_enabled</key> + <value>False</value> + </param> + <param> + <key>type</key> + <value>byte</value> + </param> + <param> + <key>lengths</key> + <value>(len(preamble)/8+payload_size), gap/sps/8</value> + </param> + <param> + <key>num_inputs</key> + <value>2</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(390, 504)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_null_source</key> + <param> + <key>id</key> + <value>blocks_null_source_0</value> + </param> + <param> + <key>_enabled</key> + <value>False</value> + </param> + <param> + <key>type</key> + <value>byte</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>num_outputs</key> + <value>1</value> + </param> + <param> + <key>bus_conns</key> + <value>[[0,],]</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(210, 538)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_delay</key> + <param> + <key>id</key> + <value>blocks_delay_0</value> + </param> + <param> + <key>_enabled</key> + <value>False</value> + </param> + <param> + <key>type</key> + <value>float</value> + </param> + <param> + <key>delay</key> + <value>int(delay)</value> + </param> + <param> + <key>num_ports</key> + <value>1</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(923, 518)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_char_to_float</key> + <param> + <key>id</key> + <value>blocks_char_to_float_0_0</value> + </param> + <param> + <key>_enabled</key> + <value>False</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>scale</key> + <value>1</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(1112, 482)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>qtgui_time_sink_x</key> + <param> + <key>id</key> + <value>qtgui_time_sink_x_0_1</value> + </param> + <param> + <key>_enabled</key> + <value>False</value> + </param> + <param> + <key>type</key> + <value>float</value> + </param> + <param> + <key>name</key> + <value></value> + </param> + <param> + <key>ylabel</key> + <value>Amplitude</value> + </param> + <param> + <key>yunit</key> + <value>""</value> + </param> + <param> + <key>size</key> + <value>20000</value> + </param> + <param> + <key>srate</key> + <value>samp_rate</value> + </param> + <param> + <key>grid</key> + <value>False</value> + </param> + <param> + <key>autoscale</key> + <value>False</value> + </param> + <param> + <key>ymin</key> + <value>-2</value> + </param> + <param> + <key>ymax</key> + <value>2</value> + </param> + <param> + <key>nconnections</key> + <value>3</value> + </param> + <param> + <key>update_time</key> + <value>0.10</value> + </param> + <param> + <key>entags</key> + <value>True</value> + </param> + <param> + <key>gui_hint</key> + <value>2,0,1,2</value> + </param> + <param> + <key>tr_mode</key> + <value>qtgui.TRIG_MODE_TAG</value> + </param> + <param> + <key>tr_slope</key> + <value>qtgui.TRIG_SLOPE_POS</value> + </param> + <param> + <key>tr_level</key> + <value>0.0</value> + </param> + <param> + <key>tr_delay</key> + <value>0.010</value> + </param> + <param> + <key>tr_chan</key> + <value>0</value> + </param> + <param> + <key>tr_tag</key> + <value>time_est</value> + </param> + <param> + <key>ctrlpanel</key> + <value>False</value> + </param> + <param> + <key>legend</key> + <value>True</value> + </param> + <param> + <key>label1</key> + <value></value> + </param> + <param> + <key>width1</key> + <value>1</value> + </param> + <param> + <key>color1</key> + <value>"blue"</value> + </param> + <param> + <key>style1</key> + <value>1</value> + </param> + <param> + <key>marker1</key> + <value>-1</value> + </param> + <param> + <key>alpha1</key> + <value>1.0</value> + </param> + <param> + <key>label2</key> + <value></value> + </param> + <param> + <key>width2</key> + <value>1</value> + </param> + <param> + <key>color2</key> + <value>"red"</value> + </param> + <param> + <key>style2</key> + <value>1</value> + </param> + <param> + <key>marker2</key> + <value>-1</value> + </param> + <param> + <key>alpha2</key> + <value>1.0</value> + </param> + <param> + <key>label3</key> + <value></value> + </param> + <param> + <key>width3</key> + <value>1</value> + </param> + <param> + <key>color3</key> + <value>"green"</value> + </param> + <param> + <key>style3</key> + <value>1</value> + </param> + <param> + <key>marker3</key> + <value>-1</value> + </param> + <param> + <key>alpha3</key> + <value>1.0</value> + </param> + <param> + <key>label4</key> + <value></value> + </param> + <param> + <key>width4</key> + <value>1</value> + </param> + <param> + <key>color4</key> + <value>"black"</value> + </param> + <param> + <key>style4</key> + <value>1</value> + </param> + <param> + <key>marker4</key> + <value>-1</value> + </param> + <param> + <key>alpha4</key> + <value>1.0</value> + </param> + <param> + <key>label5</key> + <value></value> + </param> + <param> + <key>width5</key> + <value>1</value> + </param> + <param> + <key>color5</key> + <value>"cyan"</value> + </param> + <param> + <key>style5</key> + <value>1</value> + </param> + <param> + <key>marker5</key> + <value>-1</value> + </param> + <param> + <key>alpha5</key> + <value>1.0</value> + </param> + <param> + <key>label6</key> + <value></value> + </param> + <param> + <key>width6</key> + <value>1</value> + </param> + <param> + <key>color6</key> + <value>"magenta"</value> + </param> + <param> + <key>style6</key> + <value>1</value> + </param> + <param> + <key>marker6</key> + <value>-1</value> + </param> + <param> + <key>alpha6</key> + <value>1.0</value> + </param> + <param> + <key>label7</key> + <value></value> + </param> + <param> + <key>width7</key> + <value>1</value> + </param> + <param> + <key>color7</key> + <value>"yellow"</value> + </param> + <param> + <key>style7</key> + <value>1</value> + </param> + <param> + <key>marker7</key> + <value>-1</value> + </param> + <param> + <key>alpha7</key> + <value>1.0</value> + </param> + <param> + <key>label8</key> + <value></value> + </param> + <param> + <key>width8</key> + <value>1</value> + </param> + <param> + <key>color8</key> + <value>"dark red"</value> + </param> + <param> + <key>style8</key> + <value>1</value> + </param> + <param> + <key>marker8</key> + <value>-1</value> + </param> + <param> + <key>alpha8</key> + <value>1.0</value> + </param> + <param> + <key>label9</key> + <value></value> + </param> + <param> + <key>width9</key> + <value>1</value> + </param> + <param> + <key>color9</key> + <value>"dark green"</value> + </param> + <param> + <key>style9</key> + <value>1</value> + </param> + <param> + <key>marker9</key> + <value>-1</value> + </param> + <param> + <key>alpha9</key> + <value>1.0</value> + </param> + <param> + <key>label10</key> + <value></value> + </param> + <param> + <key>width10</key> + <value>1</value> + </param> + <param> + <key>color10</key> + <value>"blue"</value> + </param> + <param> + <key>style10</key> + <value>1</value> + </param> + <param> + <key>marker10</key> + <value>-1</value> + </param> + <param> + <key>alpha10</key> + <value>1.0</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(1345, 531)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>digital_constellation_decoder_cb</key> + <param> + <key>id</key> + <value>digital_constellation_decoder_cb_0</value> + </param> + <param> + <key>_enabled</key> + <value>False</value> + </param> + <param> + <key>constellation</key> + <value>constel</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(1111, 433)</value> + </param> + <param> + <key>_rotation</key> + <value>180</value> + </param> + </block> + <block> + <key>digital_costas_loop_cc</key> + <param> + <key>id</key> + <value>digital_costas_loop_cc_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>w</key> + <value>1*3.14/50.0</value> + </param> + <param> + <key>order</key> + <value>2</value> + </param> + <param> + <key>use_snr</key> + <value>False</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(1091, 303)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>qtgui_time_sink_x</key> + <param> + <key>id</key> + <value>qtgui_time_sink_x_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>name</key> + <value></value> + </param> + <param> + <key>ylabel</key> + <value>Amplitude</value> + </param> + <param> + <key>yunit</key> + <value>""</value> + </param> + <param> + <key>size</key> + <value>50000</value> + </param> + <param> + <key>srate</key> + <value>samp_rate</value> + </param> + <param> + <key>grid</key> + <value>False</value> + </param> + <param> + <key>autoscale</key> + <value>False</value> + </param> + <param> + <key>ymin</key> + <value>-2</value> + </param> + <param> + <key>ymax</key> + <value>2</value> + </param> + <param> + <key>nconnections</key> + <value>1</value> + </param> + <param> + <key>update_time</key> + <value>0.10</value> + </param> + <param> + <key>entags</key> + <value>True</value> + </param> + <param> + <key>gui_hint</key> + <value>0,0,1,1</value> + </param> + <param> + <key>tr_mode</key> + <value>qtgui.TRIG_MODE_TAG</value> + </param> + <param> + <key>tr_slope</key> + <value>qtgui.TRIG_SLOPE_POS</value> + </param> + <param> + <key>tr_level</key> + <value>1</value> + </param> + <param> + <key>tr_delay</key> + <value>0.1</value> + </param> + <param> + <key>tr_chan</key> + <value>0</value> + </param> + <param> + <key>tr_tag</key> + <value>time_est</value> + </param> + <param> + <key>ctrlpanel</key> + <value>False</value> + </param> + <param> + <key>legend</key> + <value>True</value> + </param> + <param> + <key>label1</key> + <value></value> + </param> + <param> + <key>width1</key> + <value>1</value> + </param> + <param> + <key>color1</key> + <value>"blue"</value> + </param> + <param> + <key>style1</key> + <value>1</value> + </param> + <param> + <key>marker1</key> + <value>-1</value> + </param> + <param> + <key>alpha1</key> + <value>1.0</value> + </param> + <param> + <key>label2</key> + <value></value> + </param> + <param> + <key>width2</key> + <value>1</value> + </param> + <param> + <key>color2</key> + <value>"red"</value> + </param> + <param> + <key>style2</key> + <value>1</value> + </param> + <param> + <key>marker2</key> + <value>-1</value> + </param> + <param> + <key>alpha2</key> + <value>1.0</value> + </param> + <param> + <key>label3</key> + <value></value> + </param> + <param> + <key>width3</key> + <value>1</value> + </param> + <param> + <key>color3</key> + <value>"green"</value> + </param> + <param> + <key>style3</key> + <value>1</value> + </param> + <param> + <key>marker3</key> + <value>-1</value> + </param> + <param> + <key>alpha3</key> + <value>1.0</value> + </param> + <param> + <key>label4</key> + <value></value> + </param> + <param> + <key>width4</key> + <value>1</value> + </param> + <param> + <key>color4</key> + <value>"black"</value> + </param> + <param> + <key>style4</key> + <value>1</value> + </param> + <param> + <key>marker4</key> + <value>-1</value> + </param> + <param> + <key>alpha4</key> + <value>1.0</value> + </param> + <param> + <key>label5</key> + <value></value> + </param> + <param> + <key>width5</key> + <value>1</value> + </param> + <param> + <key>color5</key> + <value>"cyan"</value> + </param> + <param> + <key>style5</key> + <value>1</value> + </param> + <param> + <key>marker5</key> + <value>-1</value> + </param> + <param> + <key>alpha5</key> + <value>1.0</value> + </param> + <param> + <key>label6</key> + <value></value> + </param> + <param> + <key>width6</key> + <value>1</value> + </param> + <param> + <key>color6</key> + <value>"magenta"</value> + </param> + <param> + <key>style6</key> + <value>1</value> + </param> + <param> + <key>marker6</key> + <value>-1</value> + </param> + <param> + <key>alpha6</key> + <value>1.0</value> + </param> + <param> + <key>label7</key> + <value></value> + </param> + <param> + <key>width7</key> + <value>1</value> + </param> + <param> + <key>color7</key> + <value>"yellow"</value> + </param> + <param> + <key>style7</key> + <value>1</value> + </param> + <param> + <key>marker7</key> + <value>-1</value> + </param> + <param> + <key>alpha7</key> + <value>1.0</value> + </param> + <param> + <key>label8</key> + <value></value> + </param> + <param> + <key>width8</key> + <value>1</value> + </param> + <param> + <key>color8</key> + <value>"dark red"</value> + </param> + <param> + <key>style8</key> + <value>1</value> + </param> + <param> + <key>marker8</key> + <value>-1</value> + </param> + <param> + <key>alpha8</key> + <value>1.0</value> + </param> + <param> + <key>label9</key> + <value></value> + </param> + <param> + <key>width9</key> + <value>1</value> + </param> + <param> + <key>color9</key> + <value>"dark green"</value> + </param> + <param> + <key>style9</key> + <value>1</value> + </param> + <param> + <key>marker9</key> + <value>-1</value> + </param> + <param> + <key>alpha9</key> + <value>1.0</value> + </param> + <param> + <key>label10</key> + <value></value> + </param> + <param> + <key>width10</key> + <value>1</value> + </param> + <param> + <key>color10</key> + <value>"blue"</value> + </param> + <param> + <key>style10</key> + <value>1</value> + </param> + <param> + <key>marker10</key> + <value>-1</value> + </param> + <param> + <key>alpha10</key> + <value>1.0</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(1398, 370)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable_constellation</key> + <param> + <key>id</key> + <value>constel</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>sym_map</key> + <value>[0,1]</value> + </param> + <param> + <key>const_points</key> + <value>[1,-1]</value> + </param> + <param> + <key>rot_sym</key> + <value>2</value> + </param> + <param> + <key>dims</key> + <value>1</value> + </param> + <param> + <key>precision</key> + <value>8</value> + </param> + <param> + <key>soft_dec_lut</key> + <value>None</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(1237, 27)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable_qtgui_range</key> + <param> + <key>id</key> + <value>freq_offset</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>label</key> + <value>Frequency Offset</value> + </param> + <param> + <key>value</key> + <value>0</value> + </param> + <param> + <key>start</key> + <value>-0.001</value> + </param> + <param> + <key>stop</key> + <value>0.001</value> + </param> + <param> + <key>step</key> + <value>0.00002</value> + </param> + <param> + <key>widget</key> + <value>slider</value> + </param> + <param> + <key>orient</key> + <value>Qt.Horizontal</value> + </param> + <param> + <key>min_len</key> + <value>200</value> + </param> + <param> + <key>gui_hint</key> + <value>4,0,1,1</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(808, 7)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>qtgui_const_sink_x</key> + <param> + <key>id</key> + <value>qtgui_const_sink_x_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>name</key> + <value></value> + </param> + <param> + <key>size</key> + <value>(len(preamble)+payload_size)*8</value> + </param> + <param> + <key>grid</key> + <value>False</value> + </param> + <param> + <key>autoscale</key> + <value>False</value> + </param> + <param> + <key>ymin</key> + <value>-2</value> + </param> + <param> + <key>ymax</key> + <value>2</value> + </param> + <param> + <key>xmin</key> + <value>-2</value> + </param> + <param> + <key>xmax</key> + <value>2</value> + </param> + <param> + <key>nconnections</key> + <value>1</value> + </param> + <param> + <key>update_time</key> + <value>0.10</value> + </param> + <param> + <key>gui_hint</key> + <value>0,1,1,1</value> + </param> + <param> + <key>tr_mode</key> + <value>qtgui.TRIG_MODE_TAG</value> + </param> + <param> + <key>tr_slope</key> + <value>qtgui.TRIG_SLOPE_POS</value> + </param> + <param> + <key>tr_level</key> + <value>0</value> + </param> + <param> + <key>tr_chan</key> + <value>0</value> + </param> + <param> + <key>tr_tag</key> + <value>time_est</value> + </param> + <param> + <key>legend</key> + <value>True</value> + </param> + <param> + <key>label1</key> + <value></value> + </param> + <param> + <key>width1</key> + <value>1</value> + </param> + <param> + <key>color1</key> + <value>"blue"</value> + </param> + <param> + <key>style1</key> + <value>0</value> + </param> + <param> + <key>marker1</key> + <value>0</value> + </param> + <param> + <key>alpha1</key> + <value>1.0</value> + </param> + <param> + <key>label2</key> + <value></value> + </param> + <param> + <key>width2</key> + <value>1</value> + </param> + <param> + <key>color2</key> + <value>"red"</value> + </param> + <param> + <key>style2</key> + <value>0</value> + </param> + <param> + <key>marker2</key> + <value>0</value> + </param> + <param> + <key>alpha2</key> + <value>1.0</value> + </param> + <param> + <key>label3</key> + <value></value> + </param> + <param> + <key>width3</key> + <value>1</value> + </param> + <param> + <key>color3</key> + <value>"red"</value> + </param> + <param> + <key>style3</key> + <value>0</value> + </param> + <param> + <key>marker3</key> + <value>0</value> + </param> + <param> + <key>alpha3</key> + <value>1.0</value> + </param> + <param> + <key>label4</key> + <value></value> + </param> + <param> + <key>width4</key> + <value>1</value> + </param> + <param> + <key>color4</key> + <value>"red"</value> + </param> + <param> + <key>style4</key> + <value>0</value> + </param> + <param> + <key>marker4</key> + <value>0</value> + </param> + <param> + <key>alpha4</key> + <value>1.0</value> + </param> + <param> + <key>label5</key> + <value></value> + </param> + <param> + <key>width5</key> + <value>1</value> + </param> + <param> + <key>color5</key> + <value>"red"</value> + </param> + <param> + <key>style5</key> + <value>0</value> + </param> + <param> + <key>marker5</key> + <value>0</value> + </param> + <param> + <key>alpha5</key> + <value>1.0</value> + </param> + <param> + <key>label6</key> + <value></value> + </param> + <param> + <key>width6</key> + <value>1</value> + </param> + <param> + <key>color6</key> + <value>"red"</value> + </param> + <param> + <key>style6</key> + <value>0</value> + </param> + <param> + <key>marker6</key> + <value>0</value> + </param> + <param> + <key>alpha6</key> + <value>1.0</value> + </param> + <param> + <key>label7</key> + <value></value> + </param> + <param> + <key>width7</key> + <value>1</value> + </param> + <param> + <key>color7</key> + <value>"red"</value> + </param> + <param> + <key>style7</key> + <value>0</value> + </param> + <param> + <key>marker7</key> + <value>0</value> + </param> + <param> + <key>alpha7</key> + <value>1.0</value> + </param> + <param> + <key>label8</key> + <value></value> + </param> + <param> + <key>width8</key> + <value>1</value> + </param> + <param> + <key>color8</key> + <value>"red"</value> + </param> + <param> + <key>style8</key> + <value>0</value> + </param> + <param> + <key>marker8</key> + <value>0</value> + </param> + <param> + <key>alpha8</key> + <value>1.0</value> + </param> + <param> + <key>label9</key> + <value></value> + </param> + <param> + <key>width9</key> + <value>1</value> + </param> + <param> + <key>color9</key> + <value>"red"</value> + </param> + <param> + <key>style9</key> + <value>0</value> + </param> + <param> + <key>marker9</key> + <value>0</value> + </param> + <param> + <key>alpha9</key> + <value>1.0</value> + </param> + <param> + <key>label10</key> + <value></value> + </param> + <param> + <key>width10</key> + <value>1</value> + </param> + <param> + <key>color10</key> + <value>"red"</value> + </param> + <param> + <key>style10</key> + <value>0</value> + </param> + <param> + <key>marker10</key> + <value>0</value> + </param> + <param> + <key>alpha10</key> + <value>1.0</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(1399, 283)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_complex_to_mag</key> + <param> + <key>id</key> + <value>blocks_complex_to_mag_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(1235, 149)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_complex_to_float</key> + <param> + <key>id</key> + <value>blocks_complex_to_float_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(1235, 194)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>import</key> + <param> + <key>id</key> + <value>import_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>import</key> + <value>import scipy</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(181, 16)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>import</key> + <param> + <key>id</key> + <value>import_0_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>import</key> + <value>import random</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(176, 147)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_vector_source_x</key> + <param> + <key>id</key> + <value>blocks_vector_source_x_0_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>byte</value> + </param> + <param> + <key>vector</key> + <value>preamble+data</value> + </param> + <param> + <key>tags</key> + <value>[]</value> + </param> + <param> + <key>repeat</key> + <value>True</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(15, 165)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>digital_constellation_modulator</key> + <param> + <key>id</key> + <value>digital_constellation_modulator_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>constellation</key> + <value>constel</value> + </param> + <param> + <key>differential</key> + <value>False</value> + </param> + <param> + <key>samples_per_symbol</key> + <value>sps</value> + </param> + <param> + <key>excess_bw</key> + <value>eb</value> + </param> + <param> + <key>verbose</key> + <value>False</value> + </param> + <param> + <key>log</key> + <value>False</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(312, 166)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_stream_mux</key> + <param> + <key>id</key> + <value>blocks_stream_mux_0_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>lengths</key> + <value>(len(preamble)+len(data))*8*sps, gap</value> + </param> + <param> + <key>num_inputs</key> + <value>2</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(568, 288)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>qtgui_time_sink_x</key> + <param> + <key>id</key> + <value>qtgui_time_sink_x_1</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>float</value> + </param> + <param> + <key>name</key> + <value></value> + </param> + <param> + <key>ylabel</key> + <value>Amplitude</value> + </param> + <param> + <key>yunit</key> + <value>""</value> + </param> + <param> + <key>size</key> + <value>80000</value> + </param> + <param> + <key>srate</key> + <value>samp_rate</value> + </param> + <param> + <key>grid</key> + <value>False</value> + </param> + <param> + <key>autoscale</key> + <value>False</value> + </param> + <param> + <key>ymin</key> + <value>-200</value> + </param> + <param> + <key>ymax</key> + <value>400</value> + </param> + <param> + <key>nconnections</key> + <value>3</value> + </param> + <param> + <key>update_time</key> + <value>0.10</value> + </param> + <param> + <key>entags</key> + <value>True</value> + </param> + <param> + <key>gui_hint</key> + <value>1,0,1,2</value> + </param> + <param> + <key>tr_mode</key> + <value>qtgui.TRIG_MODE_NORM</value> + </param> + <param> + <key>tr_slope</key> + <value>qtgui.TRIG_SLOPE_POS</value> + </param> + <param> + <key>tr_level</key> + <value>100</value> + </param> + <param> + <key>tr_delay</key> + <value>0</value> + </param> + <param> + <key>tr_chan</key> + <value>0</value> + </param> + <param> + <key>tr_tag</key> + <value>""</value> + </param> + <param> + <key>ctrlpanel</key> + <value>False</value> + </param> + <param> + <key>legend</key> + <value>True</value> + </param> + <param> + <key>label1</key> + <value>|corr|^2</value> + </param> + <param> + <key>width1</key> + <value>1</value> + </param> + <param> + <key>color1</key> + <value>"blue"</value> + </param> + <param> + <key>style1</key> + <value>1</value> + </param> + <param> + <key>marker1</key> + <value>-1</value> + </param> + <param> + <key>alpha1</key> + <value>1.0</value> + </param> + <param> + <key>label2</key> + <value>Re{corr}</value> + </param> + <param> + <key>width2</key> + <value>1</value> + </param> + <param> + <key>color2</key> + <value>"red"</value> + </param> + <param> + <key>style2</key> + <value>1</value> + </param> + <param> + <key>marker2</key> + <value>-1</value> + </param> + <param> + <key>alpha2</key> + <value>1.0</value> + </param> + <param> + <key>label3</key> + <value>Im{corr}</value> + </param> + <param> + <key>width3</key> + <value>1</value> + </param> + <param> + <key>color3</key> + <value>"green"</value> + </param> + <param> + <key>style3</key> + <value>1</value> + </param> + <param> + <key>marker3</key> + <value>-1</value> + </param> + <param> + <key>alpha3</key> + <value>1.0</value> + </param> + <param> + <key>label4</key> + <value></value> + </param> + <param> + <key>width4</key> + <value>1</value> + </param> + <param> + <key>color4</key> + <value>"black"</value> + </param> + <param> + <key>style4</key> + <value>1</value> + </param> + <param> + <key>marker4</key> + <value>-1</value> + </param> + <param> + <key>alpha4</key> + <value>1.0</value> + </param> + <param> + <key>label5</key> + <value></value> + </param> + <param> + <key>width5</key> + <value>1</value> + </param> + <param> + <key>color5</key> + <value>"cyan"</value> + </param> + <param> + <key>style5</key> + <value>1</value> + </param> + <param> + <key>marker5</key> + <value>-1</value> + </param> + <param> + <key>alpha5</key> + <value>1.0</value> + </param> + <param> + <key>label6</key> + <value></value> + </param> + <param> + <key>width6</key> + <value>1</value> + </param> + <param> + <key>color6</key> + <value>"magenta"</value> + </param> + <param> + <key>style6</key> + <value>1</value> + </param> + <param> + <key>marker6</key> + <value>-1</value> + </param> + <param> + <key>alpha6</key> + <value>1.0</value> + </param> + <param> + <key>label7</key> + <value></value> + </param> + <param> + <key>width7</key> + <value>1</value> + </param> + <param> + <key>color7</key> + <value>"yellow"</value> + </param> + <param> + <key>style7</key> + <value>1</value> + </param> + <param> + <key>marker7</key> + <value>-1</value> + </param> + <param> + <key>alpha7</key> + <value>1.0</value> + </param> + <param> + <key>label8</key> + <value></value> + </param> + <param> + <key>width8</key> + <value>1</value> + </param> + <param> + <key>color8</key> + <value>"dark red"</value> + </param> + <param> + <key>style8</key> + <value>1</value> + </param> + <param> + <key>marker8</key> + <value>-1</value> + </param> + <param> + <key>alpha8</key> + <value>1.0</value> + </param> + <param> + <key>label9</key> + <value></value> + </param> + <param> + <key>width9</key> + <value>1</value> + </param> + <param> + <key>color9</key> + <value>"dark green"</value> + </param> + <param> + <key>style9</key> + <value>1</value> + </param> + <param> + <key>marker9</key> + <value>-1</value> + </param> + <param> + <key>alpha9</key> + <value>1.0</value> + </param> + <param> + <key>label10</key> + <value></value> + </param> + <param> + <key>width10</key> + <value>1</value> + </param> + <param> + <key>color10</key> + <value>"blue"</value> + </param> + <param> + <key>style10</key> + <value>1</value> + </param> + <param> + <key>marker10</key> + <value>-1</value> + </param> + <param> + <key>alpha10</key> + <value>1.0</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(1433, 160)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable_modulate_vector</key> + <param> + <key>id</key> + <value>modulated_sync_word</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>mod</key> + <value>rxmod</value> + </param> + <param> + <key>data</key> + <value>preamble</value> + </param> + <param> + <key>taps</key> + <value>[1]</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(8, 491)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>digital_corr_est_cc</key> + <param> + <key>id</key> + <value>digital_corr_est_cc_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>symbols</key> + <value>modulated_sync_word</value> + </param> + <param> + <key>sps</key> + <value>sps</value> + </param> + <param> + <key>mark_delay</key> + <value>1</value> + </param> + <param> + <key>threshold</key> + <value>0.9</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(972, 174)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <connection> + <source_block_id>digital_costas_loop_cc_0</source_block_id> + <sink_block_id>qtgui_time_sink_x_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>digital_costas_loop_cc_0</source_block_id> + <sink_block_id>digital_constellation_decoder_cb_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>blocks_complex_to_float_0</source_block_id> + <sink_block_id>qtgui_time_sink_x_1</sink_block_id> + <source_key>0</source_key> + <sink_key>1</sink_key> + </connection> + <connection> + <source_block_id>blocks_complex_to_mag_0</source_block_id> + <sink_block_id>qtgui_time_sink_x_1</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>digital_corr_est_cc_0</source_block_id> + <sink_block_id>digital_pfb_clock_sync_xxx_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>blocks_null_source_0_0</source_block_id> + <sink_block_id>blocks_stream_mux_0_0</sink_block_id> + <source_key>0</source_key> + <sink_key>1</sink_key> + </connection> + <connection> + <source_block_id>blocks_stream_mux_0_0</source_block_id> + <sink_block_id>blocks_throttle_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>blocks_complex_to_float_0</source_block_id> + <sink_block_id>qtgui_time_sink_x_1</sink_block_id> + <source_key>1</source_key> + <sink_key>2</sink_key> + </connection> + <connection> + <source_block_id>channels_channel_model_0</source_block_id> + <sink_block_id>digital_corr_est_cc_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>digital_constellation_modulator_0</source_block_id> + <sink_block_id>blocks_stream_mux_0_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>digital_corr_est_cc_0</source_block_id> + <sink_block_id>blocks_complex_to_mag_0</sink_block_id> + <source_key>1</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>digital_corr_est_cc_0</source_block_id> + <sink_block_id>blocks_complex_to_float_0</sink_block_id> + <source_key>1</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>blocks_throttle_0</source_block_id> + <sink_block_id>channels_channel_model_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>digital_pfb_clock_sync_xxx_0</source_block_id> + <sink_block_id>digital_costas_loop_cc_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>blocks_delay_0</source_block_id> + <sink_block_id>qtgui_time_sink_x_0_1</sink_block_id> + <source_key>0</source_key> + <sink_key>1</sink_key> + </connection> + <connection> + <source_block_id>blocks_char_to_float_0_0</source_block_id> + <sink_block_id>blocks_sub_xx_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>blocks_delay_0</source_block_id> + <sink_block_id>blocks_sub_xx_0</sink_block_id> + <source_key>0</source_key> + <sink_key>1</sink_key> + </connection> + <connection> + <source_block_id>blocks_sub_xx_0</source_block_id> + <sink_block_id>qtgui_time_sink_x_0_1</sink_block_id> + <source_key>0</source_key> + <sink_key>2</sink_key> + </connection> + <connection> + <source_block_id>blocks_char_to_float_0_0</source_block_id> + <sink_block_id>qtgui_time_sink_x_0_1</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>blocks_stream_mux_0</source_block_id> + <sink_block_id>blocks_unpack_k_bits_bb_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>blocks_unpack_k_bits_bb_0</source_block_id> + <sink_block_id>blocks_char_to_float_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>blocks_null_source_0</source_block_id> + <sink_block_id>blocks_stream_mux_0</sink_block_id> + <source_key>0</source_key> + <sink_key>1</sink_key> + </connection> + <connection> + <source_block_id>blocks_char_to_float_0</source_block_id> + <sink_block_id>blocks_delay_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>digital_constellation_decoder_cb_0</source_block_id> + <sink_block_id>blocks_char_to_float_0_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>digital_costas_loop_cc_0</source_block_id> + <sink_block_id>qtgui_const_sink_x_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>blocks_vector_source_x_0_0</source_block_id> + <sink_block_id>digital_constellation_modulator_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> +</flow_graph> diff --git a/gr-digital/grc/digital_block_tree.xml b/gr-digital/grc/digital_block_tree.xml index f6dcceb6d0..6707a8e4db 100644 --- a/gr-digital/grc/digital_block_tree.xml +++ b/gr-digital/grc/digital_block_tree.xml @@ -1,6 +1,6 @@ <?xml version="1.0"?> <!-- - Copyright 2011-2013 Free Software Foundation, Inc. + Copyright 2011-2015 Free Software Foundation, Inc. This file is part of GNU Radio @@ -63,6 +63,7 @@ <block>digital_constellation_receiver_cb</block> <block>variable_constellation</block> <block>variable_constellation_rect</block> + <block>variable_modulate_vector</block> </cat> <cat> <name>Packet Operators</name> @@ -120,6 +121,7 @@ <block>digital_mpsk_receiver_cc</block> <block>digital_pfb_clock_sync_xxx</block> <block>digital_pn_correlator_cc</block> + <block>digital_corr_est_cc</block> <block>digital_correlate_and_sync_cc</block> </cat> <cat> diff --git a/gr-digital/grc/digital_burst_shaper.xml b/gr-digital/grc/digital_burst_shaper.xml new file mode 100644 index 0000000000..5c0bc78d0a --- /dev/null +++ b/gr-digital/grc/digital_burst_shaper.xml @@ -0,0 +1,71 @@ +<?xml version="1.0"?> +<block> + <name>Burst Shaper</name> + <key>digital_burst_shaper_xx</key> + <category>Packet Operators</category> + <import>from gnuradio import digital</import> + <make>digital.burst_shaper_$(type.fcn)($window, $pre_padding, $post_padding, $insert_phasing, $length_tag_name)</make> + <param> + <name>Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Float</name> + <key>float</key> + <opt>fcn:ff</opt> + <opt>taps:float_vector</opt> + </option> + <option> + <name>Complex</name> + <key>complex</key> + <opt>fcn:cc</opt> + <opt>taps:complex_vector</opt> + </option> + </param> + <param> + <name>Window Taps</name> + <key>window</key> + <value>([])</value> + <type>$(type.taps)</type> + </param> + <param> + <name>Pre-padding Length</name> + <key>pre_padding</key> + <value>0</value> + <type>int</type> + </param> + <param> + <name>Post-padding Length</name> + <key>post_padding</key> + <value>0</value> + <type>int</type> + </param> + <param> + <name>Insert phasing symbols</name> + <key>insert_phasing</key> + <value>False</value> + <type>enum</type> + <option> + <name>No</name> + <key>False</key> + </option> + <option> + <name>Yes</name> + <key>True</key> + </option> + </param> + <param> + <name>Length Tag Name</name> + <key>length_tag_name</key> + <value>"packet_len"</value> + <type>string</type> + </param> + <sink> + <name>in</name> + <type>$type</type> + </sink> + <source> + <name>out</name> + <type>$type</type> + </source> +</block> diff --git a/gr-digital/grc/digital_corr_est_cc.xml b/gr-digital/grc/digital_corr_est_cc.xml new file mode 100644 index 0000000000..cb345e933f --- /dev/null +++ b/gr-digital/grc/digital_corr_est_cc.xml @@ -0,0 +1,50 @@ +<?xml version="1.0"?> +<block> + <name>Correlation Estimator</name> + <key>digital_corr_est_cc</key> + <import>from gnuradio import digital</import> + <make>digital.corr_est_cc($symbols, $sps, $mark_delay, $threshold)</make> + <callback>set_mark_delay($mark_delay)</callback> + <callback>set_theshold($threshold)</callback> + + <param> + <name>Symbols</name> + <key>symbols</key> + <type>complex_vector</type> + </param> + + <param> + <name>Samples per Symbol</name> + <key>sps</key> + <type>float</type> + </param> + + <param> + <name>Tag marking delay</name> + <key>mark_delay</key> + <type>int</type> + </param> + + <param> + <name>Threshold</name> + <key>threshold</key> + <value>0.9</value> + <type>float</type> + </param> + + <sink> + <name>in</name> + <type>complex</type> + </sink> + + <source> + <name>out</name> + <type>complex</type> + </source> + + <source> + <name>corr</name> + <type>complex</type> + <optional>1</optional> + </source> +</block> diff --git a/gr-digital/grc/digital_modulate_vector.xml b/gr-digital/grc/digital_modulate_vector.xml new file mode 100644 index 0000000000..91614dd3fd --- /dev/null +++ b/gr-digital/grc/digital_modulate_vector.xml @@ -0,0 +1,34 @@ +<?xml version="1.0"?> +<!-- +################################################### +# modulate_vector_bc +################################################### + --> +<block> + <name>Modulate Vector</name> + <key>variable_modulate_vector</key> + <category>Modulators</category> + <import>from gnuradio import digital</import> + <var_make>self.$(id) = $(id) = digital.modulate_vector_bc($mod .to_basic_block(), $data, $taps)</var_make> + <var_value>digital.modulate_vector_bc($mod .to_basic_block(), $data, $taps)</var_value> + <make></make> + + <param> + <name>Modulator</name> + <key>mod</key> + <value></value> + <type>raw</type> + </param> + <param> + <name>Data vector</name> + <key>data</key> + <value></value> + <type>int_vector</type> + </param> + <param> + <name>Filter taps</name> + <key>taps</key> + <value></value> + <type>float_vector</type> + </param> +</block> diff --git a/gr-digital/grc/digital_msk_timing_recovery_cc.xml b/gr-digital/grc/digital_msk_timing_recovery_cc.xml new file mode 100644 index 0000000000..cda780d685 --- /dev/null +++ b/gr-digital/grc/digital_msk_timing_recovery_cc.xml @@ -0,0 +1,49 @@ +<?xml version="1.0"?> +<block> + <name>MSK Timing Recovery</name> + <key>digital_msk_timing_recovery_cc</key> + <import>from gnuradio import digital</import> + <make>digital.msk_timing_recovery_cc($sps, $gain, $limit, $osps)</make> + <callback>set_gain($gain)</callback> + <callback>set_sps($sps)</callback> + <callback>set_limit($limit)</callback> + <param> + <name>Gain</name> + <key>gain</key> + <type>float</type> + </param> + <param> + <name>Samples per symbol</name> + <key>sps</key> + <type>float</type> + </param> + <param> + <name>Error limit</name> + <key>limit</key> + <type>float</type> + </param> + <param> + <name>Output samples per symbol</name> + <key>osps</key> + <type>int</type> + </param> + <sink> + <name>in</name> + <type>complex</type> + </sink> + <source> + <name>out</name> + <type>complex</type> + </source> + <source> + <name>err</name> + <type>float</type> + <optional>1</optional> + </source> + <source> + <name>omega</name> + <type>float</type> + <optional>1</optional> + </source> + +</block> diff --git a/gr-digital/include/gnuradio/digital/CMakeLists.txt b/gr-digital/include/gnuradio/digital/CMakeLists.txt index c39b12bed2..d8fe2b6c4d 100644 --- a/gr-digital/include/gnuradio/digital/CMakeLists.txt +++ b/gr-digital/include/gnuradio/digital/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright 2011-2014 Free Software Foundation, Inc. +# Copyright 2011-2015 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -22,6 +22,7 @@ ####################################################################### include(GrMiscUtils) GR_EXPAND_X_H(digital chunks_to_symbols_XX bf bc sf sc if ic) +GR_EXPAND_X_H(digital burst_shaper_XX cc ff) add_custom_target(digital_generated_includes DEPENDS ${generated_includes} @@ -42,6 +43,7 @@ install(FILES constellation_decoder_cb.h constellation_receiver_cb.h constellation_soft_decoder_cf.h + corr_est_cc.h correlate_access_code_bb.h correlate_access_code_tag_bb.h correlate_access_code_bb_ts.h @@ -69,9 +71,11 @@ install(FILES lms_dd_equalizer_cc.h map_bb.h metric_type.h + modulate_vector.h mpsk_receiver_cc.h mpsk_snr_est.h mpsk_snr_est_cc.h + msk_timing_recovery_cc.h ofdm_carrier_allocator_cvc.h ofdm_chanest_vcvc.h ofdm_cyclic_prefixer.h diff --git a/gr-digital/include/gnuradio/digital/burst_shaper_XX.h.t b/gr-digital/include/gnuradio/digital/burst_shaper_XX.h.t new file mode 100644 index 0000000000..fd7b69060e --- /dev/null +++ b/gr-digital/include/gnuradio/digital/burst_shaper_XX.h.t @@ -0,0 +1,123 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 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. + */ + +/* @WARNING@ */ + +#ifndef @GUARD_NAME@ +#define @GUARD_NAME@ + +#include <gnuradio/digital/api.h> +#include <gnuradio/block.h> + +namespace gr { + namespace digital { + + /*! + * \brief Burst shaper block for applying burst padding and ramping. + * \ingroup packet_operators_blk + * + * \details + * + * This block applies a configurable amount of zero padding before + * and/or after a burst indicated by tagged stream length tags. + * + * If phasing symbols are used, an alternating pattern of +1/-1 + * symbols of length ceil(N/2) will be inserted before and after + * each burst, where N is the length of the taps vector. The ramp- + * up/ramp-down shape will be applied to these phasing symbols. + * + * If phasing symbols are not used, the taper will be applied + * directly to the head and tail of each burst. + * + * Length tags will be updated to include the length of any added + * zero padding or phasing symbols and will be placed at the + * beginning of the modified tagged stream. Any other tags found at + * the same offset as a length tag will also be placed at the + * beginning of the modified tagged stream, since these tags are + * assumed to be associated with the burst rather than a specific + * sample. For example, if "tx_time" tags are used to control + * bursts, their offsets should be consistent with their associated + * burst's length tags. Tags at other offsets will be placed with + * the samples on which they were found. + * + * \li input: stream of @I_TYPE@ + * \li output: stream of @O_TYPE@ + */ + class DIGITAL_API @NAME@ : virtual public block + { + public: + // gr::digital::@BASE_NAME@::sptr + typedef boost::shared_ptr<@BASE_NAME@> sptr; + + /*! + * Make a burst shaper block. + * + * \param taps: vector of window taper taps; the first ceil(N/2) + * items are the up flank and the last ceil(N/2) + * items are the down flank. If taps.size() is odd, + * the middle tap will be used as the last item of + * the up flank and first item of the down flank. + * \param pre_padding: number of zero samples to insert before + * the burst. + * \param post_padding: number of zero samples to append after + * the burst. + * \param insert_phasing: if true, insert alternating +1/-1 + * pattern of length ceil(N/2) before and + * after the burst and apply ramp up and + * ramp down taps, respectively, to the + * inserted patterns instead of the head + * and tail items of the burst. + * \param length_tag_name: the name of the tagged stream length + * tag key. + */ + static sptr make(const std::vector<@O_TYPE@> &taps, + int pre_padding=0, int post_padding=0, + bool insert_phasing=false, + const std::string &length_tag_name="packet_len"); + + /*! + * Returns the amount of zero padding inserted before each burst. + */ + virtual int pre_padding() const = 0; + + /*! + * Returns the amount of zero padding inserted after each burst. + */ + virtual int post_padding() const = 0; + + /*! + * Returns the total amount of zero padding and phasing symbols + * inserted before each burst. + */ + virtual int prefix_length() const = 0; + + /*! + * Returns the total amount of zero padding and phasing symbols + * inserted after each burst. + */ + virtual int suffix_length() const = 0; + }; + + } // namespace digital +} // namespace gr + +#endif /* @GUARD_NAME@ */ diff --git a/gr-digital/include/gnuradio/digital/corr_est_cc.h b/gr-digital/include/gnuradio/digital/corr_est_cc.h new file mode 100644 index 0000000000..e8211cf60b --- /dev/null +++ b/gr-digital/include/gnuradio/digital/corr_est_cc.h @@ -0,0 +1,118 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 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_DIGITAL_CORR_EST_CC_CC_H +#define INCLUDED_DIGITAL_CORR_EST_CC_CC_H + +#include <gnuradio/digital/api.h> +#include <gnuradio/sync_block.h> + +namespace gr { + namespace digital { + + /*! + * \brief Correlate stream with a pre-defined sequence and estimate peak + * \ingroup synchronizers_blk + * + * \details + * Input: + * \li Stream of complex samples. + * + * Output: + * \li Output stream that just passes the input complex samples + * \li tag 'phase_est': estimate of phase offset + * \li tag 'time_est': estimate of symbol timing offset + * \li tag 'corr_est': the correlation value of the estimates + * \li tag 'corr_start': the start sample of the correlation and the value + * + * \li Optional 2nd output stream providing the advanced correlator output + * + * This block is designed to search for a sync word by correlation + * and uses the results of the correlation to get a time and phase + * offset estimate. These estimates are passed downstream as + * stream tags for use by follow-on synchronization blocks. + * + * The sync word is provided as a set of symbols along with a + * baseband matched filter which we use to create the filtered and + * upsampled symbols that we will receive over-the-air. + * + * The phase_est tag can be used by downstream blocks to adjust + * their phase estimatopm/correction loops, and is currently + * implemented by the gr::digital::costas_loop_cc block. + * + * The time_est tag can be used to adjust the sampling timing + * estimate of any downstream synchronization blocks and is + * currently implemented by the gr::digital::pfb_clock_sync_ccf + * block. + * + * The caller must provide a "time_est" and "phase_est" tag + * marking delay from the start of the correlated signal segment, + * in order to mark the proper point in the sync word for + * downstream synchronization blocks. Generally this block cannot + * know where the actual sync word symbols are located relative to + * "corr_start", given that some modulations have pulses with + * intentional ISI. The user should manually examine the primary + * output and the "corr_start" tag postition to determine the + * required tag delay settings for the particular modulation, + * sync word, and downstream blocks used. + * + * For a discussion of the properties of complex correlations, + * with respect to signal processing, see: + * Marple, Jr., S. L., "Estimating Group Delay and Phase Delay + * via Discrete-Time 'Analytic' Cross-Correlation, _IEEE_Transcations_ + * _on_Signal_Processing_, Volume 47, No. 9, September 1999 + * + */ + class DIGITAL_API corr_est_cc : virtual public sync_block + { + public: + typedef boost::shared_ptr<corr_est_cc> sptr; + + /*! + * Make a block that correlates against the \p symbols vector + * and outputs a phase and symbol timing estimate. + * + * \param symbols Set of symbols to correlate against (e.g., a + * sync word). + * \param sps Samples per symbol + * \param mark_delay tag marking delay in samples after the + * corr_start tag + * \param threshold Threshold of correlator, relative to a 100% + * correlation (1.0). Default is 0.9. + */ + static sptr make(const std::vector<gr_complex> &symbols, + float sps, unsigned int mark_delay, float threshold=0.9); + + virtual std::vector<gr_complex> symbols() const = 0; + virtual void set_symbols(const std::vector<gr_complex> &symbols) = 0; + + virtual unsigned int mark_delay() const = 0; + virtual void set_mark_delay(unsigned int mark_delay) = 0; + + virtual float threshold() const = 0; + virtual void set_threshold(float threshold) = 0; + }; + + } // namespace digital +} // namespace gr + +#endif /* INCLUDED_DIGITAL_CORR_EST_CC_H */ diff --git a/gr-digital/include/gnuradio/digital/modulate_vector.h b/gr-digital/include/gnuradio/digital/modulate_vector.h new file mode 100644 index 0000000000..6083099a89 --- /dev/null +++ b/gr-digital/include/gnuradio/digital/modulate_vector.h @@ -0,0 +1,70 @@ +/* + * Copyright 2015 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_DIGITAL_MODULATE_VECTOR_H +#define INCLUDED_DIGITAL_MODULATE_VECTOR_H + +#include <gnuradio/digital/api.h> +#include <gnuradio/types.h> + +namespace gr { + namespace digital { + + /*! + * \brief Modulate a vector of data and apply a shaping filter. + * + * \p modulator: Pointer to a byte-to-complex modulator block. + * \p data: Vector of bytes to modulate into symbols. + * \p taps: Post-modulation symbol shaping filter taps. + * + * \details + * This function modulates the input vector and applies a + * symbol shaping filter. It is intended for use with the + * corr_est_cc block as the symbol stream to correlate + * against. + * + * Any differential encoding or other data coding must be + * performed on the input vector before this modulation + * operation. + * + * Be aware that the format of the incoming data must match + * the format the modulator block is expecting. GNURadio + * modulator blocks are inconsistent in their data type + * expectations. For instance, cpmmod_bc expects unpacked, + * signed bytes in (-1, 1), while gmsk_mod expects packed, + * unsigned bytes in (0, 1). In other words, the output of + * gmsk_mod given the input vector [0xaa, 0x00] is equivalent + * to the output of cpmmod_bc given the input vector + * [1,255,1,255,1,255,1,255,255,255,255,255,255,255,255,255] + * + * Please check the documentation or source of the modulator + * before using this function. + * + */ + DIGITAL_API std::vector<gr_complex> + modulate_vector_bc(basic_block_sptr modulator, + std::vector<uint8_t> data, + std::vector<float> taps); + + } /* namespace digital */ +} /* namespace gr */ + +#endif /* INCLUDED_DIGITAL_MODULATE_VECTOR_H */ diff --git a/gr-digital/include/gnuradio/digital/msk_timing_recovery_cc.h b/gr-digital/include/gnuradio/digital/msk_timing_recovery_cc.h new file mode 100644 index 0000000000..770bd91da1 --- /dev/null +++ b/gr-digital/include/gnuradio/digital/msk_timing_recovery_cc.h @@ -0,0 +1,76 @@ +/* -*- 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_DIGITAL_MSK_TIMING_RECOVERY_CC_H +#define INCLUDED_DIGITAL_MSK_TIMING_RECOVERY_CC_H + +#include <gnuradio/digital/api.h> +#include <gnuradio/block.h> + +namespace gr { + namespace digital { + + /*! + * \brief MSK/GMSK timing recovery + * \ingroup synchronizers_blk + * + * This block performs timing synchronization on CPM modulations using a + * fourth-order nonlinearity feedback method which is non-data-aided. The + * block does not require prior phase synchronization but is relatively + * sensitive to frequency offset (keep offset to 0.1x symbol rate). + * + * For details on the algorithm, see: + * A.N. D'Andrea, U. Mengali, R. Reggiannini: A digital approach to clock + * recovery in generalized minimum shift keying. IEEE Transactions on + * Vehicular Technology, Vol. 39, Issue 3. + */ + class DIGITAL_API msk_timing_recovery_cc : virtual public gr::block + { + public: + typedef boost::shared_ptr<msk_timing_recovery_cc> sptr; + + /*! + * \brief Make an MSK timing recovery block. + * + * \param sps: Samples per symbol + * \param gain: Loop gain of timing error filter (try 0.05) + * \param limit: Relative limit of timing error (try 0.1 for 10% error max) + * \param osps: Output samples per symbol + * + */ + static sptr make(float sps, float gain, float limit, int osps); + + virtual void set_gain(float gain)=0; + virtual float get_gain(void)=0; + + virtual void set_limit(float limit)=0; + virtual float get_limit(void)=0; + + virtual void set_sps(float sps)=0; + virtual float get_sps(void)=0; + }; + + } // namespace digital +} // namespace gr + +#endif /* INCLUDED_DIGITAL_MSK_TIMING_RECOVERY_CC_H */ + diff --git a/gr-digital/lib/CMakeLists.txt b/gr-digital/lib/CMakeLists.txt index eb1008423b..daa577f56f 100644 --- a/gr-digital/lib/CMakeLists.txt +++ b/gr-digital/lib/CMakeLists.txt @@ -45,6 +45,7 @@ endif(ENABLE_GR_CTRLPORT) ######################################################################## include(GrMiscUtils) GR_EXPAND_X_CC_H(digital chunks_to_symbols_XX_impl bf bc sf sc if ic) +GR_EXPAND_X_CC_H(digital burst_shaper_XX_impl cc ff) ######################################################################## # Setup library @@ -60,6 +61,7 @@ list(APPEND digital_sources constellation_decoder_cb_impl.cc constellation_receiver_cb_impl.cc constellation_soft_decoder_cf_impl.cc + corr_est_cc_impl.cc correlate_access_code_bb_impl.cc correlate_access_code_tag_bb_impl.cc correlate_access_code_bb_ts_impl.cc @@ -85,9 +87,11 @@ list(APPEND digital_sources kurtotic_equalizer_cc_impl.cc lms_dd_equalizer_cc_impl.cc map_bb_impl.cc + modulate_vector.cc mpsk_receiver_cc_impl.cc mpsk_snr_est.cc mpsk_snr_est_cc_impl.cc + msk_timing_recovery_cc_impl.cc ofdm_carrier_allocator_cvc_impl.cc ofdm_chanest_vcvc_impl.cc ofdm_cyclic_prefixer_impl.cc diff --git a/gr-digital/lib/burst_shaper_XX_impl.cc.t b/gr-digital/lib/burst_shaper_XX_impl.cc.t new file mode 100644 index 0000000000..85add49115 --- /dev/null +++ b/gr-digital/lib/burst_shaper_XX_impl.cc.t @@ -0,0 +1,353 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 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. + */ + +/* @WARNING@ */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <boost/format.hpp> +#include <gnuradio/io_signature.h> +#include <volk/volk.h> +#include "@IMPL_NAME@.h" + +#ifndef VOLK_MULT_gr_complex +#define VOLK_MULT_gr_complex volk_32fc_x2_multiply_32fc +#endif +#ifndef VOLK_MULT_float +#define VOLK_MULT_float volk_32f_x2_multiply_32f +#endif + +namespace gr { + namespace digital { + + @BASE_NAME@::sptr + @BASE_NAME@::make(const std::vector<@I_TYPE@> &taps, + int pre_padding, int post_padding, + bool insert_phasing, + const std::string &length_tag_name) + { + return gnuradio::get_initial_sptr + (new @IMPL_NAME@(taps, pre_padding, post_padding, + insert_phasing, length_tag_name)); + } + + @IMPL_NAME@::@IMPL_NAME@(const std::vector<@I_TYPE@> &taps, + int pre_padding, int post_padding, + bool insert_phasing, + const std::string &length_tag_name) + : gr::block("@BASE_NAME@", + gr::io_signature::make(1, 1, sizeof(@I_TYPE@)), + gr::io_signature::make(1, 1, sizeof(@O_TYPE@))), + d_up_ramp(taps.begin(), taps.begin() + taps.size()/2 + taps.size()%2), + d_down_ramp(taps.begin() + taps.size()/2, taps.end()), + d_nprepad(pre_padding), + d_npostpad(post_padding), + d_insert_phasing(insert_phasing), + d_length_tag_key(pmt::string_to_symbol(length_tag_name)), + d_ncopy(0), + d_limit(0), + d_index(0), + d_length_tag_offset(0), + d_finished(false), + d_state(STATE_WAIT) + { + assert(d_up_ramp.size() == d_down_ramp.size()); + + d_up_phasing.resize(d_up_ramp.size()); + d_down_phasing.resize(d_down_ramp.size()); + + @I_TYPE@ symbol; + for(unsigned int i = 0; i < d_up_ramp.size(); i++) { + symbol = (i%2 == 0) ? @I_TYPE@(1.0f) : @I_TYPE@(-1.0f); + d_up_phasing[i] = symbol * d_up_ramp[i]; + d_down_phasing[i] = symbol * d_down_ramp[i]; + } + + //set_relative_rate(1.0); + set_tag_propagation_policy(TPP_DONT); + } + + @IMPL_NAME@::~@IMPL_NAME@() + { + } + + void + @IMPL_NAME@::forecast(int noutput_items, + gr_vector_int &ninput_items_required) + { + ninput_items_required[0] = noutput_items; + } + + int + @IMPL_NAME@::general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const @I_TYPE@ *in = reinterpret_cast<const @I_TYPE@ *>(input_items[0]); + @O_TYPE@ *out = reinterpret_cast<@O_TYPE@ *>(output_items[0]); + + int nwritten = 0; + int nread = 0; + int nspace = 0; + int nskip = 0; + int curr_tag_index = 0; + + std::vector<tag_t> length_tags; + get_tags_in_window(length_tags, 0, 0, ninput_items[0], d_length_tag_key); + std::sort(length_tags.rbegin(), length_tags.rend(), tag_t::offset_compare); + + while((nwritten < noutput_items) && (nread < ninput_items[0])) { + if(d_finished) { + d_finished = false; + break; + } + nspace = noutput_items - nwritten; + switch(d_state) { + case(STATE_WAIT): + if(!length_tags.empty()) { + d_length_tag_offset = length_tags.back().offset; + curr_tag_index = (int)(d_length_tag_offset - nitems_read(0)); + d_ncopy = pmt::to_long(length_tags.back().value); + length_tags.pop_back(); + nskip = curr_tag_index - nread; + add_length_tag(nwritten); + propagate_tags(curr_tag_index, nwritten, 1, false); + enter_prepad(); + } + else { + nskip = ninput_items[0] - nread; + } + if(nskip > 0) { + GR_LOG_WARN(d_logger, + boost::format("Dropping %1% samples") % + nskip); + nread += nskip; + in += nskip; + } + break; + + case(STATE_PREPAD): + write_padding(out, nwritten, nspace); + if(d_index == d_limit) + enter_rampup(); + break; + + case(STATE_RAMPUP): + apply_ramp(out, in, nwritten, nread, nspace); + if(d_index == d_limit) + enter_copy(); + break; + + case(STATE_COPY): + copy_items(out, in, nwritten, nread, nspace); + if(d_index == d_limit) + enter_rampdown(); + break; + + case(STATE_RAMPDOWN): + apply_ramp(out, in, nwritten, nread, nspace); + if(d_index == d_limit) + enter_postpad(); + break; + + case(STATE_POSTPAD): + write_padding(out, nwritten, nspace); + if(d_index == d_limit) + enter_wait(); + break; + + default: + throw std::runtime_error("@BASE_NAME@: invalid state"); + } + } + + consume_each(nread); + + return nwritten; + } + + int + @IMPL_NAME@::prefix_length() const + { + return (d_insert_phasing) ? + d_nprepad + d_up_ramp.size() : d_nprepad; + } + + int + @IMPL_NAME@::suffix_length() const + { + return (d_insert_phasing) ? + d_npostpad + d_down_ramp.size() : d_npostpad; + } + + void + @IMPL_NAME@::write_padding(@O_TYPE@ *&dst, int &nwritten, int nspace) + { + int nprocess = std::min(d_limit - d_index, nspace); + std::memset(dst, 0x00, nprocess * sizeof(@O_TYPE@)); + dst += nprocess; + nwritten += nprocess; + d_index += nprocess; + } + + void + @IMPL_NAME@::copy_items(@O_TYPE@ *&dst, const @I_TYPE@ *&src, int &nwritten, + int &nread, int nspace) + { + int nprocess = std::min(d_limit - d_index, nspace); + propagate_tags(nread, nwritten, nprocess); + std::memcpy(dst, src, nprocess * sizeof(@O_TYPE@)); + dst += nprocess; + nwritten += nprocess; + src += nprocess; + nread += nprocess; + d_index += nprocess; + } + + void + @IMPL_NAME@::apply_ramp(@O_TYPE@ *&dst, const @I_TYPE@ *&src, int &nwritten, + int &nread, int nspace) + { + int nprocess = std::min(d_limit - d_index, nspace); + @O_TYPE@ *phasing; + const @O_TYPE@ *ramp; + + if(d_state == STATE_RAMPUP) { + phasing = &d_up_phasing[d_index]; + ramp = &d_up_ramp[d_index]; + } + else { + phasing = &d_down_phasing[d_index]; + ramp = &d_down_ramp[d_index]; + } + + if(d_insert_phasing) + std::memcpy(dst, phasing, nprocess * sizeof(@O_TYPE@)); + else { + propagate_tags(nread, nwritten, nprocess); + VOLK_MULT_@O_TYPE@(dst, src, ramp, nprocess); + src += nprocess; + nread += nprocess; + } + + dst += nprocess; + nwritten += nprocess; + d_index += nprocess; + } + + void + @IMPL_NAME@::add_length_tag(int offset) + { + add_item_tag(0, nitems_written(0) + offset, d_length_tag_key, + pmt::from_long(d_ncopy + prefix_length() + + suffix_length()), + pmt::string_to_symbol(name())); + } + + void + @IMPL_NAME@::propagate_tags(int in_offset, int out_offset, int count, bool skip) + { + uint64_t abs_start = nitems_read(0) + in_offset; + uint64_t abs_end = abs_start + count; + uint64_t abs_offset = nitems_written(0) + out_offset; + tag_t temp_tag; + + std::vector<tag_t> tags; + std::vector<tag_t>::iterator it; + + get_tags_in_range(tags, 0, abs_start, abs_end); + + for(it = tags.begin(); it != tags.end(); it++) { + if(!pmt::equal(it->key, d_length_tag_key)) { + if(skip && (it->offset == d_length_tag_offset)) + continue; + temp_tag = *it; + temp_tag.offset = abs_offset + it->offset - abs_start; + add_item_tag(0, temp_tag); + } + } + } + + void + @IMPL_NAME@::enter_wait() + { + d_finished = true; + d_index = 0; + d_state = STATE_WAIT; + } + + void + @IMPL_NAME@::enter_prepad() + { + d_limit = d_nprepad; + d_index = 0; + d_state = STATE_PREPAD; + } + + void + @IMPL_NAME@::enter_rampup() + { + if(d_insert_phasing) + d_limit = d_up_ramp.size(); + else + d_limit = std::min((size_t)(d_ncopy/2), d_up_ramp.size()); + d_index = 0; + d_state = STATE_RAMPUP; + } + + void + @IMPL_NAME@::enter_copy() + { + if(d_insert_phasing) + d_limit = d_ncopy; + else + d_limit = d_ncopy - std::min((size_t)((d_ncopy/2)*2), + d_up_ramp.size() + + d_down_ramp.size()); + d_index = 0; + d_state = STATE_COPY; + } + + void + @IMPL_NAME@::enter_rampdown() + { + if(d_insert_phasing) + d_limit = d_down_ramp.size(); + else + d_limit = std::min((size_t)(d_ncopy/2), d_down_ramp.size()); + d_index = 0; + d_state = STATE_RAMPDOWN; + } + + void + @IMPL_NAME@::enter_postpad() + { + d_limit = d_npostpad; + d_index = 0; + d_state = STATE_POSTPAD; + } + + } /* namespace digital */ +} /* namespace gr */ diff --git a/gr-digital/lib/burst_shaper_XX_impl.h.t b/gr-digital/lib/burst_shaper_XX_impl.h.t new file mode 100644 index 0000000000..99ad7fb08a --- /dev/null +++ b/gr-digital/lib/burst_shaper_XX_impl.h.t @@ -0,0 +1,90 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 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. + */ + +/* @WARNING@ */ + +#ifndef @GUARD_NAME@ +#define @GUARD_NAME@ + +#include <gnuradio/digital/@BASE_NAME@.h> + +namespace gr { + namespace digital { + + class @IMPL_NAME@ : public @BASE_NAME@ + { + protected: + enum state_t {STATE_WAIT, STATE_PREPAD, STATE_RAMPUP, + STATE_COPY, STATE_RAMPDOWN, STATE_POSTPAD}; + + private: + const std::vector<@O_TYPE@> d_up_ramp; + const std::vector<@O_TYPE@> d_down_ramp; + const int d_nprepad; + const int d_npostpad; + const bool d_insert_phasing; + const pmt::pmt_t d_length_tag_key; + std::vector<@O_TYPE@> d_up_phasing; + std::vector<@O_TYPE@> d_down_phasing; + int d_ncopy; + int d_limit; + int d_index; + uint64_t d_length_tag_offset; + bool d_finished; + state_t d_state; + + void write_padding(@O_TYPE@ *&dst, int &nwritten, int nspace); + void copy_items(@O_TYPE@ *&dst, const @I_TYPE@ *&src, int &nwritten, + int &nread, int nspace); + void apply_ramp(@O_TYPE@ *&dst, const @I_TYPE@ *&src, int &nwritten, + int &nread, int nspace); + void add_length_tag(int offset); + void propagate_tags(int in_offset, int out_offset, int count, bool skip=true); + void enter_wait(); + void enter_prepad(); + void enter_rampup(); + void enter_copy(); + void enter_rampdown(); + void enter_postpad(); + + public: + @IMPL_NAME@(const std::vector<@O_TYPE@> &taps, int pre_padding, + int post_padding, bool insert_phasing, + const std::string &length_tag_name); + ~@IMPL_NAME@(); + + void forecast(int noutput_items, gr_vector_int &ninput_items_required); + + int general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + int pre_padding() const { return d_nprepad; } + int post_padding() const { return d_npostpad; } + int prefix_length() const; + int suffix_length() const; + }; + + } // namespace digital +} // namespace gr + +#endif /* @GUARD_NAME@ */ diff --git a/gr-digital/lib/corr_est_cc_impl.cc b/gr-digital/lib/corr_est_cc_impl.cc new file mode 100644 index 0000000000..66645f6b5d --- /dev/null +++ b/gr-digital/lib/corr_est_cc_impl.cc @@ -0,0 +1,331 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 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 <gnuradio/io_signature.h> +#include <gnuradio/math.h> +#include "corr_est_cc_impl.h" +#include <volk/volk.h> +#include <boost/format.hpp> +#include <boost/math/special_functions/round.hpp> +#include <gnuradio/filter/pfb_arb_resampler.h> +#include <gnuradio/filter/firdes.h> + +namespace gr { + namespace digital { + + corr_est_cc::sptr + corr_est_cc::make(const std::vector<gr_complex> &symbols, + float sps, unsigned int mark_delay, + float threshold) + { + return gnuradio::get_initial_sptr + (new corr_est_cc_impl(symbols, sps, mark_delay, threshold)); + } + + corr_est_cc_impl::corr_est_cc_impl(const std::vector<gr_complex> &symbols, + float sps, unsigned int mark_delay, + float threshold) + : sync_block("corr_est_cc", + io_signature::make(1, 1, sizeof(gr_complex)), + io_signature::make(1, 2, sizeof(gr_complex))), + d_src_id(pmt::intern(alias())) + { + d_sps = sps; + + // Create time-reversed conjugate of symbols + d_symbols = symbols; + for(size_t i=0; i < d_symbols.size(); i++) { + d_symbols[i] = conj(d_symbols[i]); + } + std::reverse(d_symbols.begin(), d_symbols.end()); + + set_mark_delay(mark_delay); + set_threshold(threshold); + + // Correlation filter + d_filter = new kernel::fft_filter_ccc(1, d_symbols); + + // Per comments in gr-filter/include/gnuradio/filter/fft_filter.h, + // set the block output multiple to the FFT filter kernel's internal, + // assumed "nsamples", to ensure the scheduler always passes a + // proper number of samples. + int nsamples; + nsamples = d_filter->set_taps(d_symbols); + set_output_multiple(nsamples); + + // It looks like the kernel::fft_filter_ccc stashes a tail between + // calls, so that contains our filtering history (I think). The + // fft_filter_ccc block (which calls the kernel::fft_filter_ccc) sets + // the history to 1 (0 history items), so let's follow its lead. + //set_history(1); + + // We'll (ab)use the history for our own purposes of tagging back in time. + // Keep a history of the length of the sync word to delay for tagging. + set_history(d_symbols.size()+1); + + declare_sample_delay(1, 0); + declare_sample_delay(0, d_symbols.size()); + + // Setting the alignment multiple for volk causes problems with the + // expected behavior of setting the output multiple for the FFT filter. + // Don't set the alignment multiple. + //const int alignment_multiple = + // volk_get_alignment() / sizeof(gr_complex); + //set_alignment(std::max(1,alignment_multiple)); + + // In order to easily support the optional second output, + // don't deal with an unbounded max number of output items. + // For the common case of not using the optional second output, + // this ensures we optimally call the volk routines. + const size_t nitems = 24*1024; + set_max_noutput_items(nitems); + d_corr = (gr_complex *) + volk_malloc(sizeof(gr_complex)*nitems, volk_get_alignment()); + d_corr_mag = (float *) + volk_malloc(sizeof(float)*nitems, volk_get_alignment()); + } + + corr_est_cc_impl::~corr_est_cc_impl() + { + delete d_filter; + volk_free(d_corr); + volk_free(d_corr_mag); + } + + std::vector<gr_complex> + corr_est_cc_impl::symbols() const + { + return d_symbols; + } + + void + corr_est_cc_impl::set_symbols(const std::vector<gr_complex> &symbols) + { + gr::thread::scoped_lock lock(d_setlock); + + d_symbols = symbols; + + // Per comments in gr-filter/include/gnuradio/filter/fft_filter.h, + // set the block output multiple to the FFT filter kernel's internal, + // assumed "nsamples", to ensure the scheduler always passes a + // proper number of samples. + int nsamples; + nsamples = d_filter->set_taps(d_symbols); + set_output_multiple(nsamples); + + // It looks like the kernel::fft_filter_ccc stashes a tail between + // calls, so that contains our filtering history (I think). The + // fft_filter_ccc block (which calls the kernel::fft_filter_ccc) sets + // the history to 1 (0 history items), so let's follow its lead. + //set_history(1); + + // We'll (ab)use the history for our own purposes of tagging back in time. + // Keep a history of the length of the sync word to delay for tagging. + set_history(d_symbols.size()+1); + + declare_sample_delay(1, 0); + declare_sample_delay(0, d_symbols.size()); + + _set_mark_delay(d_stashed_mark_delay); + _set_threshold(d_stashed_threshold); + } + + unsigned int + corr_est_cc_impl::mark_delay() const + { + return d_mark_delay; + } + + void + corr_est_cc_impl::_set_mark_delay(unsigned int mark_delay) + { + d_stashed_mark_delay = mark_delay; + + if(mark_delay >= d_symbols.size()) { + d_mark_delay = d_symbols.size()-1; + GR_LOG_WARN(d_logger, boost::format("set_mark_delay: asked for %1% but due " + "to the symbol size constraints, " + "mark delay set to %2%.") \ + % mark_delay % d_mark_delay); + } + else { + d_mark_delay = mark_delay; + } + } + + void + corr_est_cc_impl::set_mark_delay(unsigned int mark_delay) + { + gr::thread::scoped_lock lock(d_setlock); + _set_mark_delay(mark_delay); + } + + float + corr_est_cc_impl::threshold() const + { + return d_thresh; + } + + void + corr_est_cc_impl::_set_threshold(float threshold) + { + d_stashed_threshold = threshold; + + // Compute a correlation threshold. + // Compute the value of the discrete autocorrelation of the matched + // filter with offset 0 (aka the autocorrelation peak). + float corr = 0; + for(size_t i = 0; i < d_symbols.size(); i++) + corr += abs(d_symbols[i]*conj(d_symbols[i])); + d_thresh = threshold*corr*corr; + } + + void + corr_est_cc_impl::set_threshold(float threshold) + { + gr::thread::scoped_lock lock(d_setlock); + _set_threshold(threshold); + } + + int + corr_est_cc_impl::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + gr::thread::scoped_lock lock(d_setlock); + + const gr_complex *in = (gr_complex *)input_items[0]; + gr_complex *out = (gr_complex*)output_items[0]; + gr_complex *corr; + if (output_items.size() > 1) + corr = (gr_complex *) output_items[1]; + else + corr = d_corr; + + // Our correlation filter length + unsigned int hist_len = history() - 1; + + // Delay the output by our correlation filter length so we can + // tag backwards in time + memcpy(out, &in[0], sizeof(gr_complex)*noutput_items); + + // Calculate the correlation of the non-delayed input with the + // known symbols. + d_filter->filter(noutput_items, &in[hist_len], corr); + + // Find the magnitude squared of the correlation + volk_32fc_magnitude_squared_32f(&d_corr_mag[0], corr, noutput_items); + + int isps = (int)(d_sps + 0.5f); + int i = 0; + while(i < noutput_items) { + // Look for the correlator output to cross the threshold + if (d_corr_mag[i] <= d_thresh) { + i++; + continue; + } + // Go to (just past) the current correlator output peak + while ((i < (noutput_items-1)) && + (d_corr_mag[i] < d_corr_mag[i+1])) + i++; + + // Delaying the primary signal output by the matched filter + // length using history(), means that the the peak output of + // the matched filter aligns with the start of the desired + // sync word in the primary signal output. This corr_start + // tag is not offset to another sample, so that downstream + // data-aided blocks (like adaptive equalizers) know exactly + // where the start of the correlated symbols are. + add_item_tag(0, nitems_written(0) + i, pmt::intern("corr_start"), + pmt::from_double(d_corr_mag[i]), d_src_id); + + // Peak detector using a "center of mass" approach center + // holds the +/- fraction of a sample index from the found + // peak index to the estimated actual peak index. + double center = 0.0; + if (i > 0 && i < (noutput_items - 1)) { + double nom = 0, den = 0; + for(int s = 0; s < 3; s++) { + nom += (s+1)*d_corr_mag[i+s-1]; + den += d_corr_mag[i+s-1]; + } + center = nom / den - 2.0; + } + + // Calculate the phase offset of the incoming signal. + // + // The analytic cross-correlation is: + // + // 2A*e_bb(t-t_d)*exp(-j*2*pi*f*(t-t_d) - j*phi_bb(t-t_d) - j*theta_c) + // + + // The analytic auto-correlation's envelope, e_bb(), has its + // peak at the "group delay" time, t = t_d. The analytic + // cross-correlation's center frequency phase shift, theta_c, + // is determined from the argument of the analytic + // cross-correlation at the "group delay" time, t = t_d. + // + // Taking the argument of the analytic cross-correlation at + // any other time will include the baseband auto-correlation's + // phase term, phi_bb(t-t_d), and a frequency dependent term + // of the cross-correlation, which I don't believe maps simply + // to expected symbol phase differences. + float phase = fast_atan2f(corr[i].imag(), corr[i].real()); + int index = i + d_mark_delay; + + add_item_tag(0, nitems_written(0) + index, pmt::intern("phase_est"), + pmt::from_double(phase), d_src_id); + add_item_tag(0, nitems_written(0) + index, pmt::intern("time_est"), + pmt::from_double(center), d_src_id); + // N.B. the appropriate d_corr_mag[] index is "i", not "index". + add_item_tag(0, nitems_written(0) + index, pmt::intern("corr_est"), + pmt::from_double(d_corr_mag[i]), d_src_id); + + if (output_items.size() > 1) { + // N.B. these debug tags are not offset to avoid walking off out buf + add_item_tag(1, nitems_written(0) + i, pmt::intern("phase_est"), + pmt::from_double(phase), d_src_id); + add_item_tag(1, nitems_written(0) + i, pmt::intern("time_est"), + pmt::from_double(center), d_src_id); + add_item_tag(1, nitems_written(0) + i, pmt::intern("corr_est"), + pmt::from_double(d_corr_mag[i]), d_src_id); + } + + // Skip ahead to the next potential symbol peak + // (for non-offset/interleaved symbols) + i += isps; + } + + //if (output_items.size() > 1) + // add_item_tag(1, nitems_written(0) + noutput_items - 1, + // pmt::intern("ce_eow"), pmt::from_uint64(noutput_items), + // d_src_id); + + return noutput_items; + } + + } /* namespace digital */ +} /* namespace gr */ diff --git a/gr-digital/lib/corr_est_cc_impl.h b/gr-digital/lib/corr_est_cc_impl.h new file mode 100644 index 0000000000..6e8dd17083 --- /dev/null +++ b/gr-digital/lib/corr_est_cc_impl.h @@ -0,0 +1,73 @@ +/* -*- c++ -*- */ +/* + * Copyright 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_DIGITAL_CORR_EST_CC_IMPL_H +#define INCLUDED_DIGITAL_CORR_EST_CC_IMPL_H + +#include <gnuradio/digital/corr_est_cc.h> +#include <gnuradio/filter/fft_filter.h> + +using namespace gr::filter; + +namespace gr { + namespace digital { + + class corr_est_cc_impl : public corr_est_cc + { + private: + pmt::pmt_t d_src_id; + std::vector<gr_complex> d_symbols; + float d_sps; + unsigned int d_mark_delay, d_stashed_mark_delay; + float d_thresh, d_stashed_threshold; + kernel::fft_filter_ccc *d_filter; + + gr_complex *d_corr; + float *d_corr_mag; + + void _set_mark_delay(unsigned int mark_delay); + void _set_threshold(float threshold); + + public: + corr_est_cc_impl(const std::vector<gr_complex> &symbols, + float sps, unsigned int mark_delay, + float threshold=0.9); + ~corr_est_cc_impl(); + + std::vector<gr_complex> symbols() const; + void set_symbols(const std::vector<gr_complex> &symbols); + + unsigned int mark_delay() const; + void set_mark_delay(unsigned int mark_delay); + + float threshold() const; + void set_threshold(float threshold); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } // namespace digital +} // namespace gr + +#endif /* INCLUDED_DIGITAL_CORR_EST_CC_IMPL_H */ diff --git a/gr-digital/lib/modulate_vector.cc b/gr-digital/lib/modulate_vector.cc new file mode 100644 index 0000000000..281e3435c5 --- /dev/null +++ b/gr-digital/lib/modulate_vector.cc @@ -0,0 +1,70 @@ +/* +* Copyright 2015 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. +* +*/ + +/* +* Generate a modulated transmit vector corresponding to a particular +* data sequence, resampling rate, and shaping filter. The output is +* suitable for use as a candidate filter for the correlate_and_sync +* block, or just for prototyping. +* +* It accepts a sptr to a modulator block as an argument; given +* suitable data vectors and arguments you should be able to use any of +* the GNU Radio modulator blocks as a modulator. Be careful that some +* modulators expect packed words, some expect unpacked words, and some +* have unique expectations, requirements, or limitations. + +* modulator as: gr.block or gr.hier_block +* taps as: list or array +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gnuradio/blocks/vector_source_b.h> +#include <gnuradio/blocks/vector_sink_c.h> +#include <gnuradio/filter/fir_filter_ccf.h> +#include <gnuradio/top_block.h> +#include <gnuradio/digital/modulate_vector.h> + +namespace gr { + namespace digital { + std::vector<gr_complex> modulate_vector_bc(basic_block_sptr modulator, + std::vector<uint8_t> data, + std::vector<float> taps) + { + blocks::vector_source_b::sptr vector_src = blocks::vector_source_b::make(data); + filter::fir_filter_ccf::sptr filter = filter::fir_filter_ccf::make(1, taps); + blocks::vector_sink_c::sptr vector_sink = blocks::vector_sink_c::make(); + + top_block_sptr tb = make_top_block("modulate_vector"); + + tb->connect(vector_src, 0, modulator, 0); + tb->connect(modulator, 0, filter, 0); + tb->connect(filter, 0, vector_sink, 0); + + tb->run(); + + return vector_sink->data(); + } + } /* namespace digital */ +} /* namespace gr */ diff --git a/gr-digital/lib/msk_timing_recovery_cc_impl.cc b/gr-digital/lib/msk_timing_recovery_cc_impl.cc new file mode 100644 index 0000000000..4b26573870 --- /dev/null +++ b/gr-digital/lib/msk_timing_recovery_cc_impl.cc @@ -0,0 +1,210 @@ +/* -*- 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gnuradio/io_signature.h> +#include <gnuradio/math.h> +#include "msk_timing_recovery_cc_impl.h" +#include <gnuradio/filter/firdes.h> + +namespace gr { + namespace digital { + + msk_timing_recovery_cc::sptr + msk_timing_recovery_cc::make(float sps, float gain, float limit, int osps=1) + { + return gnuradio::get_initial_sptr + (new msk_timing_recovery_cc_impl(sps, gain, limit, osps)); + } + + /* + * The private constructor + */ + msk_timing_recovery_cc_impl::msk_timing_recovery_cc_impl(float sps, float gain, float limit, int osps) + : gr::block("msk_timing_recovery_cc", + gr::io_signature::make(1, 1, sizeof(gr_complex)), + gr::io_signature::make3(1, 3, sizeof(gr_complex), sizeof(float), sizeof(float))), + d_limit(limit), + d_interp(new filter::mmse_fir_interpolator_cc()), + d_dly_conj_1(0), + d_dly_conj_2(0), + d_dly_diff_1(0), + d_mu(0.5), + d_div(0), + d_osps(osps) + { + set_sps(sps); + enable_update_rate(true); //fixes tag propagation through variable rate blox + set_gain(gain); + if(d_osps != 1 && d_osps != 2) throw std::out_of_range("osps must be 1 or 2"); + } + + msk_timing_recovery_cc_impl::~msk_timing_recovery_cc_impl() + { + delete d_interp; + } + + void msk_timing_recovery_cc_impl::set_sps(float sps) { + d_sps = sps/2.0; //loop runs at 2x sps + d_omega = d_sps; + set_relative_rate(d_osps/sps); +// set_history(d_sps); + } + + float msk_timing_recovery_cc_impl::get_sps(void) { + return d_sps; + } + + void msk_timing_recovery_cc_impl::set_gain(float gain) { + d_gain = gain; + if(d_gain <= 0) throw std::out_of_range("Gain must be positive"); + d_gain_omega = d_gain*d_gain*0.25; + } + + float msk_timing_recovery_cc_impl::get_gain(void) { + return d_gain; + } + + void msk_timing_recovery_cc_impl::set_limit(float limit) { + d_limit = limit; + } + + float msk_timing_recovery_cc_impl::get_limit(void) { + return d_limit; + } + + void + msk_timing_recovery_cc_impl::forecast (int noutput_items, gr_vector_int &ninput_items_required) + { + unsigned ninputs = ninput_items_required.size(); + for(unsigned i=0; i<ninputs; i++) { + ninput_items_required[i] = (int)ceil((noutput_items*d_sps*2) + 3.0*d_sps + d_interp->ntaps()); + } + } + + int + msk_timing_recovery_cc_impl::general_work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const gr_complex *in = (const gr_complex *) input_items[0]; + gr_complex *out = (gr_complex *) output_items[0]; + float *out2, *out3; + if(output_items.size() >= 2) out2 = (float *) output_items[1]; + if(output_items.size() >= 3) out3 = (float *) output_items[2]; + int oidx=0, iidx=0; + int ninp=ninput_items[0] - 3.0*d_sps; + if(ninp <= 0) { + consume_each(0); + return(0); + } + + std::vector<tag_t> tags; + get_tags_in_range(tags, + 0, + nitems_read(0), + nitems_read(0)+ninp, + pmt::intern("time_est")); + + gr_complex sq, //Squared input + dly_conj, //Input delayed sps and conjugated + nlin_out, //output of the nonlinearity + in_interp; //interpolated input + float err_out=0; //error output + + while(oidx < noutput_items && iidx < ninp) { + //check to see if there's a tag to reset the timing estimate + if(tags.size() > 0) { + int offset = tags[0].offset - nitems_read(0); + if((offset >= iidx) && (offset < (iidx+d_sps))) { + float center = (float) pmt::to_double(tags[0].value); + if(center != center) { //test for NaN, it happens somehow + tags.erase(tags.begin()); + goto out; + } + d_mu = center; + iidx = offset; + if(d_mu<0) { + d_mu++; + iidx--; + } + d_div = 0; + d_omega = d_sps; + d_dly_conj_2 = d_dly_conj_1; + //this keeps the block from outputting an odd number of + //samples and throwing off downstream blocks which depend + //on proper alignment -- for instance, a decimating FIR + //filter. +// if(d_div == 0 and d_osps == 2) oidx++; + tags.erase(tags.begin()); + } + } + +out: + //the actual equation for the nonlinearity is as follows: + //e(n) = in[n]^2 * in[n-sps].conj()^2 + //we then differentiate the error by subtracting the sample delayed by d_sps/2 + in_interp = d_interp->interpolate(&in[iidx], d_mu); + sq = in_interp*in_interp; + //conjugation is distributive. + dly_conj = std::conj(d_dly_conj_2*d_dly_conj_2); + nlin_out = sq*dly_conj; + //TODO: paper argues that some improvement can be had + //if you either operate at >2sps or use a better numeric + //differentiation method. + err_out = std::real(nlin_out - d_dly_diff_1); + if(d_div % 2) { //error loop calc once per symbol + err_out = gr::branchless_clip(err_out, 3.0); + d_omega += d_gain_omega*err_out; + d_omega = d_sps + gr::branchless_clip(d_omega-d_sps, d_limit); + d_mu += d_gain*err_out; + } + //output every other d_sps by default. + if(!(d_div % 2) || d_osps==2) { + out[oidx] = in_interp; + if(output_items.size() >= 2) out2[oidx] = err_out; + if(output_items.size() >= 3) out3[oidx] = d_mu; + oidx++; + } + d_div++; + + d_dly_conj_1 = in_interp; + d_dly_conj_2 = d_dly_conj_1; + d_dly_diff_1 = nlin_out; + + //update interpolator twice per symbol + d_mu += d_omega; + iidx += (int)floor(d_mu); + d_mu -= floor(d_mu); + } + + consume_each (iidx); + return oidx; + } + + } /* namespace digital */ +} /* namespace gr */ + diff --git a/gr-digital/lib/msk_timing_recovery_cc_impl.h b/gr-digital/lib/msk_timing_recovery_cc_impl.h new file mode 100644 index 0000000000..02c29dc6ec --- /dev/null +++ b/gr-digital/lib/msk_timing_recovery_cc_impl.h @@ -0,0 +1,72 @@ +/* -*- 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_DIGITAL_MSK_TIMING_RECOVERY_CC_IMPL_H +#define INCLUDED_DIGITAL_MSK_TIMING_RECOVERY_CC_IMPL_H + +#include <gnuradio/digital/msk_timing_recovery_cc.h> +#include <gnuradio/filter/mmse_fir_interpolator_cc.h> +#include <boost/circular_buffer.hpp> +#include <gnuradio/filter/fir_filter_with_buffer.h> + +namespace gr { + namespace digital { + + class msk_timing_recovery_cc_impl : public msk_timing_recovery_cc + { + private: + float d_sps; + float d_gain; + float d_limit; + filter::mmse_fir_interpolator_cc *d_interp; + filter::kernel::fir_filter_with_buffer_fff *d_decim; + gr_complex d_dly_conj_1, d_dly_conj_2, d_dly_diff_1; + float d_mu, d_omega, d_gain_omega; + int d_div; + int d_osps; + int d_loop_rate; + + public: + msk_timing_recovery_cc_impl(float sps, float gain, float limit, int osps); + ~msk_timing_recovery_cc_impl(); + + // Where all the action really happens + void forecast (int noutput_items, gr_vector_int &ninput_items_required); + + int general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + void set_gain(float gain); + float get_gain(void); + + void set_limit(float limit); + float get_limit(void); + + void set_sps(float sps); + float get_sps(void); + }; + } // namespace digital +} // namespace gr + +#endif /* INCLUDED_DIGITAL_MSK_TIMING_RECOVERY_CC_IMPL_H */ + diff --git a/gr-digital/lib/ofdm_frame_equalizer_vcvc_impl.cc b/gr-digital/lib/ofdm_frame_equalizer_vcvc_impl.cc index 70e840d778..1b0dee4055 100644 --- a/gr-digital/lib/ofdm_frame_equalizer_vcvc_impl.cc +++ b/gr-digital/lib/ofdm_frame_equalizer_vcvc_impl.cc @@ -167,7 +167,7 @@ namespace gr { get_tags_in_window(tags, 0, 0, frame_len); for (size_t i = 0; i < tags.size(); i++) { if (tags[i].key != CHAN_TAPS_KEY - and tags[i].key != pmt::mp(d_length_tag_key_str)) { + && tags[i].key != pmt::mp(d_length_tag_key_str)) { add_item_tag(0, tags[i]); } } diff --git a/gr-digital/python/digital/qa_burst_shaper.py b/gr-digital/python/digital/qa_burst_shaper.py new file mode 100755 index 0000000000..f85b79ceec --- /dev/null +++ b/gr-digital/python/digital/qa_burst_shaper.py @@ -0,0 +1,340 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Copyright 2015 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 +from gnuradio import blocks, digital +import pmt +import numpy as np +import sys + +def make_length_tag(offset, length): + return gr.python_to_tag({'offset' : offset, + 'key' : pmt.intern('packet_len'), + 'value' : pmt.from_long(length), + 'srcid' : pmt.intern('qa_burst_shaper')}) + +def make_tag(offset, key, value): + return gr.python_to_tag({'offset' : offset, + 'key' : pmt.intern(key), + 'value' : value, + 'srcid' : pmt.intern('qa_burst_shaper')}) + +def compare_tags(a, b): + return a.offset == b.offset and pmt.equal(a.key, b.key) and \ + pmt.equal(a.value, b.value) + +class qa_burst_shaper (gr_unittest.TestCase): + + def setUp (self): + self.tb = gr.top_block () + + def tearDown (self): + self.tb = None + + def test_ff (self): + prepad = 10 + postpad = 10 + length = 20 + data = np.ones(length + 10) # need 10 more to push things through + window = np.concatenate((-2.0*np.ones(5), -4.0*np.ones(5))) + tags = (make_length_tag(0, length),) + expected = np.concatenate((np.zeros(prepad), window[0:5], + np.ones(length - len(window)), window[5:10], + np.zeros(postpad))) + etag = make_length_tag(0, length + prepad + postpad) + + # flowgraph + source = blocks.vector_source_f(data, tags=tags) + shaper = digital.burst_shaper_ff(window, pre_padding=prepad, + post_padding=postpad) + sink = blocks.vector_sink_f() + self.tb.connect(source, shaper, sink) + self.tb.run () + + # checks + self.assertFloatTuplesAlmostEqual(sink.data(), expected, 6) + self.assertTrue(compare_tags(sink.tags()[0], etag)) + + def test_cc (self): + prepad = 10 + postpad = 10 + length = 20 + data = np.ones(length + 10, + dtype=complex) # need 10 more to push things through + window = np.concatenate((-2.0*np.ones(5, dtype=complex), + -4.0*np.ones(5, dtype=complex))) + tags = (make_length_tag(0, length),) + expected = np.concatenate((np.zeros(prepad, dtype=complex), window[0:5], + np.ones(length - len(window), dtype=complex), + window[5:10], np.zeros(postpad, + dtype=complex))) + etag = make_length_tag(0, length + prepad + postpad) + + # flowgraph + source = blocks.vector_source_c(data, tags=tags) + shaper = digital.burst_shaper_cc(window, pre_padding=prepad, + post_padding=postpad) + sink = blocks.vector_sink_c() + self.tb.connect(source, shaper, sink) + self.tb.run () + + # checks + self.assertComplexTuplesAlmostEqual(sink.data(), expected, 6) + self.assertTrue(compare_tags(sink.tags()[0], etag)) + + def test_ff_with_phasing (self): + prepad = 10 + postpad = 10 + length = 20 + data = np.ones(length + 10) # need 10 more to push things through + window = np.concatenate((-2.0*np.ones(5), -4.0*np.ones(5))) + tags = (make_length_tag(0, length),) + phasing = np.zeros(5) + for i in xrange(5): + phasing[i] = ((-1.0)**i) + expected = np.concatenate((np.zeros(prepad), phasing*window[0:5], + np.ones(length), phasing*window[5:10], + np.zeros(postpad))) + etag = make_length_tag(0, length + prepad + postpad + len(window)) + + # flowgraph + source = blocks.vector_source_f(data, tags=tags) + shaper = digital.burst_shaper_ff(window, pre_padding=prepad, + post_padding=postpad, + insert_phasing=True) + sink = blocks.vector_sink_f() + self.tb.connect(source, shaper, sink) + self.tb.run () + + # checks + self.assertFloatTuplesAlmostEqual(sink.data(), expected, 6) + self.assertTrue(compare_tags(sink.tags()[0], etag)) + + def test_cc_with_phasing (self): + prepad = 10 + postpad = 10 + length = 20 + data = np.ones(length + 10, + dtype=complex) # need 10 more to push things through + window = np.concatenate((-2.0*np.ones(5, dtype=complex), + -4.0*np.ones(5, dtype=complex))) + tags = (make_length_tag(0, length),) + phasing = np.zeros(5, dtype=complex) + for i in xrange(5): + phasing[i] = complex((-1.0)**i) + expected = np.concatenate((np.zeros(prepad, dtype=complex), + phasing*window[0:5], + np.ones(length, dtype=complex), + phasing*window[5:10], + np.zeros(postpad, dtype=complex))) + etag = make_length_tag(0, length + prepad + postpad + len(window)) + + # flowgraph + source = blocks.vector_source_c(data, tags=tags) + shaper = digital.burst_shaper_cc(window, pre_padding=prepad, + post_padding=postpad, + insert_phasing=True) + sink = blocks.vector_sink_c() + self.tb.connect(source, shaper, sink) + self.tb.run () + + # checks + self.assertComplexTuplesAlmostEqual(sink.data(), expected, 6) + self.assertTrue(compare_tags(sink.tags()[0], etag)) + + def test_odd_window (self): + prepad = 10 + postpad = 10 + length = 20 + data = np.ones(length + 10) # need 10 more to push things through + window = np.concatenate((-2.0*np.ones(5), -3.0*np.ones(1), + -4.0*np.ones(5))) + tags = (make_length_tag(0, length),) + expected = np.concatenate((np.zeros(prepad), window[0:6], + np.ones(length - len(window) - 1), + window[5:11], np.zeros(postpad))) + etag = make_length_tag(0, length + prepad + postpad) + + # flowgraph + source = blocks.vector_source_f(data, tags=tags) + shaper = digital.burst_shaper_ff(window, pre_padding=prepad, + post_padding=postpad) + sink = blocks.vector_sink_f() + self.tb.connect(source, shaper, sink) + self.tb.run () + + # checks + self.assertFloatTuplesAlmostEqual(sink.data(), expected, 6) + self.assertTrue(compare_tags(sink.tags()[0], etag)) + + def test_short_burst (self): + prepad = 10 + postpad = 10 + length = 9 + data = np.ones(length + 10) # need 10 more to push things through + window = np.concatenate((-2.0*np.ones(5), -3.0*np.ones(1), + -4.0*np.ones(5))) + tags = (make_length_tag(0, length),) + expected = np.concatenate((np.zeros(prepad), window[0:4], + np.ones(1), window[5:9], + np.zeros(postpad))) + etag = make_length_tag(0, length + prepad + postpad) + + # flowgraph + source = blocks.vector_source_f(data, tags=tags) + shaper = digital.burst_shaper_ff(window, pre_padding=prepad, + post_padding=postpad) + sink = blocks.vector_sink_f() + self.tb.connect(source, shaper, sink) + self.tb.run () + + # checks + self.assertFloatTuplesAlmostEqual(sink.data(), expected, 6) + self.assertTrue(compare_tags(sink.tags()[0], etag)) + + def test_consecutive_bursts (self): + prepad = 10 + postpad = 10 + length1 = 15 + length2 = 25 + data = np.concatenate((np.ones(length1), -1.0*np.ones(length2), + np.zeros(10))) # need 10 more to push things through + window = np.concatenate((-2.0*np.ones(5), -4.0*np.ones(5))) + tags = (make_length_tag(0, length1), make_length_tag(length1, length2)) + expected = np.concatenate((np.zeros(prepad), window[0:5], + np.ones(length1 - len(window)), window[5:10], + np.zeros(postpad + prepad), -1.0*window[0:5], + -1.0*np.ones(length2 - len(window)), + -1.0*window[5:10], np.zeros(postpad))) + etags = (make_length_tag(0, length1 + prepad + postpad), + make_length_tag(length1 + prepad + postpad, + length2 + prepad + postpad)) + + # flowgraph + source = blocks.vector_source_f(data, tags=tags) + shaper = digital.burst_shaper_ff(window, pre_padding=prepad, + post_padding=postpad) + sink = blocks.vector_sink_f() + self.tb.connect(source, shaper, sink) + self.tb.run () + + # checks + self.assertFloatTuplesAlmostEqual(sink.data(), expected, 6) + for i in xrange(len(etags)): + self.assertTrue(compare_tags(sink.tags()[i], etags[i])) + + def test_tag_gap (self): + prepad = 10 + postpad = 10 + length = 20 + gap_len = 5 + data = np.arange(2*length + 10, + dtype=float) # need 10 more to push things through + window = np.concatenate((-2.0*np.ones(5), -4.0*np.ones(5))) + ewindow = window * np.array([1,-1,1,-1,1,1,-1,1,-1,1],dtype=float) + tags = (make_length_tag(0, length), + make_length_tag(length + gap_len, length)) + expected = np.concatenate((np.zeros(prepad), ewindow[0:5], + np.arange(0, length, dtype=float), + ewindow[5:10], np.zeros(postpad), + np.zeros(prepad), ewindow[0:5], + np.arange(length + gap_len, + 2*length + gap_len, dtype=float), + ewindow[5:10], np.zeros(postpad))) + burst_len = length + len(window) + prepad + postpad + etags = (make_length_tag(0, burst_len), + make_length_tag(burst_len, burst_len)) + + # flowgraph + source = blocks.vector_source_f(data, tags=tags) + shaper = digital.burst_shaper_ff(window, pre_padding=prepad, + post_padding=postpad, + insert_phasing=True) + sink = blocks.vector_sink_f() + self.tb.connect(source, shaper, sink) + self.tb.run () + + # checks + self.assertFloatTuplesAlmostEqual(sink.data(), expected, 6) + for i in xrange(len(etags)): + self.assertTrue(compare_tags(sink.tags()[i], etags[i])) + + def test_tag_propagation (self): + prepad = 10 + postpad = 10 + length1 = 15 + length2 = 25 + gap_len = 5 + lentag1_offset = 0 + lentag2_offset = length1 + gap_len + tag1_offset = 0 # accompanies first length tag + tag2_offset = length1 + gap_len # accompanies second length tag + tag3_offset = 2 # in ramp-up state + tag4_offset = length1 + 2 # in gap; tag will be dropped + tag5_offset = length1 + gap_len + 7 # in copy state + + data = np.concatenate((np.ones(length1), np.zeros(gap_len), + -1.0*np.ones(length2), np.zeros(10))) + window = np.concatenate((-2.0*np.ones(5), -4.0*np.ones(5))) + tags = (make_length_tag(lentag1_offset, length1), + make_length_tag(lentag2_offset, length2), + make_tag(tag1_offset, 'head', pmt.intern('tag1')), + make_tag(tag2_offset, 'head', pmt.intern('tag2')), + make_tag(tag3_offset, 'body', pmt.intern('tag3')), + make_tag(tag4_offset, 'body', pmt.intern('tag4')), + make_tag(tag5_offset, 'body', pmt.intern('tag5'))) + expected = np.concatenate((np.zeros(prepad), window[0:5], + np.ones(length1 - len(window)), window[5:10], + np.zeros(postpad + prepad), -1.0*window[0:5], + -1.0*np.ones(length2 - len(window)), + -1.0*window[5:10], np.zeros(postpad))) + elentag1_offset = 0 + elentag2_offset = length1 + prepad + postpad + etag1_offset = 0 + etag2_offset = elentag2_offset + etag3_offset = prepad + tag3_offset + etag5_offset = 2*prepad + postpad + tag5_offset - gap_len + etags = (make_length_tag(elentag1_offset, length1 + prepad + postpad), + make_length_tag(elentag2_offset, length2 + prepad + postpad), + make_tag(etag1_offset, 'head', pmt.intern('tag1')), + make_tag(etag2_offset, 'head', pmt.intern('tag2')), + make_tag(etag3_offset, 'body', pmt.intern('tag3')), + make_tag(etag5_offset, 'body', pmt.intern('tag5'))) + + # flowgraph + source = blocks.vector_source_f(data, tags=tags) + shaper = digital.burst_shaper_ff(window, pre_padding=prepad, + post_padding=postpad) + sink = blocks.vector_sink_f() + self.tb.connect(source, shaper, sink) + self.tb.run () + + # checks + self.assertFloatTuplesAlmostEqual(sink.data(), expected, 6) + for x, y in zip(sorted(sink.tags(), key=gr.tag_t_offset_compare_key()), + sorted(etags, key=gr.tag_t_offset_compare_key())): + self.assertTrue(compare_tags(x, y)) + + +if __name__ == '__main__': + gr_unittest.run(qa_burst_shaper, "qa_burst_shaper.xml") diff --git a/gr-digital/swig/digital_swig.i b/gr-digital/swig/digital_swig.i index 43f68a3d6e..d7a3b81c15 100644 --- a/gr-digital/swig/digital_swig.i +++ b/gr-digital/swig/digital_swig.i @@ -1,5 +1,5 @@ /* - * Copyright 2011,2012 Free Software Foundation, Inc. + * Copyright 2011-2015 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -39,6 +39,8 @@ %{ #include "gnuradio/digital/additive_scrambler_bb.h" #include "gnuradio/digital/binary_slicer_fb.h" +#include "gnuradio/digital/burst_shaper_cc.h" +#include "gnuradio/digital/burst_shaper_ff.h" #include "gnuradio/digital/chunks_to_symbols_bc.h" #include "gnuradio/digital/chunks_to_symbols_bf.h" #include "gnuradio/digital/chunks_to_symbols_ic.h" @@ -52,6 +54,7 @@ #include "gnuradio/digital/constellation_decoder_cb.h" #include "gnuradio/digital/constellation_receiver_cb.h" #include "gnuradio/digital/constellation_soft_decoder_cf.h" +#include "gnuradio/digital/corr_est_cc.h" #include "gnuradio/digital/correlate_access_code_bb.h" #include "gnuradio/digital/correlate_access_code_tag_bb.h" #include "gnuradio/digital/correlate_access_code_bb_ts.h" @@ -78,9 +81,11 @@ #include "gnuradio/digital/lms_dd_equalizer_cc.h" #include "gnuradio/digital/map_bb.h" #include "gnuradio/digital/metric_type.h" +#include "gnuradio/digital/modulate_vector.h" #include "gnuradio/digital/mpsk_receiver_cc.h" #include "gnuradio/digital/mpsk_snr_est.h" #include "gnuradio/digital/mpsk_snr_est_cc.h" +#include "gnuradio/digital/msk_timing_recovery_cc.h" #include "gnuradio/digital/ofdm_carrier_allocator_cvc.h" #include "gnuradio/digital/ofdm_chanest_vcvc.h" #include "gnuradio/digital/ofdm_cyclic_prefixer.h" @@ -115,6 +120,8 @@ %include "gnuradio/digital/additive_scrambler_bb.h" %include "gnuradio/digital/binary_slicer_fb.h" +%include "gnuradio/digital/burst_shaper_cc.h" +%include "gnuradio/digital/burst_shaper_ff.h" %include "gnuradio/digital/chunks_to_symbols_bc.h" %include "gnuradio/digital/chunks_to_symbols_bf.h" %include "gnuradio/digital/chunks_to_symbols_ic.h" @@ -128,6 +135,7 @@ %include "gnuradio/digital/constellation_decoder_cb.h" %include "gnuradio/digital/constellation_receiver_cb.h" %include "gnuradio/digital/constellation_soft_decoder_cf.h" +%include "gnuradio/digital/corr_est_cc.h" %include "gnuradio/digital/correlate_access_code_bb.h" %include "gnuradio/digital/correlate_access_code_tag_bb.h" %include "gnuradio/digital/correlate_access_code_bb_ts.h" @@ -154,9 +162,11 @@ %include "gnuradio/digital/lms_dd_equalizer_cc.h" %include "gnuradio/digital/map_bb.h" %include "gnuradio/digital/metric_type.h" +%include "gnuradio/digital/modulate_vector.h" %include "gnuradio/digital/mpsk_receiver_cc.h" %include "gnuradio/digital/mpsk_snr_est.h" %include "gnuradio/digital/mpsk_snr_est_cc.h" +%include "gnuradio/digital/msk_timing_recovery_cc.h" %include "gnuradio/digital/ofdm_carrier_allocator_cvc.h" %include "gnuradio/digital/ofdm_chanest_vcvc.h" %include "gnuradio/digital/ofdm_cyclic_prefixer.h" @@ -187,6 +197,8 @@ GR_SWIG_BLOCK_MAGIC2(digital, additive_scrambler_bb); GR_SWIG_BLOCK_MAGIC2(digital, binary_slicer_fb); +GR_SWIG_BLOCK_MAGIC2(digital, burst_shaper_cc); +GR_SWIG_BLOCK_MAGIC2(digital, burst_shaper_ff); GR_SWIG_BLOCK_MAGIC2(digital, chunks_to_symbols_bc); GR_SWIG_BLOCK_MAGIC2(digital, chunks_to_symbols_bf); GR_SWIG_BLOCK_MAGIC2(digital, chunks_to_symbols_ic); @@ -199,6 +211,7 @@ GR_SWIG_BLOCK_MAGIC2(digital, cma_equalizer_cc); GR_SWIG_BLOCK_MAGIC2(digital, constellation_decoder_cb); GR_SWIG_BLOCK_MAGIC2(digital, constellation_receiver_cb); GR_SWIG_BLOCK_MAGIC2(digital, constellation_soft_decoder_cf); +GR_SWIG_BLOCK_MAGIC2(digital, corr_est_cc); GR_SWIG_BLOCK_MAGIC2(digital, correlate_access_code_bb); GR_SWIG_BLOCK_MAGIC2(digital, correlate_access_code_tag_bb); GR_SWIG_BLOCK_MAGIC2(digital, correlate_access_code_bb_ts); @@ -224,6 +237,7 @@ GR_SWIG_BLOCK_MAGIC2(digital, lms_dd_equalizer_cc); GR_SWIG_BLOCK_MAGIC2(digital, map_bb); GR_SWIG_BLOCK_MAGIC2(digital, mpsk_receiver_cc); GR_SWIG_BLOCK_MAGIC2(digital, mpsk_snr_est_cc); +GR_SWIG_BLOCK_MAGIC2(digital, msk_timing_recovery_cc); GR_SWIG_BLOCK_MAGIC2(digital, ofdm_carrier_allocator_cvc); GR_SWIG_BLOCK_MAGIC2(digital, ofdm_chanest_vcvc); GR_SWIG_BLOCK_MAGIC2(digital, ofdm_cyclic_prefixer); diff --git a/gr-dtv/examples/README.dvbt b/gr-dtv/examples/README.dvbt new file mode 100644 index 0000000000..88986c74a8 --- /dev/null +++ b/gr-dtv/examples/README.dvbt @@ -0,0 +1,4 @@ +Additional information and links to test streams for the +DVB-T flow graphs can be found here: + +https://github.com/drmpeg/dtv-utils diff --git a/gr-dtv/examples/dvbt_tx_2k.grc b/gr-dtv/examples/dvbt_tx_2k.grc new file mode 100644 index 0000000000..3db36aedcf --- /dev/null +++ b/gr-dtv/examples/dvbt_tx_2k.grc @@ -0,0 +1,2076 @@ +<?xml version='1.0' encoding='ASCII'?> +<?grc format='1' created='3.7.8'?> +<flow_graph> + <timestamp>Thu Jan 16 23:00:58 2014</timestamp> + <block> + <key>dtv_dvbt_bit_inner_interleaver</key> + <param> + <key>id</key> + <value>dtv_dvbt_bit_inner_interleaver_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>constellation</key> + <value>64qam</value> + </param> + <param> + <key>hierarchy</key> + <value>nh</value> + </param> + <param> + <key>transmission_mode</key> + <value>T2k</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(984, 243)</value> + </param> + <param> + <key>_rotation</key> + <value>180</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>samp_rate</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>(8000000.0 * 8) / 7</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(8, 83)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>dtv_dvbt_symbol_inner_interleaver</key> + <param> + <key>id</key> + <value>dtv_dvbt_symbol_inner_interleaver_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>transmission_mode</key> + <value>T2k</value> + </param> + <param> + <key>direction</key> + <value>Interleave</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(664, 243)</value> + </param> + <param> + <key>_rotation</key> + <value>180</value> + </param> + </block> + <block> + <key>qtgui_const_sink_x</key> + <param> + <key>id</key> + <value>qtgui_const_sink_x_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>name</key> + <value>""</value> + </param> + <param> + <key>size</key> + <value>1024</value> + </param> + <param> + <key>grid</key> + <value>False</value> + </param> + <param> + <key>autoscale</key> + <value>False</value> + </param> + <param> + <key>ymin</key> + <value>-2</value> + </param> + <param> + <key>ymax</key> + <value>2</value> + </param> + <param> + <key>xmin</key> + <value>-2</value> + </param> + <param> + <key>xmax</key> + <value>2</value> + </param> + <param> + <key>nconnections</key> + <value>1</value> + </param> + <param> + <key>update_time</key> + <value>0.10</value> + </param> + <param> + <key>gui_hint</key> + <value></value> + </param> + <param> + <key>tr_mode</key> + <value>qtgui.TRIG_MODE_FREE</value> + </param> + <param> + <key>tr_slope</key> + <value>qtgui.TRIG_SLOPE_POS</value> + </param> + <param> + <key>tr_level</key> + <value>0.0</value> + </param> + <param> + <key>tr_chan</key> + <value>0</value> + </param> + <param> + <key>tr_tag</key> + <value>""</value> + </param> + <param> + <key>legend</key> + <value>True</value> + </param> + <param> + <key>label1</key> + <value></value> + </param> + <param> + <key>width1</key> + <value>1</value> + </param> + <param> + <key>color1</key> + <value>"blue"</value> + </param> + <param> + <key>style1</key> + <value>0</value> + </param> + <param> + <key>marker1</key> + <value>0</value> + </param> + <param> + <key>alpha1</key> + <value>1.0</value> + </param> + <param> + <key>label2</key> + <value></value> + </param> + <param> + <key>width2</key> + <value>1</value> + </param> + <param> + <key>color2</key> + <value>"red"</value> + </param> + <param> + <key>style2</key> + <value>0</value> + </param> + <param> + <key>marker2</key> + <value>0</value> + </param> + <param> + <key>alpha2</key> + <value>1.0</value> + </param> + <param> + <key>label3</key> + <value></value> + </param> + <param> + <key>width3</key> + <value>1</value> + </param> + <param> + <key>color3</key> + <value>"red"</value> + </param> + <param> + <key>style3</key> + <value>0</value> + </param> + <param> + <key>marker3</key> + <value>0</value> + </param> + <param> + <key>alpha3</key> + <value>1.0</value> + </param> + <param> + <key>label4</key> + <value></value> + </param> + <param> + <key>width4</key> + <value>1</value> + </param> + <param> + <key>color4</key> + <value>"red"</value> + </param> + <param> + <key>style4</key> + <value>0</value> + </param> + <param> + <key>marker4</key> + <value>0</value> + </param> + <param> + <key>alpha4</key> + <value>1.0</value> + </param> + <param> + <key>label5</key> + <value></value> + </param> + <param> + <key>width5</key> + <value>1</value> + </param> + <param> + <key>color5</key> + <value>"red"</value> + </param> + <param> + <key>style5</key> + <value>0</value> + </param> + <param> + <key>marker5</key> + <value>0</value> + </param> + <param> + <key>alpha5</key> + <value>1.0</value> + </param> + <param> + <key>label6</key> + <value></value> + </param> + <param> + <key>width6</key> + <value>1</value> + </param> + <param> + <key>color6</key> + <value>"red"</value> + </param> + <param> + <key>style6</key> + <value>0</value> + </param> + <param> + <key>marker6</key> + <value>0</value> + </param> + <param> + <key>alpha6</key> + <value>1.0</value> + </param> + <param> + <key>label7</key> + <value></value> + </param> + <param> + <key>width7</key> + <value>1</value> + </param> + <param> + <key>color7</key> + <value>"red"</value> + </param> + <param> + <key>style7</key> + <value>0</value> + </param> + <param> + <key>marker7</key> + <value>0</value> + </param> + <param> + <key>alpha7</key> + <value>1.0</value> + </param> + <param> + <key>label8</key> + <value></value> + </param> + <param> + <key>width8</key> + <value>1</value> + </param> + <param> + <key>color8</key> + <value>"red"</value> + </param> + <param> + <key>style8</key> + <value>0</value> + </param> + <param> + <key>marker8</key> + <value>0</value> + </param> + <param> + <key>alpha8</key> + <value>1.0</value> + </param> + <param> + <key>label9</key> + <value></value> + </param> + <param> + <key>width9</key> + <value>1</value> + </param> + <param> + <key>color9</key> + <value>"red"</value> + </param> + <param> + <key>style9</key> + <value>0</value> + </param> + <param> + <key>marker9</key> + <value>0</value> + </param> + <param> + <key>alpha9</key> + <value>1.0</value> + </param> + <param> + <key>label10</key> + <value></value> + </param> + <param> + <key>width10</key> + <value>1</value> + </param> + <param> + <key>color10</key> + <value>"red"</value> + </param> + <param> + <key>style10</key> + <value>0</value> + </param> + <param> + <key>marker10</key> + <value>0</value> + </param> + <param> + <key>alpha10</key> + <value>1.0</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(360, 555)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_vector_to_stream</key> + <param> + <key>id</key> + <value>blocks_vector_to_stream_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>num_items</key> + <value>2048</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(120, 563)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>dtv_dvbt_energy_dispersal</key> + <param> + <key>id</key> + <value>dtv_dvbt_energy_dispersal_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>nsize</key> + <value>1</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(328, 96)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>dtv_dvbt_reed_solomon_enc</key> + <param> + <key>id</key> + <value>dtv_dvbt_reed_solomon_enc_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>p</key> + <value>2</value> + </param> + <param> + <key>m</key> + <value>8</value> + </param> + <param> + <key>gfpoly</key> + <value>0x11d</value> + </param> + <param> + <key>n</key> + <value>255</value> + </param> + <param> + <key>k</key> + <value>239</value> + </param> + <param> + <key>t</key> + <value>8</value> + </param> + <param> + <key>s</key> + <value>51</value> + </param> + <param> + <key>blocks</key> + <value>8</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(512, 43)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>dtv_dvbt_convolutional_interleaver</key> + <param> + <key>id</key> + <value>dtv_dvbt_convolutional_interleaver_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>blocks</key> + <value>136</value> + </param> + <param> + <key>I</key> + <value>12</value> + </param> + <param> + <key>M</key> + <value>17</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(736, 75)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>dtv_dvbt_inner_coder</key> + <param> + <key>id</key> + <value>dtv_dvbt_inner_coder_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>ninput</key> + <value>1</value> + </param> + <param> + <key>noutput</key> + <value>1512</value> + </param> + <param> + <key>constellation</key> + <value>64qam</value> + </param> + <param> + <key>hierarchy</key> + <value>nh</value> + </param> + <param> + <key>code_rate</key> + <value>C2_3</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(1000, 67)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>dtv_dvbt_map</key> + <param> + <key>id</key> + <value>dtv_dvbt_map_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>constellation</key> + <value>64qam</value> + </param> + <param> + <key>hierarchy</key> + <value>nh</value> + </param> + <param> + <key>transmission_mode</key> + <value>T2k</value> + </param> + <param> + <key>gain</key> + <value>1</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(344, 227)</value> + </param> + <param> + <key>_rotation</key> + <value>180</value> + </param> + </block> + <block> + <key>fft_vxx</key> + <param> + <key>id</key> + <value>fft_vxx_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>fft_size</key> + <value>2048</value> + </param> + <param> + <key>forward</key> + <value>False</value> + </param> + <param> + <key>window</key> + <value>window.rectangular(2048)</value> + </param> + <param> + <key>shift</key> + <value>True</value> + </param> + <param> + <key>nthreads</key> + <value>1</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(64, 403)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_file_source</key> + <param> + <key>id</key> + <value>blocks_file_source_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>file</key> + <value>/run/shm/advtest.ts</value> + </param> + <param> + <key>type</key> + <value>byte</value> + </param> + <param> + <key>repeat</key> + <value>True</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(112, 83)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>uhd_usrp_sink</key> + <param> + <key>id</key> + <value>uhd_usrp_sink_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>fc32</value> + </param> + <param> + <key>otw</key> + <value></value> + </param> + <param> + <key>stream_args</key> + <value></value> + </param> + <param> + <key>stream_chans</key> + <value>[]</value> + </param> + <param> + <key>dev_addr</key> + <value>"send_frame_size=65536,num_send_frames=128,master_clock_rate=" + str(samp_rate*4)</value> + </param> + <param> + <key>dev_args</key> + <value>""</value> + </param> + <param> + <key>sync</key> + <value></value> + </param> + <param> + <key>clock_rate</key> + <value>0.0</value> + </param> + <param> + <key>num_mboards</key> + <value>1</value> + </param> + <param> + <key>clock_source0</key> + <value></value> + </param> + <param> + <key>time_source0</key> + <value></value> + </param> + <param> + <key>sd_spec0</key> + <value></value> + </param> + <param> + <key>clock_source1</key> + <value></value> + </param> + <param> + <key>time_source1</key> + <value></value> + </param> + <param> + <key>sd_spec1</key> + <value></value> + </param> + <param> + <key>clock_source2</key> + <value></value> + </param> + <param> + <key>time_source2</key> + <value></value> + </param> + <param> + <key>sd_spec2</key> + <value></value> + </param> + <param> + <key>clock_source3</key> + <value></value> + </param> + <param> + <key>time_source3</key> + <value></value> + </param> + <param> + <key>sd_spec3</key> + <value></value> + </param> + <param> + <key>clock_source4</key> + <value></value> + </param> + <param> + <key>time_source4</key> + <value></value> + </param> + <param> + <key>sd_spec4</key> + <value></value> + </param> + <param> + <key>clock_source5</key> + <value></value> + </param> + <param> + <key>time_source5</key> + <value></value> + </param> + <param> + <key>sd_spec5</key> + <value></value> + </param> + <param> + <key>clock_source6</key> + <value></value> + </param> + <param> + <key>time_source6</key> + <value></value> + </param> + <param> + <key>sd_spec6</key> + <value></value> + </param> + <param> + <key>clock_source7</key> + <value></value> + </param> + <param> + <key>time_source7</key> + <value></value> + </param> + <param> + <key>sd_spec7</key> + <value></value> + </param> + <param> + <key>nchan</key> + <value>1</value> + </param> + <param> + <key>samp_rate</key> + <value>samp_rate</value> + </param> + <param> + <key>center_freq0</key> + <value>429000000</value> + </param> + <param> + <key>gain0</key> + <value>50</value> + </param> + <param> + <key>norm_gain0</key> + <value>False</value> + </param> + <param> + <key>ant0</key> + <value></value> + </param> + <param> + <key>bw0</key> + <value>0</value> + </param> + <param> + <key>center_freq1</key> + <value>0</value> + </param> + <param> + <key>gain1</key> + <value>0</value> + </param> + <param> + <key>norm_gain1</key> + <value>False</value> + </param> + <param> + <key>ant1</key> + <value></value> + </param> + <param> + <key>bw1</key> + <value>0</value> + </param> + <param> + <key>center_freq2</key> + <value>0</value> + </param> + <param> + <key>gain2</key> + <value>0</value> + </param> + <param> + <key>norm_gain2</key> + <value>False</value> + </param> + <param> + <key>ant2</key> + <value></value> + </param> + <param> + <key>bw2</key> + <value>0</value> + </param> + <param> + <key>center_freq3</key> + <value>0</value> + </param> + <param> + <key>gain3</key> + <value>0</value> + </param> + <param> + <key>norm_gain3</key> + <value>False</value> + </param> + <param> + <key>ant3</key> + <value></value> + </param> + <param> + <key>bw3</key> + <value>0</value> + </param> + <param> + <key>center_freq4</key> + <value>0</value> + </param> + <param> + <key>gain4</key> + <value>0</value> + </param> + <param> + <key>norm_gain4</key> + <value>False</value> + </param> + <param> + <key>ant4</key> + <value></value> + </param> + <param> + <key>bw4</key> + <value>0</value> + </param> + <param> + <key>center_freq5</key> + <value>0</value> + </param> + <param> + <key>gain5</key> + <value>0</value> + </param> + <param> + <key>norm_gain5</key> + <value>False</value> + </param> + <param> + <key>ant5</key> + <value></value> + </param> + <param> + <key>bw5</key> + <value>0</value> + </param> + <param> + <key>center_freq6</key> + <value>0</value> + </param> + <param> + <key>gain6</key> + <value>0</value> + </param> + <param> + <key>norm_gain6</key> + <value>False</value> + </param> + <param> + <key>ant6</key> + <value></value> + </param> + <param> + <key>bw6</key> + <value>0</value> + </param> + <param> + <key>center_freq7</key> + <value>0</value> + </param> + <param> + <key>gain7</key> + <value>0</value> + </param> + <param> + <key>norm_gain7</key> + <value>False</value> + </param> + <param> + <key>ant7</key> + <value></value> + </param> + <param> + <key>bw7</key> + <value>0</value> + </param> + <param> + <key>center_freq8</key> + <value>0</value> + </param> + <param> + <key>gain8</key> + <value>0</value> + </param> + <param> + <key>norm_gain8</key> + <value>False</value> + </param> + <param> + <key>ant8</key> + <value></value> + </param> + <param> + <key>bw8</key> + <value>0</value> + </param> + <param> + <key>center_freq9</key> + <value>0</value> + </param> + <param> + <key>gain9</key> + <value>0</value> + </param> + <param> + <key>norm_gain9</key> + <value>False</value> + </param> + <param> + <key>ant9</key> + <value></value> + </param> + <param> + <key>bw9</key> + <value>0</value> + </param> + <param> + <key>center_freq10</key> + <value>0</value> + </param> + <param> + <key>gain10</key> + <value>0</value> + </param> + <param> + <key>norm_gain10</key> + <value>False</value> + </param> + <param> + <key>ant10</key> + <value></value> + </param> + <param> + <key>bw10</key> + <value>0</value> + </param> + <param> + <key>center_freq11</key> + <value>0</value> + </param> + <param> + <key>gain11</key> + <value>0</value> + </param> + <param> + <key>norm_gain11</key> + <value>False</value> + </param> + <param> + <key>ant11</key> + <value></value> + </param> + <param> + <key>bw11</key> + <value>0</value> + </param> + <param> + <key>center_freq12</key> + <value>0</value> + </param> + <param> + <key>gain12</key> + <value>0</value> + </param> + <param> + <key>norm_gain12</key> + <value>False</value> + </param> + <param> + <key>ant12</key> + <value></value> + </param> + <param> + <key>bw12</key> + <value>0</value> + </param> + <param> + <key>center_freq13</key> + <value>0</value> + </param> + <param> + <key>gain13</key> + <value>0</value> + </param> + <param> + <key>norm_gain13</key> + <value>False</value> + </param> + <param> + <key>ant13</key> + <value></value> + </param> + <param> + <key>bw13</key> + <value>0</value> + </param> + <param> + <key>center_freq14</key> + <value>0</value> + </param> + <param> + <key>gain14</key> + <value>0</value> + </param> + <param> + <key>norm_gain14</key> + <value>False</value> + </param> + <param> + <key>ant14</key> + <value></value> + </param> + <param> + <key>bw14</key> + <value>0</value> + </param> + <param> + <key>center_freq15</key> + <value>0</value> + </param> + <param> + <key>gain15</key> + <value>0</value> + </param> + <param> + <key>norm_gain15</key> + <value>False</value> + </param> + <param> + <key>ant15</key> + <value></value> + </param> + <param> + <key>bw15</key> + <value>0</value> + </param> + <param> + <key>center_freq16</key> + <value>0</value> + </param> + <param> + <key>gain16</key> + <value>0</value> + </param> + <param> + <key>norm_gain16</key> + <value>False</value> + </param> + <param> + <key>ant16</key> + <value></value> + </param> + <param> + <key>bw16</key> + <value>0</value> + </param> + <param> + <key>center_freq17</key> + <value>0</value> + </param> + <param> + <key>gain17</key> + <value>0</value> + </param> + <param> + <key>norm_gain17</key> + <value>False</value> + </param> + <param> + <key>ant17</key> + <value></value> + </param> + <param> + <key>bw17</key> + <value>0</value> + </param> + <param> + <key>center_freq18</key> + <value>0</value> + </param> + <param> + <key>gain18</key> + <value>0</value> + </param> + <param> + <key>norm_gain18</key> + <value>False</value> + </param> + <param> + <key>ant18</key> + <value></value> + </param> + <param> + <key>bw18</key> + <value>0</value> + </param> + <param> + <key>center_freq19</key> + <value>0</value> + </param> + <param> + <key>gain19</key> + <value>0</value> + </param> + <param> + <key>norm_gain19</key> + <value>False</value> + </param> + <param> + <key>ant19</key> + <value></value> + </param> + <param> + <key>bw19</key> + <value>0</value> + </param> + <param> + <key>center_freq20</key> + <value>0</value> + </param> + <param> + <key>gain20</key> + <value>0</value> + </param> + <param> + <key>norm_gain20</key> + <value>False</value> + </param> + <param> + <key>ant20</key> + <value></value> + </param> + <param> + <key>bw20</key> + <value>0</value> + </param> + <param> + <key>center_freq21</key> + <value>0</value> + </param> + <param> + <key>gain21</key> + <value>0</value> + </param> + <param> + <key>norm_gain21</key> + <value>False</value> + </param> + <param> + <key>ant21</key> + <value></value> + </param> + <param> + <key>bw21</key> + <value>0</value> + </param> + <param> + <key>center_freq22</key> + <value>0</value> + </param> + <param> + <key>gain22</key> + <value>0</value> + </param> + <param> + <key>norm_gain22</key> + <value>False</value> + </param> + <param> + <key>ant22</key> + <value></value> + </param> + <param> + <key>bw22</key> + <value>0</value> + </param> + <param> + <key>center_freq23</key> + <value>0</value> + </param> + <param> + <key>gain23</key> + <value>0</value> + </param> + <param> + <key>norm_gain23</key> + <value>False</value> + </param> + <param> + <key>ant23</key> + <value></value> + </param> + <param> + <key>bw23</key> + <value>0</value> + </param> + <param> + <key>center_freq24</key> + <value>0</value> + </param> + <param> + <key>gain24</key> + <value>0</value> + </param> + <param> + <key>norm_gain24</key> + <value>False</value> + </param> + <param> + <key>ant24</key> + <value></value> + </param> + <param> + <key>bw24</key> + <value>0</value> + </param> + <param> + <key>center_freq25</key> + <value>0</value> + </param> + <param> + <key>gain25</key> + <value>0</value> + </param> + <param> + <key>norm_gain25</key> + <value>False</value> + </param> + <param> + <key>ant25</key> + <value></value> + </param> + <param> + <key>bw25</key> + <value>0</value> + </param> + <param> + <key>center_freq26</key> + <value>0</value> + </param> + <param> + <key>gain26</key> + <value>0</value> + </param> + <param> + <key>norm_gain26</key> + <value>False</value> + </param> + <param> + <key>ant26</key> + <value></value> + </param> + <param> + <key>bw26</key> + <value>0</value> + </param> + <param> + <key>center_freq27</key> + <value>0</value> + </param> + <param> + <key>gain27</key> + <value>0</value> + </param> + <param> + <key>norm_gain27</key> + <value>False</value> + </param> + <param> + <key>ant27</key> + <value></value> + </param> + <param> + <key>bw27</key> + <value>0</value> + </param> + <param> + <key>center_freq28</key> + <value>0</value> + </param> + <param> + <key>gain28</key> + <value>0</value> + </param> + <param> + <key>norm_gain28</key> + <value>False</value> + </param> + <param> + <key>ant28</key> + <value></value> + </param> + <param> + <key>bw28</key> + <value>0</value> + </param> + <param> + <key>center_freq29</key> + <value>0</value> + </param> + <param> + <key>gain29</key> + <value>0</value> + </param> + <param> + <key>norm_gain29</key> + <value>False</value> + </param> + <param> + <key>ant29</key> + <value></value> + </param> + <param> + <key>bw29</key> + <value>0</value> + </param> + <param> + <key>center_freq30</key> + <value>0</value> + </param> + <param> + <key>gain30</key> + <value>0</value> + </param> + <param> + <key>norm_gain30</key> + <value>False</value> + </param> + <param> + <key>ant30</key> + <value></value> + </param> + <param> + <key>bw30</key> + <value>0</value> + </param> + <param> + <key>center_freq31</key> + <value>0</value> + </param> + <param> + <key>gain31</key> + <value>0</value> + </param> + <param> + <key>norm_gain31</key> + <value>False</value> + </param> + <param> + <key>ant31</key> + <value></value> + </param> + <param> + <key>bw31</key> + <value>0</value> + </param> + <param> + <key>len_tag_name</key> + <value></value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(984, 387)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>digital_ofdm_cyclic_prefixer</key> + <param> + <key>id</key> + <value>digital_ofdm_cyclic_prefixer_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>input_size</key> + <value>2048</value> + </param> + <param> + <key>cp_len</key> + <value>64</value> + </param> + <param> + <key>rolloff</key> + <value>0</value> + </param> + <param> + <key>tagname</key> + <value></value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(392, 419)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_multiply_const_vxx</key> + <param> + <key>id</key> + <value>blocks_multiply_const_vxx_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>const</key> + <value>0.0022097087</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(664, 435)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>options</key> + <param> + <key>id</key> + <value>dvbt_tx_demo</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>title</key> + <value></value> + </param> + <param> + <key>author</key> + <value></value> + </param> + <param> + <key>description</key> + <value></value> + </param> + <param> + <key>window_size</key> + <value>1280, 1024</value> + </param> + <param> + <key>generate_options</key> + <value>qt_gui</value> + </param> + <param> + <key>category</key> + <value>Custom</value> + </param> + <param> + <key>run_options</key> + <value>prompt</value> + </param> + <param> + <key>run</key> + <value>True</value> + </param> + <param> + <key>max_nouts</key> + <value>0</value> + </param> + <param> + <key>realtime_scheduling</key> + <value></value> + </param> + <param> + <key>thread_safe_setters</key> + <value></value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(8, 11)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>dtv_dvbt_reference_signals</key> + <param> + <key>id</key> + <value>dtv_dvbt_reference_signals_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>constellation</key> + <value>64qam</value> + </param> + <param> + <key>hierarchy</key> + <value>nh</value> + </param> + <param> + <key>code_rate_hp</key> + <value>C2_3</value> + </param> + <param> + <key>code_rate_lp</key> + <value>C2_3</value> + </param> + <param> + <key>guard_interval</key> + <value>GI_1_32</value> + </param> + <param> + <key>transmission_mode</key> + <value>T2k</value> + </param> + <param> + <key>include_cell_id</key> + <value>cell_ide_no</value> + </param> + <param> + <key>cell_id</key> + <value>0</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(40, 187)</value> + </param> + <param> + <key>_rotation</key> + <value>180</value> + </param> + </block> + <connection> + <source_block_id>digital_ofdm_cyclic_prefixer_0</source_block_id> + <sink_block_id>blocks_multiply_const_vxx_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>fft_vxx_0</source_block_id> + <sink_block_id>digital_ofdm_cyclic_prefixer_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>blocks_multiply_const_vxx_0</source_block_id> + <sink_block_id>uhd_usrp_sink_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>blocks_file_source_0</source_block_id> + <sink_block_id>dtv_dvbt_energy_dispersal_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>dtv_dvbt_energy_dispersal_0</source_block_id> + <sink_block_id>dtv_dvbt_reed_solomon_enc_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>dtv_dvbt_convolutional_interleaver_0</source_block_id> + <sink_block_id>dtv_dvbt_inner_coder_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>dtv_dvbt_inner_coder_0</source_block_id> + <sink_block_id>dtv_dvbt_bit_inner_interleaver_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>dtv_dvbt_bit_inner_interleaver_0</source_block_id> + <sink_block_id>dtv_dvbt_symbol_inner_interleaver_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>dtv_dvbt_symbol_inner_interleaver_0</source_block_id> + <sink_block_id>dtv_dvbt_map_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>dtv_dvbt_map_0</source_block_id> + <sink_block_id>dtv_dvbt_reference_signals_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>dtv_dvbt_reference_signals_0</source_block_id> + <sink_block_id>fft_vxx_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>dtv_dvbt_reference_signals_0</source_block_id> + <sink_block_id>blocks_vector_to_stream_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>blocks_vector_to_stream_0</source_block_id> + <sink_block_id>qtgui_const_sink_x_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>dtv_dvbt_reed_solomon_enc_0</source_block_id> + <sink_block_id>dtv_dvbt_convolutional_interleaver_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> +</flow_graph> diff --git a/gr-dtv/examples/dvbt_tx_8k.grc b/gr-dtv/examples/dvbt_tx_8k.grc new file mode 100644 index 0000000000..4cad688e29 --- /dev/null +++ b/gr-dtv/examples/dvbt_tx_8k.grc @@ -0,0 +1,2076 @@ +<?xml version='1.0' encoding='ASCII'?> +<?grc format='1' created='3.7.8'?> +<flow_graph> + <timestamp>Thu Jan 16 23:00:58 2014</timestamp> + <block> + <key>qtgui_const_sink_x</key> + <param> + <key>id</key> + <value>qtgui_const_sink_x_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>name</key> + <value>""</value> + </param> + <param> + <key>size</key> + <value>1024</value> + </param> + <param> + <key>grid</key> + <value>False</value> + </param> + <param> + <key>autoscale</key> + <value>False</value> + </param> + <param> + <key>ymin</key> + <value>-2</value> + </param> + <param> + <key>ymax</key> + <value>2</value> + </param> + <param> + <key>xmin</key> + <value>-2</value> + </param> + <param> + <key>xmax</key> + <value>2</value> + </param> + <param> + <key>nconnections</key> + <value>1</value> + </param> + <param> + <key>update_time</key> + <value>0.10</value> + </param> + <param> + <key>gui_hint</key> + <value></value> + </param> + <param> + <key>tr_mode</key> + <value>qtgui.TRIG_MODE_FREE</value> + </param> + <param> + <key>tr_slope</key> + <value>qtgui.TRIG_SLOPE_POS</value> + </param> + <param> + <key>tr_level</key> + <value>0.0</value> + </param> + <param> + <key>tr_chan</key> + <value>0</value> + </param> + <param> + <key>tr_tag</key> + <value>""</value> + </param> + <param> + <key>legend</key> + <value>True</value> + </param> + <param> + <key>label1</key> + <value></value> + </param> + <param> + <key>width1</key> + <value>1</value> + </param> + <param> + <key>color1</key> + <value>"blue"</value> + </param> + <param> + <key>style1</key> + <value>0</value> + </param> + <param> + <key>marker1</key> + <value>0</value> + </param> + <param> + <key>alpha1</key> + <value>1.0</value> + </param> + <param> + <key>label2</key> + <value></value> + </param> + <param> + <key>width2</key> + <value>1</value> + </param> + <param> + <key>color2</key> + <value>"red"</value> + </param> + <param> + <key>style2</key> + <value>0</value> + </param> + <param> + <key>marker2</key> + <value>0</value> + </param> + <param> + <key>alpha2</key> + <value>1.0</value> + </param> + <param> + <key>label3</key> + <value></value> + </param> + <param> + <key>width3</key> + <value>1</value> + </param> + <param> + <key>color3</key> + <value>"red"</value> + </param> + <param> + <key>style3</key> + <value>0</value> + </param> + <param> + <key>marker3</key> + <value>0</value> + </param> + <param> + <key>alpha3</key> + <value>1.0</value> + </param> + <param> + <key>label4</key> + <value></value> + </param> + <param> + <key>width4</key> + <value>1</value> + </param> + <param> + <key>color4</key> + <value>"red"</value> + </param> + <param> + <key>style4</key> + <value>0</value> + </param> + <param> + <key>marker4</key> + <value>0</value> + </param> + <param> + <key>alpha4</key> + <value>1.0</value> + </param> + <param> + <key>label5</key> + <value></value> + </param> + <param> + <key>width5</key> + <value>1</value> + </param> + <param> + <key>color5</key> + <value>"red"</value> + </param> + <param> + <key>style5</key> + <value>0</value> + </param> + <param> + <key>marker5</key> + <value>0</value> + </param> + <param> + <key>alpha5</key> + <value>1.0</value> + </param> + <param> + <key>label6</key> + <value></value> + </param> + <param> + <key>width6</key> + <value>1</value> + </param> + <param> + <key>color6</key> + <value>"red"</value> + </param> + <param> + <key>style6</key> + <value>0</value> + </param> + <param> + <key>marker6</key> + <value>0</value> + </param> + <param> + <key>alpha6</key> + <value>1.0</value> + </param> + <param> + <key>label7</key> + <value></value> + </param> + <param> + <key>width7</key> + <value>1</value> + </param> + <param> + <key>color7</key> + <value>"red"</value> + </param> + <param> + <key>style7</key> + <value>0</value> + </param> + <param> + <key>marker7</key> + <value>0</value> + </param> + <param> + <key>alpha7</key> + <value>1.0</value> + </param> + <param> + <key>label8</key> + <value></value> + </param> + <param> + <key>width8</key> + <value>1</value> + </param> + <param> + <key>color8</key> + <value>"red"</value> + </param> + <param> + <key>style8</key> + <value>0</value> + </param> + <param> + <key>marker8</key> + <value>0</value> + </param> + <param> + <key>alpha8</key> + <value>1.0</value> + </param> + <param> + <key>label9</key> + <value></value> + </param> + <param> + <key>width9</key> + <value>1</value> + </param> + <param> + <key>color9</key> + <value>"red"</value> + </param> + <param> + <key>style9</key> + <value>0</value> + </param> + <param> + <key>marker9</key> + <value>0</value> + </param> + <param> + <key>alpha9</key> + <value>1.0</value> + </param> + <param> + <key>label10</key> + <value></value> + </param> + <param> + <key>width10</key> + <value>1</value> + </param> + <param> + <key>color10</key> + <value>"red"</value> + </param> + <param> + <key>style10</key> + <value>0</value> + </param> + <param> + <key>marker10</key> + <value>0</value> + </param> + <param> + <key>alpha10</key> + <value>1.0</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(360, 555)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>samp_rate</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>(8000000.0 * 8) / 7</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(8, 83)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>dtv_dvbt_energy_dispersal</key> + <param> + <key>id</key> + <value>dtv_dvbt_energy_dispersal_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>nsize</key> + <value>1</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(328, 96)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>dtv_dvbt_reed_solomon_enc</key> + <param> + <key>id</key> + <value>dtv_dvbt_reed_solomon_enc_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>p</key> + <value>2</value> + </param> + <param> + <key>m</key> + <value>8</value> + </param> + <param> + <key>gfpoly</key> + <value>0x11d</value> + </param> + <param> + <key>n</key> + <value>255</value> + </param> + <param> + <key>k</key> + <value>239</value> + </param> + <param> + <key>t</key> + <value>8</value> + </param> + <param> + <key>s</key> + <value>51</value> + </param> + <param> + <key>blocks</key> + <value>8</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(512, 43)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>dtv_dvbt_convolutional_interleaver</key> + <param> + <key>id</key> + <value>dtv_dvbt_convolutional_interleaver_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>blocks</key> + <value>136</value> + </param> + <param> + <key>I</key> + <value>12</value> + </param> + <param> + <key>M</key> + <value>17</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(736, 75)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_file_source</key> + <param> + <key>id</key> + <value>blocks_file_source_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>file</key> + <value>/run/shm/advtest.ts</value> + </param> + <param> + <key>type</key> + <value>byte</value> + </param> + <param> + <key>repeat</key> + <value>True</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(112, 83)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>uhd_usrp_sink</key> + <param> + <key>id</key> + <value>uhd_usrp_sink_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>fc32</value> + </param> + <param> + <key>otw</key> + <value></value> + </param> + <param> + <key>stream_args</key> + <value></value> + </param> + <param> + <key>stream_chans</key> + <value>[]</value> + </param> + <param> + <key>dev_addr</key> + <value>"send_frame_size=65536,num_send_frames=128,master_clock_rate=" + str(samp_rate*4)</value> + </param> + <param> + <key>dev_args</key> + <value>""</value> + </param> + <param> + <key>sync</key> + <value></value> + </param> + <param> + <key>clock_rate</key> + <value>0.0</value> + </param> + <param> + <key>num_mboards</key> + <value>1</value> + </param> + <param> + <key>clock_source0</key> + <value></value> + </param> + <param> + <key>time_source0</key> + <value></value> + </param> + <param> + <key>sd_spec0</key> + <value></value> + </param> + <param> + <key>clock_source1</key> + <value></value> + </param> + <param> + <key>time_source1</key> + <value></value> + </param> + <param> + <key>sd_spec1</key> + <value></value> + </param> + <param> + <key>clock_source2</key> + <value></value> + </param> + <param> + <key>time_source2</key> + <value></value> + </param> + <param> + <key>sd_spec2</key> + <value></value> + </param> + <param> + <key>clock_source3</key> + <value></value> + </param> + <param> + <key>time_source3</key> + <value></value> + </param> + <param> + <key>sd_spec3</key> + <value></value> + </param> + <param> + <key>clock_source4</key> + <value></value> + </param> + <param> + <key>time_source4</key> + <value></value> + </param> + <param> + <key>sd_spec4</key> + <value></value> + </param> + <param> + <key>clock_source5</key> + <value></value> + </param> + <param> + <key>time_source5</key> + <value></value> + </param> + <param> + <key>sd_spec5</key> + <value></value> + </param> + <param> + <key>clock_source6</key> + <value></value> + </param> + <param> + <key>time_source6</key> + <value></value> + </param> + <param> + <key>sd_spec6</key> + <value></value> + </param> + <param> + <key>clock_source7</key> + <value></value> + </param> + <param> + <key>time_source7</key> + <value></value> + </param> + <param> + <key>sd_spec7</key> + <value></value> + </param> + <param> + <key>nchan</key> + <value>1</value> + </param> + <param> + <key>samp_rate</key> + <value>samp_rate</value> + </param> + <param> + <key>center_freq0</key> + <value>429000000</value> + </param> + <param> + <key>gain0</key> + <value>50</value> + </param> + <param> + <key>norm_gain0</key> + <value>False</value> + </param> + <param> + <key>ant0</key> + <value></value> + </param> + <param> + <key>bw0</key> + <value>0</value> + </param> + <param> + <key>center_freq1</key> + <value>0</value> + </param> + <param> + <key>gain1</key> + <value>0</value> + </param> + <param> + <key>norm_gain1</key> + <value>False</value> + </param> + <param> + <key>ant1</key> + <value></value> + </param> + <param> + <key>bw1</key> + <value>0</value> + </param> + <param> + <key>center_freq2</key> + <value>0</value> + </param> + <param> + <key>gain2</key> + <value>0</value> + </param> + <param> + <key>norm_gain2</key> + <value>False</value> + </param> + <param> + <key>ant2</key> + <value></value> + </param> + <param> + <key>bw2</key> + <value>0</value> + </param> + <param> + <key>center_freq3</key> + <value>0</value> + </param> + <param> + <key>gain3</key> + <value>0</value> + </param> + <param> + <key>norm_gain3</key> + <value>False</value> + </param> + <param> + <key>ant3</key> + <value></value> + </param> + <param> + <key>bw3</key> + <value>0</value> + </param> + <param> + <key>center_freq4</key> + <value>0</value> + </param> + <param> + <key>gain4</key> + <value>0</value> + </param> + <param> + <key>norm_gain4</key> + <value>False</value> + </param> + <param> + <key>ant4</key> + <value></value> + </param> + <param> + <key>bw4</key> + <value>0</value> + </param> + <param> + <key>center_freq5</key> + <value>0</value> + </param> + <param> + <key>gain5</key> + <value>0</value> + </param> + <param> + <key>norm_gain5</key> + <value>False</value> + </param> + <param> + <key>ant5</key> + <value></value> + </param> + <param> + <key>bw5</key> + <value>0</value> + </param> + <param> + <key>center_freq6</key> + <value>0</value> + </param> + <param> + <key>gain6</key> + <value>0</value> + </param> + <param> + <key>norm_gain6</key> + <value>False</value> + </param> + <param> + <key>ant6</key> + <value></value> + </param> + <param> + <key>bw6</key> + <value>0</value> + </param> + <param> + <key>center_freq7</key> + <value>0</value> + </param> + <param> + <key>gain7</key> + <value>0</value> + </param> + <param> + <key>norm_gain7</key> + <value>False</value> + </param> + <param> + <key>ant7</key> + <value></value> + </param> + <param> + <key>bw7</key> + <value>0</value> + </param> + <param> + <key>center_freq8</key> + <value>0</value> + </param> + <param> + <key>gain8</key> + <value>0</value> + </param> + <param> + <key>norm_gain8</key> + <value>False</value> + </param> + <param> + <key>ant8</key> + <value></value> + </param> + <param> + <key>bw8</key> + <value>0</value> + </param> + <param> + <key>center_freq9</key> + <value>0</value> + </param> + <param> + <key>gain9</key> + <value>0</value> + </param> + <param> + <key>norm_gain9</key> + <value>False</value> + </param> + <param> + <key>ant9</key> + <value></value> + </param> + <param> + <key>bw9</key> + <value>0</value> + </param> + <param> + <key>center_freq10</key> + <value>0</value> + </param> + <param> + <key>gain10</key> + <value>0</value> + </param> + <param> + <key>norm_gain10</key> + <value>False</value> + </param> + <param> + <key>ant10</key> + <value></value> + </param> + <param> + <key>bw10</key> + <value>0</value> + </param> + <param> + <key>center_freq11</key> + <value>0</value> + </param> + <param> + <key>gain11</key> + <value>0</value> + </param> + <param> + <key>norm_gain11</key> + <value>False</value> + </param> + <param> + <key>ant11</key> + <value></value> + </param> + <param> + <key>bw11</key> + <value>0</value> + </param> + <param> + <key>center_freq12</key> + <value>0</value> + </param> + <param> + <key>gain12</key> + <value>0</value> + </param> + <param> + <key>norm_gain12</key> + <value>False</value> + </param> + <param> + <key>ant12</key> + <value></value> + </param> + <param> + <key>bw12</key> + <value>0</value> + </param> + <param> + <key>center_freq13</key> + <value>0</value> + </param> + <param> + <key>gain13</key> + <value>0</value> + </param> + <param> + <key>norm_gain13</key> + <value>False</value> + </param> + <param> + <key>ant13</key> + <value></value> + </param> + <param> + <key>bw13</key> + <value>0</value> + </param> + <param> + <key>center_freq14</key> + <value>0</value> + </param> + <param> + <key>gain14</key> + <value>0</value> + </param> + <param> + <key>norm_gain14</key> + <value>False</value> + </param> + <param> + <key>ant14</key> + <value></value> + </param> + <param> + <key>bw14</key> + <value>0</value> + </param> + <param> + <key>center_freq15</key> + <value>0</value> + </param> + <param> + <key>gain15</key> + <value>0</value> + </param> + <param> + <key>norm_gain15</key> + <value>False</value> + </param> + <param> + <key>ant15</key> + <value></value> + </param> + <param> + <key>bw15</key> + <value>0</value> + </param> + <param> + <key>center_freq16</key> + <value>0</value> + </param> + <param> + <key>gain16</key> + <value>0</value> + </param> + <param> + <key>norm_gain16</key> + <value>False</value> + </param> + <param> + <key>ant16</key> + <value></value> + </param> + <param> + <key>bw16</key> + <value>0</value> + </param> + <param> + <key>center_freq17</key> + <value>0</value> + </param> + <param> + <key>gain17</key> + <value>0</value> + </param> + <param> + <key>norm_gain17</key> + <value>False</value> + </param> + <param> + <key>ant17</key> + <value></value> + </param> + <param> + <key>bw17</key> + <value>0</value> + </param> + <param> + <key>center_freq18</key> + <value>0</value> + </param> + <param> + <key>gain18</key> + <value>0</value> + </param> + <param> + <key>norm_gain18</key> + <value>False</value> + </param> + <param> + <key>ant18</key> + <value></value> + </param> + <param> + <key>bw18</key> + <value>0</value> + </param> + <param> + <key>center_freq19</key> + <value>0</value> + </param> + <param> + <key>gain19</key> + <value>0</value> + </param> + <param> + <key>norm_gain19</key> + <value>False</value> + </param> + <param> + <key>ant19</key> + <value></value> + </param> + <param> + <key>bw19</key> + <value>0</value> + </param> + <param> + <key>center_freq20</key> + <value>0</value> + </param> + <param> + <key>gain20</key> + <value>0</value> + </param> + <param> + <key>norm_gain20</key> + <value>False</value> + </param> + <param> + <key>ant20</key> + <value></value> + </param> + <param> + <key>bw20</key> + <value>0</value> + </param> + <param> + <key>center_freq21</key> + <value>0</value> + </param> + <param> + <key>gain21</key> + <value>0</value> + </param> + <param> + <key>norm_gain21</key> + <value>False</value> + </param> + <param> + <key>ant21</key> + <value></value> + </param> + <param> + <key>bw21</key> + <value>0</value> + </param> + <param> + <key>center_freq22</key> + <value>0</value> + </param> + <param> + <key>gain22</key> + <value>0</value> + </param> + <param> + <key>norm_gain22</key> + <value>False</value> + </param> + <param> + <key>ant22</key> + <value></value> + </param> + <param> + <key>bw22</key> + <value>0</value> + </param> + <param> + <key>center_freq23</key> + <value>0</value> + </param> + <param> + <key>gain23</key> + <value>0</value> + </param> + <param> + <key>norm_gain23</key> + <value>False</value> + </param> + <param> + <key>ant23</key> + <value></value> + </param> + <param> + <key>bw23</key> + <value>0</value> + </param> + <param> + <key>center_freq24</key> + <value>0</value> + </param> + <param> + <key>gain24</key> + <value>0</value> + </param> + <param> + <key>norm_gain24</key> + <value>False</value> + </param> + <param> + <key>ant24</key> + <value></value> + </param> + <param> + <key>bw24</key> + <value>0</value> + </param> + <param> + <key>center_freq25</key> + <value>0</value> + </param> + <param> + <key>gain25</key> + <value>0</value> + </param> + <param> + <key>norm_gain25</key> + <value>False</value> + </param> + <param> + <key>ant25</key> + <value></value> + </param> + <param> + <key>bw25</key> + <value>0</value> + </param> + <param> + <key>center_freq26</key> + <value>0</value> + </param> + <param> + <key>gain26</key> + <value>0</value> + </param> + <param> + <key>norm_gain26</key> + <value>False</value> + </param> + <param> + <key>ant26</key> + <value></value> + </param> + <param> + <key>bw26</key> + <value>0</value> + </param> + <param> + <key>center_freq27</key> + <value>0</value> + </param> + <param> + <key>gain27</key> + <value>0</value> + </param> + <param> + <key>norm_gain27</key> + <value>False</value> + </param> + <param> + <key>ant27</key> + <value></value> + </param> + <param> + <key>bw27</key> + <value>0</value> + </param> + <param> + <key>center_freq28</key> + <value>0</value> + </param> + <param> + <key>gain28</key> + <value>0</value> + </param> + <param> + <key>norm_gain28</key> + <value>False</value> + </param> + <param> + <key>ant28</key> + <value></value> + </param> + <param> + <key>bw28</key> + <value>0</value> + </param> + <param> + <key>center_freq29</key> + <value>0</value> + </param> + <param> + <key>gain29</key> + <value>0</value> + </param> + <param> + <key>norm_gain29</key> + <value>False</value> + </param> + <param> + <key>ant29</key> + <value></value> + </param> + <param> + <key>bw29</key> + <value>0</value> + </param> + <param> + <key>center_freq30</key> + <value>0</value> + </param> + <param> + <key>gain30</key> + <value>0</value> + </param> + <param> + <key>norm_gain30</key> + <value>False</value> + </param> + <param> + <key>ant30</key> + <value></value> + </param> + <param> + <key>bw30</key> + <value>0</value> + </param> + <param> + <key>center_freq31</key> + <value>0</value> + </param> + <param> + <key>gain31</key> + <value>0</value> + </param> + <param> + <key>norm_gain31</key> + <value>False</value> + </param> + <param> + <key>ant31</key> + <value></value> + </param> + <param> + <key>bw31</key> + <value>0</value> + </param> + <param> + <key>len_tag_name</key> + <value></value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(984, 387)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_multiply_const_vxx</key> + <param> + <key>id</key> + <value>blocks_multiply_const_vxx_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>const</key> + <value>0.0022097087</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(664, 435)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>options</key> + <param> + <key>id</key> + <value>dvbt_tx_demo</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>title</key> + <value></value> + </param> + <param> + <key>author</key> + <value></value> + </param> + <param> + <key>description</key> + <value></value> + </param> + <param> + <key>window_size</key> + <value>1280, 1024</value> + </param> + <param> + <key>generate_options</key> + <value>qt_gui</value> + </param> + <param> + <key>category</key> + <value>Custom</value> + </param> + <param> + <key>run_options</key> + <value>prompt</value> + </param> + <param> + <key>run</key> + <value>True</value> + </param> + <param> + <key>max_nouts</key> + <value>0</value> + </param> + <param> + <key>realtime_scheduling</key> + <value></value> + </param> + <param> + <key>thread_safe_setters</key> + <value></value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(8, 11)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>dtv_dvbt_bit_inner_interleaver</key> + <param> + <key>id</key> + <value>dtv_dvbt_bit_inner_interleaver_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>constellation</key> + <value>64qam</value> + </param> + <param> + <key>hierarchy</key> + <value>nh</value> + </param> + <param> + <key>transmission_mode</key> + <value>T8k</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(984, 243)</value> + </param> + <param> + <key>_rotation</key> + <value>180</value> + </param> + </block> + <block> + <key>dtv_dvbt_symbol_inner_interleaver</key> + <param> + <key>id</key> + <value>dtv_dvbt_symbol_inner_interleaver_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>transmission_mode</key> + <value>T8k</value> + </param> + <param> + <key>direction</key> + <value>Interleave</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(664, 243)</value> + </param> + <param> + <key>_rotation</key> + <value>180</value> + </param> + </block> + <block> + <key>dtv_dvbt_map</key> + <param> + <key>id</key> + <value>dtv_dvbt_map_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>constellation</key> + <value>64qam</value> + </param> + <param> + <key>hierarchy</key> + <value>nh</value> + </param> + <param> + <key>transmission_mode</key> + <value>T8k</value> + </param> + <param> + <key>gain</key> + <value>1</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(344, 227)</value> + </param> + <param> + <key>_rotation</key> + <value>180</value> + </param> + </block> + <block> + <key>dtv_dvbt_reference_signals</key> + <param> + <key>id</key> + <value>dtv_dvbt_reference_signals_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>constellation</key> + <value>64qam</value> + </param> + <param> + <key>hierarchy</key> + <value>nh</value> + </param> + <param> + <key>code_rate_hp</key> + <value>C2_3</value> + </param> + <param> + <key>code_rate_lp</key> + <value>C2_3</value> + </param> + <param> + <key>guard_interval</key> + <value>GI_1_32</value> + </param> + <param> + <key>transmission_mode</key> + <value>T8k</value> + </param> + <param> + <key>include_cell_id</key> + <value>cell_ide_no</value> + </param> + <param> + <key>cell_id</key> + <value>0</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(40, 187)</value> + </param> + <param> + <key>_rotation</key> + <value>180</value> + </param> + </block> + <block> + <key>fft_vxx</key> + <param> + <key>id</key> + <value>fft_vxx_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>fft_size</key> + <value>8192</value> + </param> + <param> + <key>forward</key> + <value>False</value> + </param> + <param> + <key>window</key> + <value>window.rectangular(8192)</value> + </param> + <param> + <key>shift</key> + <value>True</value> + </param> + <param> + <key>nthreads</key> + <value>1</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(64, 403)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_vector_to_stream</key> + <param> + <key>id</key> + <value>blocks_vector_to_stream_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>num_items</key> + <value>8192</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(120, 563)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>digital_ofdm_cyclic_prefixer</key> + <param> + <key>id</key> + <value>digital_ofdm_cyclic_prefixer_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>input_size</key> + <value>8192</value> + </param> + <param> + <key>cp_len</key> + <value>256</value> + </param> + <param> + <key>rolloff</key> + <value>0</value> + </param> + <param> + <key>tagname</key> + <value></value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(392, 419)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>dtv_dvbt_inner_coder</key> + <param> + <key>id</key> + <value>dtv_dvbt_inner_coder_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>ninput</key> + <value>1</value> + </param> + <param> + <key>noutput</key> + <value>6048</value> + </param> + <param> + <key>constellation</key> + <value>64qam</value> + </param> + <param> + <key>hierarchy</key> + <value>nh</value> + </param> + <param> + <key>code_rate</key> + <value>C2_3</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(1000, 67)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <connection> + <source_block_id>digital_ofdm_cyclic_prefixer_0</source_block_id> + <sink_block_id>blocks_multiply_const_vxx_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>fft_vxx_0</source_block_id> + <sink_block_id>digital_ofdm_cyclic_prefixer_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>blocks_multiply_const_vxx_0</source_block_id> + <sink_block_id>uhd_usrp_sink_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>blocks_file_source_0</source_block_id> + <sink_block_id>dtv_dvbt_energy_dispersal_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>dtv_dvbt_energy_dispersal_0</source_block_id> + <sink_block_id>dtv_dvbt_reed_solomon_enc_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>dtv_dvbt_convolutional_interleaver_0</source_block_id> + <sink_block_id>dtv_dvbt_inner_coder_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>dtv_dvbt_inner_coder_0</source_block_id> + <sink_block_id>dtv_dvbt_bit_inner_interleaver_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>dtv_dvbt_bit_inner_interleaver_0</source_block_id> + <sink_block_id>dtv_dvbt_symbol_inner_interleaver_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>dtv_dvbt_symbol_inner_interleaver_0</source_block_id> + <sink_block_id>dtv_dvbt_map_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>dtv_dvbt_map_0</source_block_id> + <sink_block_id>dtv_dvbt_reference_signals_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>dtv_dvbt_reference_signals_0</source_block_id> + <sink_block_id>fft_vxx_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>dtv_dvbt_reference_signals_0</source_block_id> + <sink_block_id>blocks_vector_to_stream_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>blocks_vector_to_stream_0</source_block_id> + <sink_block_id>qtgui_const_sink_x_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>dtv_dvbt_reed_solomon_enc_0</source_block_id> + <sink_block_id>dtv_dvbt_convolutional_interleaver_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> +</flow_graph> diff --git a/gr-dtv/grc/CMakeLists.txt b/gr-dtv/grc/CMakeLists.txt index ce2d71883e..2187e283a5 100644 --- a/gr-dtv/grc/CMakeLists.txt +++ b/gr-dtv/grc/CMakeLists.txt @@ -52,6 +52,14 @@ install(FILES dtv_dvbs2_interleaver_bb.xml dtv_dvbs2_modulator_bc.xml dtv_dvbs2_physical_cc.xml + dtv_dvbt_energy_dispersal.xml + dtv_dvbt_reed_solomon_enc.xml + dtv_dvbt_convolutional_interleaver.xml + dtv_dvbt_inner_coder.xml + dtv_dvbt_bit_inner_interleaver.xml + dtv_dvbt_symbol_inner_interleaver.xml + dtv_dvbt_map.xml + dtv_dvbt_reference_signals.xml DESTINATION ${GRC_BLOCKS_DIR} COMPONENT "dtv_python" ) diff --git a/gr-dtv/grc/dtv_block_tree.xml b/gr-dtv/grc/dtv_block_tree.xml index 770b7ec0fe..1f05bc75dc 100644 --- a/gr-dtv/grc/dtv_block_tree.xml +++ b/gr-dtv/grc/dtv_block_tree.xml @@ -75,5 +75,16 @@ <block>dtv_dvbs2_modulator_bc</block> <block>dtv_dvbs2_physical_cc</block> </cat> + <cat> + <name>DVB-T</name> + <block>dtv_dvbt_energy_dispersal</block> + <block>dtv_dvbt_reed_solomon_enc</block> + <block>dtv_dvbt_convolutional_interleaver</block> + <block>dtv_dvbt_inner_coder</block> + <block>dtv_dvbt_bit_inner_interleaver</block> + <block>dtv_dvbt_symbol_inner_interleaver</block> + <block>dtv_dvbt_map</block> + <block>dtv_dvbt_reference_signals</block> + </cat> </cat> </cat> diff --git a/gr-dtv/grc/dtv_dvbt_bit_inner_interleaver.xml b/gr-dtv/grc/dtv_dvbt_bit_inner_interleaver.xml new file mode 100644 index 0000000000..31f1c2cfa5 --- /dev/null +++ b/gr-dtv/grc/dtv_dvbt_bit_inner_interleaver.xml @@ -0,0 +1,89 @@ +<?xml version="1.0"?> +<!-- +################################################### +## DVB-T Bit Inner Interleaver +################################################### + --> +<block> + <name>Bit Inner Interleaver</name> + <key>dtv_dvbt_bit_inner_interleaver</key> + <import>from gnuradio import dtv</import> + <make>dtv.dvbt_bit_inner_interleaver($transmission_mode.payload_length, $constellation.val, $hierarchy.val, $transmission_mode.val)</make> + <param> + <name>Constellation Type</name> + <key>constellation</key> + <type>enum</type> + <option> + <name>QPSK</name> + <key>qpsk</key> + <opt>val:dtv.MOD_QPSK</opt> + </option> + <option> + <name>16QAM</name> + <key>16qam</key> + <opt>val:dtv.MOD_16QAM</opt> + </option> + <option> + <name>64QAM</name> + <key>64qam</key> + <opt>val:dtv.MOD_64QAM</opt> + </option> + </param> + <param> + <name>Hierarchy Type</name> + <key>hierarchy</key> + <type>enum</type> + <option> + <name>Non Hierarchical</name> + <key>nh</key> + <opt>val:dtv.NH</opt> + <opt>num_streams:1</opt> + </option> + <option> + <name>Alpha 1</name> + <key>alpha1</key> + <opt>val:dtv.ALPHA1</opt> + <opt>num_streams:2</opt> + </option> + <option> + <name>Alpha 2</name> + <key>alpha2</key> + <opt>val:dtv.ALPHA2</opt> + <opt>num_streams:2</opt> + </option> + <option> + <name>Alpha 4</name> + <key>alpha4</key> + <opt>val:dtv.ALPHA4</opt> + <opt>num_streams:2</opt> + </option> + </param> + <param> + <name>Transmission Mode</name> + <key>transmission_mode</key> + <type>enum</type> + <option> + <name>2K</name> + <key>T2k</key> + <opt>val:dtv.T2k</opt> + <opt>payload_length:1512</opt> + </option> + <option> + <name>8K</name> + <key>T8k</key> + <opt>val:dtv.T8k</opt> + <opt>payload_length:6048</opt> + </option> + </param> + <sink> + <name>in</name> + <type>byte</type> + <vlen>$transmission_mode.payload_length</vlen> + <nports>$hierarchy.num_streams</nports> + </sink> + <source> + <name>out</name> + <type>byte</type> + <vlen>$transmission_mode.payload_length</vlen> + </source> +</block> diff --git a/gr-dtv/grc/dtv_dvbt_convolutional_interleaver.xml b/gr-dtv/grc/dtv_dvbt_convolutional_interleaver.xml new file mode 100644 index 0000000000..04518dd622 --- /dev/null +++ b/gr-dtv/grc/dtv_dvbt_convolutional_interleaver.xml @@ -0,0 +1,43 @@ +<?xml version="1.0"?> +<!-- +################################################### +## DVB-T Convolutional Interleaver +################################################### + --> +<block> + <name>Convolutional Interleaver</name> + <key>dtv_dvbt_convolutional_interleaver</key> + <import>from gnuradio import dtv</import> + <make>dtv.dvbt_convolutional_interleaver($blocks, $I, $M)</make> + <param> + <name>Blocks (12 Bytes)</name> + <key>blocks</key> + <value>136</value> + <type>int</type> + </param> + <param> + <name>Number of Shift registers</name> + <key>I</key> + <value>12</value> + <type>int</type> + </param> + <param> + <name>Depth of shift registers</name> + <key>M</key> + <value>17</value> + <type>int</type> + </param> + <check>$blocks > 0</check> + <check>$I > 0</check> + <check>$M > 0</check> + <sink> + <name>in</name> + <type>byte</type> + <vlen>$blocks*$I</vlen> + </sink> + <source> + <name>out</name> + <type>byte</type> + <vlen>1</vlen> + </source> +</block> diff --git a/gr-dtv/grc/dtv_dvbt_energy_dispersal.xml b/gr-dtv/grc/dtv_dvbt_energy_dispersal.xml new file mode 100644 index 0000000000..50746c8e4d --- /dev/null +++ b/gr-dtv/grc/dtv_dvbt_energy_dispersal.xml @@ -0,0 +1,29 @@ +<?xml version="1.0"?> +<!-- +################################################### +## DVB-T Energy Dispersal +################################################### + --> +<block> + <name>Energy Dispersal</name> + <key>dtv_dvbt_energy_dispersal</key> + <import>from gnuradio import dtv</import> + <make>dtv.dvbt_energy_dispersal($nsize)</make> + <param> + <name>Blocks(1504 Bytes)</name> + <key>nsize</key> + <value>8</value> + <type>int</type> + </param> + <check>$nsize > 0</check> + <sink> + <name>in</name> + <type>byte</type> + <vlen>1</vlen> + </sink> + <source> + <name>out</name> + <type>byte</type> + <vlen>1504*$nsize</vlen> + </source> +</block> diff --git a/gr-dtv/grc/dtv_dvbt_inner_coder.xml b/gr-dtv/grc/dtv_dvbt_inner_coder.xml new file mode 100644 index 0000000000..4751065dd1 --- /dev/null +++ b/gr-dtv/grc/dtv_dvbt_inner_coder.xml @@ -0,0 +1,112 @@ +<?xml version="1.0"?> +<!-- +################################################### +## DVB-T Inner Coder +################################################### + --> +<block> + <name>Inner Coder</name> + <key>dtv_dvbt_inner_coder</key> + <import>from gnuradio import dtv</import> + <make>dtv.dvbt_inner_coder($ninput, $noutput, $constellation.val, $hierarchy.val, $code_rate.val)</make> + <param> + <name>Input length</name> + <key>ninput</key> + <value>1</value> + <type>int</type> + </param> + <param> + <name>Output length</name> + <key>noutput</key> + <value>1512</value> + <type>int</type> + </param> + <param> + <name>Constellation Type</name> + <key>constellation</key> + <type>enum</type> + <option> + <name>QPSK</name> + <key>qpsk</key> + <opt>val:dtv.MOD_QPSK</opt> + </option> + <option> + <name>16QAM</name> + <key>16qam</key> + <opt>val:dtv.MOD_16QAM</opt> + </option> + <option> + <name>64QAM</name> + <key>64qam</key> + <opt>val:dtv.MOD_64QAM</opt> + </option> + </param> + <param> + <name>Hierarchy Type</name> + <key>hierarchy</key> + <type>enum</type> + <option> + <name>Non Hierarchical</name> + <key>nh</key> + <opt>val:dtv.NH</opt> + </option> + <option> + <name>Alpha 1</name> + <key>alpha1</key> + <opt>val:dtv.ALPHA1</opt> + </option> + <option> + <name>Alpha 2</name> + <key>alpha2</key> + <opt>val:dtv.ALPHA2</opt> + </option> + <option> + <name>Alpha 4</name> + <key>alpha4</key> + <opt>val:dtv.ALPHA4</opt> + </option> + </param> + <param> + <name>Code rate</name> + <key>code_rate</key> + <type>enum</type> + <option> + <name>1/2</name> + <key>C1_2</key> + <opt>val:dtv.C1_2</opt> + </option> + <option> + <name>2/3</name> + <key>C2_3</key> + <opt>val:dtv.C2_3</opt> + </option> + <option> + <name>3/4</name> + <key>C3_4</key> + <opt>val:dtv.C3_4</opt> + </option> + <option> + <name>5/6</name> + <key>C5_6</key> + <opt>val:dtv.C5_6</opt> + </option> + <option> + <name>7/8</name> + <key>C7_8</key> + <opt>val:dtv.C7_8</opt> + </option> + </param> + <check>$ninput > 0</check> + <check>$noutput > 0</check> + <check>$noutput >= $ninput</check> + <sink> + <name>in</name> + <type>byte</type> + <vlen>$ninput</vlen> + </sink> + <source> + <name>out</name> + <type>byte</type> + <vlen>$noutput</vlen> + </source> +</block> diff --git a/gr-dtv/grc/dtv_dvbt_map.xml b/gr-dtv/grc/dtv_dvbt_map.xml new file mode 100644 index 0000000000..705a508033 --- /dev/null +++ b/gr-dtv/grc/dtv_dvbt_map.xml @@ -0,0 +1,90 @@ +<?xml version="1.0"?> +<!-- +################################################### +## DVB-T Map +################################################### + --> +<block> + <name>DVB-T Map</name> + <key>dtv_dvbt_map</key> + <import>from gnuradio import dtv</import> + <make>dtv.dvbt_map($transmission_mode.payload_length, $constellation.val, $hierarchy.val, $transmission_mode.val, $gain)</make> + <param> + <name>Constellation Type</name> + <key>constellation</key> + <type>enum</type> + <option> + <name>QPSK</name> + <key>qpsk</key> + <opt>val:dtv.MOD_QPSK</opt> + </option> + <option> + <name>16QAM</name> + <key>16qam</key> + <opt>val:dtv.MOD_16QAM</opt> + </option> + <option> + <name>64QAM</name> + <key>64qam</key> + <opt>val:dtv.MOD_64QAM</opt> + </option> + </param> + <param> + <name>Hierarchy Type</name> + <key>hierarchy</key> + <type>enum</type> + <option> + <name>Non Hierarchical</name> + <key>nh</key> + <opt>val:dtv.NH</opt> + </option> + <option> + <name>Alpha 1</name> + <key>alpha1</key> + <opt>val:dtv.ALPHA1</opt> + </option> + <option> + <name>Alpha 2</name> + <key>alpha2</key> + <opt>val:dtv.ALPHA2</opt> + </option> + <option> + <name>Alpha 4</name> + <key>alpha4</key> + <opt>val:dtv.ALPHA4</opt> + </option> + </param> + <param> + <name>Transmission Mode</name> + <key>transmission_mode</key> + <type>enum</type> + <option> + <name>2K</name> + <key>T2k</key> + <opt>val:dtv.T2k</opt> + <opt>payload_length:1512</opt> + </option> + <option> + <name>8K</name> + <key>T8k</key> + <opt>val:dtv.T8k</opt> + <opt>payload_length:6048</opt> + </option> + </param> + <param> + <name>Gain</name> + <key>gain</key> + <value>1</value> + <type>complex</type> + </param> + <sink> + <name>in</name> + <type>byte</type> + <vlen>$transmission_mode.payload_length</vlen> + </sink> + <source> + <name>out</name> + <type>complex</type> + <vlen>$transmission_mode.payload_length</vlen> + </source> +</block> diff --git a/gr-dtv/grc/dtv_dvbt_reed_solomon_enc.xml b/gr-dtv/grc/dtv_dvbt_reed_solomon_enc.xml new file mode 100644 index 0000000000..3dd57a7df0 --- /dev/null +++ b/gr-dtv/grc/dtv_dvbt_reed_solomon_enc.xml @@ -0,0 +1,70 @@ +<?xml version="1.0"?> +<!-- +################################################### +## DVB-T Reed Solomon Encoder +################################################### + --> +<block> + <name>Reed-Solomon Encoder</name> + <key>dtv_dvbt_reed_solomon_enc</key> + <import>from gnuradio import dtv</import> + <make>dtv.dvbt_reed_solomon_enc($p, $m, $gfpoly, $n, $k, $t, $s, $blocks)</make> + <param> + <name>p</name> + <key>p</key> + <value>2</value> + <type>int</type> + </param> + <param> + <name>m</name> + <key>m</key> + <value>8</value> + <type>int</type> + </param> + <param> + <name>GF polynomial</name> + <key>gfpoly</key> + <value>0x11d</value> + <type>raw</type> + </param> + <param> + <name>N</name> + <key>n</key> + <value>255</value> + <type>int</type> + </param> + <param> + <name>K</name> + <key>k</key> + <value>239</value> + <type>int</type> + </param> + <param> + <name>t</name> + <key>t</key> + <value>8</value> + <type>int</type> + </param> + <param> + <name>Shortening size</name> + <key>s</key> + <value>51</value> + <type>int</type> + </param> + <param> + <name>Blocks</name> + <key>blocks</key> + <value>8</value> + <type>int</type> + </param> + <sink> + <name>in</name> + <type>byte</type> + <vlen>$blocks*($k-$s)</vlen> + </sink> + <source> + <name>out</name> + <type>byte</type> + <vlen>$blocks*($n-$s)</vlen> + </source> +</block> diff --git a/gr-dtv/grc/dtv_dvbt_reference_signals.xml b/gr-dtv/grc/dtv_dvbt_reference_signals.xml new file mode 100644 index 0000000000..9be57630e5 --- /dev/null +++ b/gr-dtv/grc/dtv_dvbt_reference_signals.xml @@ -0,0 +1,222 @@ +<?xml version="1.0"?> +<!-- +################################################### +## Reference Signals +################################################### + --> +<block> + <name>Reference Signals</name> + <key>dtv_dvbt_reference_signals</key> + <import>from gnuradio import dtv</import> + <make>dtv.dvbt_reference_signals($type.size, $transmission_mode.payload_length, $transmission_mode.fft_length, $constellation.val, $hierarchy.val, $code_rate_hp.val, $code_rate_lp.val, $guard_interval.val, $transmission_mode.val, $include_cell_id.val, $cell_id)</make> + <param> + <name>IO 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>Constellation Type</name> + <key>constellation</key> + <type>enum</type> + <option> + <name>QPSK</name> + <key>qpsk</key> + <opt>val:dtv.MOD_QPSK</opt> + </option> + <option> + <name>16QAM</name> + <key>16qam</key> + <opt>val:dtv.MOD_16QAM</opt> + </option> + <option> + <name>64QAM</name> + <key>64qam</key> + <opt>val:dtv.MOD_64QAM</opt> + </option> + </param> + <param> + <name>Hierarchy Type</name> + <key>hierarchy</key> + <type>enum</type> + <option> + <name>Non Hierarchical</name> + <key>nh</key> + <opt>val:dtv.NH</opt> + </option> + <option> + <name>Alpha 1</name> + <key>alpha1</key> + <opt>val:dtv.ALPHA1</opt> + </option> + <option> + <name>Alpha 2</name> + <key>alpha2</key> + <opt>val:dtv.ALPHA2</opt> + </option> + <option> + <name>Alpha 4</name> + <key>alpha4</key> + <opt>val:dtv.ALPHA4</opt> + </option> + </param> + <param> + <name>Code rate HP</name> + <key>code_rate_hp</key> + <type>enum</type> + <option> + <name>1/2</name> + <key>C1_2</key> + <opt>val:dtv.C1_2</opt> + </option> + <option> + <name>2/3</name> + <key>C2_3</key> + <opt>val:dtv.C2_3</opt> + </option> + <option> + <name>3/4</name> + <key>C3_4</key> + <opt>val:dtv.C3_4</opt> + </option> + <option> + <name>5/6</name> + <key>C5_6</key> + <opt>val:dtv.C5_6</opt> + </option> + <option> + <name>7/8</name> + <key>C7_8</key> + <opt>val:dtv.C7_8</opt> + </option> + </param> + <param> + <name>Code rate LP</name> + <key>code_rate_lp</key> + <type>enum</type> + <option> + <name>1/2</name> + <key>C1_2</key> + <opt>val:dtv.C1_2</opt> + </option> + <option> + <name>2/3</name> + <key>C2_3</key> + <opt>val:dtv.C2_3</opt> + </option> + <option> + <name>3/4</name> + <key>C3_4</key> + <opt>val:dtv.C3_4</opt> + </option> + <option> + <name>5/6</name> + <key>C5_6</key> + <opt>val:dtv.C5_6</opt> + </option> + <option> + <name>7/8</name> + <key>C7_8</key> + <opt>val:dtv.C7_8</opt> + </option> + </param> + <param> + <name>Guard Interval</name> + <key>guard_interval</key> + <type>enum</type> + <option> + <name>1/32</name> + <key>GI_1_32</key> + <opt>val:dtv.GI_1_32</opt> + </option> + <option> + <name>1/16</name> + <key>GI_1_16</key> + <opt>val:dtv.GI_1_16</opt> + </option> + <option> + <name>1/8</name> + <key>GI_1_8</key> + <opt>val:dtv.GI_1_8</opt> + </option> + <option> + <name>1/4</name> + <key>GI_1_4</key> + <opt>val:dtv.GI_1_4</opt> + </option> + </param> + <param> + <name>Transmission Mode</name> + <key>transmission_mode</key> + <type>enum</type> + <option> + <name>2K</name> + <key>T2k</key> + <opt>val:dtv.T2k</opt> + <opt>fft_length:2048</opt> + <opt>payload_length:1512</opt> + </option> + <option> + <name>8K</name> + <key>T8k</key> + <opt>val:dtv.T8k</opt> + <opt>fft_length:8192</opt> + <opt>payload_length:6048</opt> + </option> + </param> + <param> + <name>Include Cell ID</name> + <key>include_cell_id</key> + <type>enum</type> + <option> + <name>Yes</name> + <key>call_id_yes</key> + <opt>val:1</opt> + </option> + <option> + <name>No</name> + <key>cell_ide_no</key> + <opt>val:0</opt> + </option> + </param> + <param> + <name>Cell Id</name> + <key>cell_id</key> + <value>0</value> + <type>int</type> + </param> + <sink> + <name>in</name> + <type>complex</type> + <vlen>$transmission_mode.payload_length</vlen> + </sink> + <source> + <name>out</name> + <type>complex</type> + <vlen>$transmission_mode.fft_length</vlen> + </source> +</block> diff --git a/gr-dtv/grc/dtv_dvbt_symbol_inner_interleaver.xml b/gr-dtv/grc/dtv_dvbt_symbol_inner_interleaver.xml new file mode 100644 index 0000000000..f440769a46 --- /dev/null +++ b/gr-dtv/grc/dtv_dvbt_symbol_inner_interleaver.xml @@ -0,0 +1,56 @@ +<?xml version="1.0"?> +<!-- +################################################### +## DVB-T Symbol Inner Interleaver +################################################### + --> +<block> + <name>Symbol Inner Interleaver</name> + <key>dtv_dvbt_symbol_inner_interleaver</key> + <import>from gnuradio import dtv</import> + <make>dtv.dvbt_symbol_inner_interleaver($transmission_mode.payload_length, $transmission_mode.val, $direction.val)</make> + <param> + <name>Transmission Mode</name> + <key>transmission_mode</key> + <type>enum</type> + <option> + <name>2K</name> + <key>T2k</key> + <opt>val:dtv.T2k</opt> + <opt>fft_length:2048</opt> + <opt>payload_length:1512</opt> + </option> + <option> + <name>8K</name> + <key>T8k</key> + <opt>val:dtv.T8k</opt> + <opt>fft_length:8192</opt> + <opt>payload_length:6048</opt> + </option> + </param> + <param> + <name>Direction</name> + <key>direction</key> + <type>enum</type> + <option> + <name>Interleave</name> + <key>Interleave</key> + <opt>val:1</opt> + </option> + <option> + <name>Deinterleave</name> + <key>Deinterleave</key> + <opt>val:0</opt> + </option> + </param> + <sink> + <name>in</name> + <type>byte</type> + <vlen>$transmission_mode.payload_length</vlen> + </sink> + <source> + <name>out</name> + <type>byte</type> + <vlen>$transmission_mode.payload_length</vlen> + </source> +</block> diff --git a/gr-dtv/include/gnuradio/dtv/CMakeLists.txt b/gr-dtv/include/gnuradio/dtv/CMakeLists.txt index 97264492cb..d1eff3f891 100644 --- a/gr-dtv/include/gnuradio/dtv/CMakeLists.txt +++ b/gr-dtv/include/gnuradio/dtv/CMakeLists.txt @@ -39,6 +39,7 @@ install(FILES atsc_trellis_encoder.h atsc_field_sync_mux.h dvb_config.h + dvbt_config.h dvbs2_config.h dvbt2_config.h dvb_bbheader_bb.h @@ -57,6 +58,14 @@ install(FILES dvbs2_interleaver_bb.h dvbs2_modulator_bc.h dvbs2_physical_cc.h + dvbt_energy_dispersal.h + dvbt_reed_solomon_enc.h + dvbt_convolutional_interleaver.h + dvbt_inner_coder.h + dvbt_bit_inner_interleaver.h + dvbt_symbol_inner_interleaver.h + dvbt_map.h + dvbt_reference_signals.h DESTINATION ${GR_INCLUDE_DIR}/gnuradio/dtv COMPONENT "dtv_devel" ) diff --git a/gr-dtv/include/gnuradio/dtv/dvb_config.h b/gr-dtv/include/gnuradio/dtv/dvb_config.h index d08c9c882e..9405f966b0 100644 --- a/gr-dtv/include/gnuradio/dtv/dvb_config.h +++ b/gr-dtv/include/gnuradio/dtv/dvb_config.h @@ -38,6 +38,7 @@ namespace gr { C3_4, C4_5, C5_6, + C7_8, C8_9, C9_10, C13_45, @@ -97,6 +98,16 @@ namespace gr { MOD_OTHER, }; + enum dvb_guardinterval_t { + GI_1_32 = 0, + GI_1_16, + GI_1_8, + GI_1_4, + GI_1_128, + GI_19_128, + GI_19_256, + }; + } // namespace dtv } // namespace gr @@ -104,6 +115,7 @@ typedef gr::dtv::dvb_standard_t dvb_standard_t; typedef gr::dtv::dvb_code_rate_t dvb_code_rate_t; typedef gr::dtv::dvb_framesize_t dvb_framesize_t; typedef gr::dtv::dvb_constellation_t dvb_constellation_t; +typedef gr::dtv::dvb_guardinterval_t dvb_guardinterval_t; #endif /* INCLUDED_DTV_DVB_CONFIG_H */ diff --git a/gr-dtv/include/gnuradio/dtv/dvbt2_config.h b/gr-dtv/include/gnuradio/dtv/dvbt2_config.h index 928690c3a0..906d953255 100644 --- a/gr-dtv/include/gnuradio/dtv/dvbt2_config.h +++ b/gr-dtv/include/gnuradio/dtv/dvbt2_config.h @@ -64,16 +64,6 @@ namespace gr { FFTSIZE_16K_T2GI = 11, }; - enum dvbt2_guardinterval_t { - GI_1_32 = 0, - GI_1_16, - GI_1_8, - GI_1_4, - GI_1_128, - GI_19_128, - GI_19_256, - }; - enum dvbt2_papr_t { PAPR_OFF = 0, PAPR_ACE, @@ -153,7 +143,6 @@ typedef gr::dtv::dvbt2_inputmode_t dvbt2_inputmode_t; typedef gr::dtv::dvbt2_extended_carrier_t dvbt2_extended_carrier_t; typedef gr::dtv::dvbt2_preamble_t dvbt2_preamble_t; typedef gr::dtv::dvbt2_fftsize_t dvbt2_fftsize_t; -typedef gr::dtv::dvbt2_guardinterval_t dvbt2_guardinterval_t; typedef gr::dtv::dvbt2_papr_t dvbt2_papr_t; typedef gr::dtv::dvbt2_l1constellation_t dvbt2_l1constellation_t; typedef gr::dtv::dvbt2_pilotpattern_t dvbt2_pilotpattern_t; diff --git a/gr-dtv/include/gnuradio/dtv/dvbt2_framemapper_cc.h b/gr-dtv/include/gnuradio/dtv/dvbt2_framemapper_cc.h index abead6adbb..bf6e4db297 100644 --- a/gr-dtv/include/gnuradio/dtv/dvbt2_framemapper_cc.h +++ b/gr-dtv/include/gnuradio/dtv/dvbt2_framemapper_cc.h @@ -65,7 +65,7 @@ namespace gr { * \param l1scrambled scramble L1 post signalling (on or off). * \param inband In-band type B signalling (on or off). */ - static sptr make(dvb_framesize_t framesize, dvb_code_rate_t rate, dvb_constellation_t constellation, dvbt2_rotation_t rotation, int fecblocks, int tiblocks, dvbt2_extended_carrier_t carriermode, dvbt2_fftsize_t fftsize, dvbt2_guardinterval_t guardinterval, dvbt2_l1constellation_t l1constellation, dvbt2_pilotpattern_t pilotpattern, int t2frames, int numdatasyms, dvbt2_papr_t paprmode, dvbt2_version_t version, dvbt2_preamble_t preamble, dvbt2_inputmode_t inputmode, dvbt2_reservedbiasbits_t reservedbiasbits, dvbt2_l1scrambled_t l1scrambled, dvbt2_inband_t inband); + static sptr make(dvb_framesize_t framesize, dvb_code_rate_t rate, dvb_constellation_t constellation, dvbt2_rotation_t rotation, int fecblocks, int tiblocks, dvbt2_extended_carrier_t carriermode, dvbt2_fftsize_t fftsize, dvb_guardinterval_t guardinterval, dvbt2_l1constellation_t l1constellation, dvbt2_pilotpattern_t pilotpattern, int t2frames, int numdatasyms, dvbt2_papr_t paprmode, dvbt2_version_t version, dvbt2_preamble_t preamble, dvbt2_inputmode_t inputmode, dvbt2_reservedbiasbits_t reservedbiasbits, dvbt2_l1scrambled_t l1scrambled, dvbt2_inband_t inband); }; } // namespace dtv diff --git a/gr-dtv/include/gnuradio/dtv/dvbt2_freqinterleaver_cc.h b/gr-dtv/include/gnuradio/dtv/dvbt2_freqinterleaver_cc.h index cfb352b109..766fe031a3 100644 --- a/gr-dtv/include/gnuradio/dtv/dvbt2_freqinterleaver_cc.h +++ b/gr-dtv/include/gnuradio/dtv/dvbt2_freqinterleaver_cc.h @@ -22,6 +22,7 @@ #define INCLUDED_DTV_DVBT2_FREQINTERLEAVER_CC_H #include <gnuradio/dtv/api.h> +#include <gnuradio/dtv/dvb_config.h> #include <gnuradio/dtv/dvbt2_config.h> #include <gnuradio/sync_block.h> @@ -52,7 +53,7 @@ namespace gr { * \param version DVB-T2 specification version. * \param preamble P1 symbol preamble format. */ - static sptr make(dvbt2_extended_carrier_t carriermode, dvbt2_fftsize_t fftsize, dvbt2_pilotpattern_t pilotpattern, dvbt2_guardinterval_t guardinterval, int numdatasyms, dvbt2_papr_t paprmode, dvbt2_version_t version, dvbt2_preamble_t preamble); + static sptr make(dvbt2_extended_carrier_t carriermode, dvbt2_fftsize_t fftsize, dvbt2_pilotpattern_t pilotpattern, dvb_guardinterval_t guardinterval, int numdatasyms, dvbt2_papr_t paprmode, dvbt2_version_t version, dvbt2_preamble_t preamble); }; } // namespace dtv diff --git a/gr-dtv/include/gnuradio/dtv/dvbt2_miso_cc.h b/gr-dtv/include/gnuradio/dtv/dvbt2_miso_cc.h index 1268ae8dae..c16e711e9b 100644 --- a/gr-dtv/include/gnuradio/dtv/dvbt2_miso_cc.h +++ b/gr-dtv/include/gnuradio/dtv/dvbt2_miso_cc.h @@ -22,6 +22,7 @@ #define INCLUDED_DTV_DVBT2_MISO_CC_H #include <gnuradio/dtv/api.h> +#include <gnuradio/dtv/dvb_config.h> #include <gnuradio/dtv/dvbt2_config.h> #include <gnuradio/sync_block.h> @@ -51,7 +52,7 @@ namespace gr { * \param numdatasyms number of OFDM symbols in a T2 frame. * \param paprmode PAPR reduction mode. */ - static sptr make(dvbt2_extended_carrier_t carriermode, dvbt2_fftsize_t fftsize, dvbt2_pilotpattern_t pilotpattern, dvbt2_guardinterval_t guardinterval, int numdatasyms, dvbt2_papr_t paprmode); + static sptr make(dvbt2_extended_carrier_t carriermode, dvbt2_fftsize_t fftsize, dvbt2_pilotpattern_t pilotpattern, dvb_guardinterval_t guardinterval, int numdatasyms, dvbt2_papr_t paprmode); }; } // namespace dtv diff --git a/gr-dtv/include/gnuradio/dtv/dvbt2_p1insertion_cc.h b/gr-dtv/include/gnuradio/dtv/dvbt2_p1insertion_cc.h index dd15026cb3..84e0d4a268 100644 --- a/gr-dtv/include/gnuradio/dtv/dvbt2_p1insertion_cc.h +++ b/gr-dtv/include/gnuradio/dtv/dvbt2_p1insertion_cc.h @@ -22,6 +22,7 @@ #define INCLUDED_DTV_DVBT2_P1INSERTION_CC_H #include <gnuradio/dtv/api.h> +#include <gnuradio/dtv/dvb_config.h> #include <gnuradio/dtv/dvbt2_config.h> #include <gnuradio/block.h> @@ -51,7 +52,7 @@ namespace gr { * \param showlevels print peak IQ levels. * \param vclip set peak IQ level threshold. */ - static sptr make(dvbt2_extended_carrier_t carriermode, dvbt2_fftsize_t fftsize, dvbt2_guardinterval_t guardinterval, int numdatasyms, dvbt2_preamble_t preamble, dvbt2_showlevels_t showlevels, float vclip); + static sptr make(dvbt2_extended_carrier_t carriermode, dvbt2_fftsize_t fftsize, dvb_guardinterval_t guardinterval, int numdatasyms, dvbt2_preamble_t preamble, dvbt2_showlevels_t showlevels, float vclip); }; } // namespace dtv diff --git a/gr-dtv/include/gnuradio/dtv/dvbt2_paprtr_cc.h b/gr-dtv/include/gnuradio/dtv/dvbt2_paprtr_cc.h index 728a6650a2..5a39dfa565 100644 --- a/gr-dtv/include/gnuradio/dtv/dvbt2_paprtr_cc.h +++ b/gr-dtv/include/gnuradio/dtv/dvbt2_paprtr_cc.h @@ -22,6 +22,7 @@ #define INCLUDED_DTV_DVBT2_PAPRTR_CC_H #include <gnuradio/dtv/api.h> +#include <gnuradio/dtv/dvb_config.h> #include <gnuradio/dtv/dvbt2_config.h> #include <gnuradio/sync_block.h> @@ -54,7 +55,7 @@ namespace gr { * \param iterations PAPR algorithm number of iterations. * \param vlength input and output vector length. */ - static sptr make(dvbt2_extended_carrier_t carriermode, dvbt2_fftsize_t fftsize, dvbt2_pilotpattern_t pilotpattern, dvbt2_guardinterval_t guardinterval, int numdatasyms, dvbt2_papr_t paprmode, dvbt2_version_t version, float vclip, int iterations, int vlength); + static sptr make(dvbt2_extended_carrier_t carriermode, dvbt2_fftsize_t fftsize, dvbt2_pilotpattern_t pilotpattern, dvb_guardinterval_t guardinterval, int numdatasyms, dvbt2_papr_t paprmode, dvbt2_version_t version, float vclip, int iterations, int vlength); }; } // namespace dtv diff --git a/gr-dtv/include/gnuradio/dtv/dvbt2_pilotgenerator_cc.h b/gr-dtv/include/gnuradio/dtv/dvbt2_pilotgenerator_cc.h index f74005a84a..19ae6d948f 100644 --- a/gr-dtv/include/gnuradio/dtv/dvbt2_pilotgenerator_cc.h +++ b/gr-dtv/include/gnuradio/dtv/dvbt2_pilotgenerator_cc.h @@ -22,6 +22,7 @@ #define INCLUDED_DTV_DVBT2_PILOTGENERATOR_CC_H #include <gnuradio/dtv/api.h> +#include <gnuradio/dtv/dvb_config.h> #include <gnuradio/dtv/dvbt2_config.h> #include <gnuradio/block.h> @@ -56,7 +57,7 @@ namespace gr { * \param bandwidth sin(x)/x equalization bandwidth. * \param vlength output vector length. */ - static sptr make(dvbt2_extended_carrier_t carriermode, dvbt2_fftsize_t fftsize, dvbt2_pilotpattern_t pilotpattern, dvbt2_guardinterval_t guardinterval, int numdatasyms, dvbt2_papr_t paprmode, dvbt2_version_t version, dvbt2_preamble_t preamble, dvbt2_misogroup_t misogroup, dvbt2_equalization_t equalization, dvbt2_bandwidth_t bandwidth, int vlength); + static sptr make(dvbt2_extended_carrier_t carriermode, dvbt2_fftsize_t fftsize, dvbt2_pilotpattern_t pilotpattern, dvb_guardinterval_t guardinterval, int numdatasyms, dvbt2_papr_t paprmode, dvbt2_version_t version, dvbt2_preamble_t preamble, dvbt2_misogroup_t misogroup, dvbt2_equalization_t equalization, dvbt2_bandwidth_t bandwidth, int vlength); }; } // namespace dtv diff --git a/gr-dtv/include/gnuradio/dtv/dvbt_bit_inner_interleaver.h b/gr-dtv/include/gnuradio/dtv/dvbt_bit_inner_interleaver.h new file mode 100644 index 0000000000..d74763e5eb --- /dev/null +++ b/gr-dtv/include/gnuradio/dtv/dvbt_bit_inner_interleaver.h @@ -0,0 +1,67 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 Free Software Foundation, Inc. + * + * 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_DTV_DVBT_BIT_INNER_INTERLEAVER_H +#define INCLUDED_DTV_DVBT_BIT_INNER_INTERLEAVER_H + +#include <gnuradio/dtv/api.h> +#include <gnuradio/block.h> +#include <gnuradio/dtv/dvb_config.h> +#include <gnuradio/dtv/dvbt_config.h> + +namespace gr { + namespace dtv { + + /*! + * \brief Bit Inner interleaver. + * \ingroup dtv + * + * ETSI EN 300 744 Clause 4.3.4.1 \n + * Data Input format: \n + * 000000X0X1 - QPSK. \n + * 0000X0X1X2X3 - 16QAM. \n + * 00X0X1X2X3X4X5 - 64QAM. \n + * Data Output format: \n + * 000000B0B1 - QPSK. \n + * 0000B0B1B2B3 - 16QAM. \n + * 00B0B1B2B3B4B5 - 64QAM. \n + * bit interleaver block size is 126. + */ + class DTV_API dvbt_bit_inner_interleaver : virtual public block + { + public: + typedef boost::shared_ptr<dvbt_bit_inner_interleaver> sptr; + + /*! + * \brief Create a Bit Inner interleaver + * + * \param nsize length of input stream. \n + * \param constellation constellation used. \n + * \param hierarchy hierarchy used. \n + * \param transmission transmission mode used. + */ + static sptr make(int nsize, dvb_constellation_t constellation, dvbt_hierarchy_t hierarchy, dvbt_transmission_mode_t transmission); + }; + + } // namespace dtv +} // namespace gr + +#endif /* INCLUDED_DTV_DVBT_BIT_INNER_INTERLEAVER_H */ + diff --git a/gr-dtv/include/gnuradio/dtv/dvbt_config.h b/gr-dtv/include/gnuradio/dtv/dvbt_config.h new file mode 100644 index 0000000000..c6bfa1a7e5 --- /dev/null +++ b/gr-dtv/include/gnuradio/dtv/dvbt_config.h @@ -0,0 +1,45 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 Free Software Foundation, Inc. + * + * 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_DTV_DVBT_CONFIG_H +#define INCLUDED_DTV_DVBT_CONFIG_H + +namespace gr { + namespace dtv { + enum dvbt_hierarchy_t { + NH = 0, + ALPHA1, + ALPHA2, + ALPHA4, + }; + + enum dvbt_transmission_mode_t { + T2k = 0, + T8k = 1, + }; + + } // namespace dtv +} // namespace gr + +typedef gr::dtv::dvbt_hierarchy_t dvbt_hierarchy_t; +typedef gr::dtv::dvbt_transmission_mode_t dvbt_transmission_mode_t; + +#endif /* INCLUDED_DTV_DVBT_CONFIG_H */ + diff --git a/gr-dtv/include/gnuradio/dtv/dvbt_convolutional_interleaver.h b/gr-dtv/include/gnuradio/dtv/dvbt_convolutional_interleaver.h new file mode 100644 index 0000000000..a4c9577b54 --- /dev/null +++ b/gr-dtv/include/gnuradio/dtv/dvbt_convolutional_interleaver.h @@ -0,0 +1,58 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 Free Software Foundation, Inc. + * + * 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_DTV_DVBT_CONVOLUTIONAL_INTERLEAVER_H +#define INCLUDED_DTV_DVBT_CONVOLUTIONAL_INTERLEAVER_H + +#include <gnuradio/dtv/api.h> +#include <gnuradio/sync_interpolator.h> + +namespace gr { + namespace dtv { + + /*! + * \brief Convolutional interleaver. + * \ingroup dtv + * + * ETSI EN 300 744 Clause 4.3.1 \n + * Forney (Ramsey type III) convolutional interleaver. \n + * Input: Blocks of I bytes size. \n + * Output: Stream of 1 byte elements. + */ + class DTV_API dvbt_convolutional_interleaver : virtual public sync_interpolator + { + public: + typedef boost::shared_ptr<dvbt_convolutional_interleaver> sptr; + + /*! + * \brief Create a DVB-T convolutional interleaver. + * + * \param nsize number of blocks to process. \n + * \param I size of a block. \n + * \param M depth length for each element in shift registers. + */ + static sptr make(int nsize, int I, int M); + }; + + } // namespace dtv +} // namespace gr + +#endif /* INCLUDED_DTV_DVBT_CONVOLUTIONAL_INTERLEAVER_H */ + diff --git a/gr-dtv/include/gnuradio/dtv/dvbt_energy_dispersal.h b/gr-dtv/include/gnuradio/dtv/dvbt_energy_dispersal.h new file mode 100644 index 0000000000..b5258bbe1d --- /dev/null +++ b/gr-dtv/include/gnuradio/dtv/dvbt_energy_dispersal.h @@ -0,0 +1,58 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 Free Software Foundation, Inc. + * + * 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_DTV_DVBT_ENERGY_DISPERSAL_H +#define INCLUDED_DTV_DVBT_ENERGY_DISPERSAL_H + +#include <gnuradio/dtv/api.h> +#include <gnuradio/block.h> + +namespace gr { + namespace dtv { + + /*! + * \brief Energy dispersal. + * \ingroup dtv + * + * ETSI EN 300 744 - Clause 4.3.1 \n + * Input - MPEG-2 transport packets (including sync - 0x47). \n + * Output - Randomized MPEG-2 transport packets. \n + * If first byte is not a SYNC then look for it. \n + * First sync in a row of 8 packets is reversed - 0xB8. \n + * Block size is 188 bytes. + */ + class DTV_API dvbt_energy_dispersal : virtual public gr::block + { + public: + typedef boost::shared_ptr<dvbt_energy_dispersal> sptr; + + /*! + * \brief Create DVB-T energy dispersal. + * + * \param nsize number of blocks. + */ + static sptr make(int nsize); + }; + + } // namespace dtv +} // namespace gr + +#endif /* INCLUDED_DTV_DVBT_ENERGY_DISPERSAL_H */ + diff --git a/gr-dtv/include/gnuradio/dtv/dvbt_inner_coder.h b/gr-dtv/include/gnuradio/dtv/dvbt_inner_coder.h new file mode 100644 index 0000000000..e88596e09b --- /dev/null +++ b/gr-dtv/include/gnuradio/dtv/dvbt_inner_coder.h @@ -0,0 +1,69 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 Free Software Foundation, Inc. + * + * 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_DTV_DVBT_INNER_CODER_H +#define INCLUDED_DTV_DVBT_INNER_CODER_H + +#include <gnuradio/dtv/api.h> +#include <gnuradio/block.h> +#include <gnuradio/dtv/dvb_config.h> +#include <gnuradio/dtv/dvbt_config.h> + +namespace gr { + namespace dtv { + + /*! + * \brief Inner coder with Puncturing. + * \ingroup dtv + * + * ETSI EN 300 744 Clause 4.3.3 \n + * Mother convolutional code with rate 1/2. \n + * k=1, n=2, K=6. \n + * Generator polynomial G1=171(OCT), G2=133(OCT). \n + * Punctured to obtain rates of 2/3, 3/4, 5/6, 7/8. \n + * Data Input format: Packed bytes (each bit is data). \n + * MSB - first, LSB last. \n + * Data Output format: \n + * 000000X0X1 - QPSK. \n + * 0000X0X1X2X3 - 16QAM. \n + * 00X0X1X2X3X4X5 - 64QAM. + */ + class DTV_API dvbt_inner_coder : virtual public block + { + public: + typedef boost::shared_ptr<dvbt_inner_coder> sptr; + + /*! + * \brief Create an Inner coder with Puncturing. + * + * \param ninput length of input. \n + * \param noutput lenght of output. \n + * \param constellation type of constellation. \n + * \param hierarchy type of hierarchy used. \n + * \param coderate coderate used. + */ + static sptr make(int ninput, int noutput, dvb_constellation_t constellation, dvbt_hierarchy_t hierarchy, dvb_code_rate_t coderate); + }; + + } // namespace dtv +} // namespace gr + +#endif /* INCLUDED_DTV_DVBT_INNER_CODER_H */ + diff --git a/gr-dtv/include/gnuradio/dtv/dvbt_map.h b/gr-dtv/include/gnuradio/dtv/dvbt_map.h new file mode 100644 index 0000000000..d9b7976b31 --- /dev/null +++ b/gr-dtv/include/gnuradio/dtv/dvbt_map.h @@ -0,0 +1,65 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 Free Software Foundation, Inc. + * + * 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_DVBT_DVBT_MAP_H +#define INCLUDED_DVBT_DVBT_MAP_H + +#include <gnuradio/dtv/api.h> +#include <gnuradio/dtv/dvb_config.h> +#include <gnuradio/dtv/dvbt_config.h> +#include <gnuradio/block.h> + +namespace gr { + namespace dtv { + + /*! + * \brief DVB-T mapper. + * \ingroup dtv + * + * ETSI EN 300 744 Clause 4.3.5. \n + * Data input format: \n + * 000000Y0Y1 - QPSK. \n + * 0000Y0Y1Y2Y3 - 16QAM. \n + * 00Y0Y1Y2Y3Y4Y5 - 64QAM. \n + * Data output format: \n + * complex(real(float), imag(float)). + */ + class DTV_API dvbt_map : virtual public block + { + public: + typedef boost::shared_ptr<dvbt_map> sptr; + + /*! + * \brief Create a DVB-T mapper. + * + * \param nsize length of input stream. \n + * \param constellation constellation used. \n + * \param hierarchy hierarchy used. \n + * \param transmission transmission mode used. \n + * \param gain gain of complex output stream. + */ + static sptr make(int nsize, dvb_constellation_t constellation, dvbt_hierarchy_t hierarchy, dvbt_transmission_mode_t transmission, float gain); + }; + + } // namespace dtv +} // namespace gr + +#endif /* INCLUDED_DTV_DVBT_MAP_H */ + diff --git a/gr-dtv/include/gnuradio/dtv/dvbt_reed_solomon_enc.h b/gr-dtv/include/gnuradio/dtv/dvbt_reed_solomon_enc.h new file mode 100644 index 0000000000..08c7c571fd --- /dev/null +++ b/gr-dtv/include/gnuradio/dtv/dvbt_reed_solomon_enc.h @@ -0,0 +1,61 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 Free Software Foundation, Inc. + * + * 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_DTV_DVBT_REED_SOLOMON_ENC_H +#define INCLUDED_DTV_DVBT_REED_SOLOMON_ENC_H + +#include <gnuradio/dtv/api.h> +#include <gnuradio/block.h> + +namespace gr { + namespace dtv { + + /*! + * \brief Reed Solomon encoder + * \ingroup dtv + * + * ETSI EN 300 744 Clause 4.3.2 \n + * RS(N=204,K=239,T=8). + */ + class DTV_API dvbt_reed_solomon_enc : virtual public block + { + public: + typedef boost::shared_ptr<dvbt_reed_solomon_enc> sptr; + + /*! + * \brief Create a Reed Solomon encoder. + * + * \param p characteristic of GF(p^m). + * \param m we use GF(p^m). + * \param gfpoly Generator Polynomial. + * \param n length of codeword of RS coder. + * \param k length of information sequence of RS encoder. + * \param t number of corrected errors. + * \param s shortened length. + * \param blocks number of blocks to process at once. + */ + static sptr make(int p, int m, int gfpoly, int n, int k, int t, int s, int blocks); + }; + + } // namespace dtv +} // namespace gr + +#endif /* INCLUDED_DTV_DVBT_REED_SOLOMON_ENC_H */ + diff --git a/gr-dtv/include/gnuradio/dtv/dvbt_reference_signals.h b/gr-dtv/include/gnuradio/dtv/dvbt_reference_signals.h new file mode 100644 index 0000000000..d41b949528 --- /dev/null +++ b/gr-dtv/include/gnuradio/dtv/dvbt_reference_signals.h @@ -0,0 +1,71 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 Free Software Foundation, Inc. + * + * 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_DTV_DVBT_REFERENCE_SIGNALS_H +#define INCLUDED_DTV_DVBT_REFERENCE_SIGNALS_H + +#include <gnuradio/dtv/api.h> +#include <gnuradio/dtv/dvb_config.h> +#include <gnuradio/dtv/dvbt_config.h> +#include <gnuradio/block.h> + +namespace gr { + namespace dtv { + + /*! + * \brief Reference signals generator. + * \ingroup dtv + * + * ETSI EN 300 744 Clause 4.5 \n + * Data input format: \n + * complex(real(float), imag(float)). \n + * Data output format: \n + * complex(real(float), imag(float)). + */ + class DTV_API dvbt_reference_signals : virtual public block + { + public: + typedef boost::shared_ptr<dvbt_reference_signals> sptr; + + /*! + * \brief Create Reference signals generator. + * + * \param itemsize size of an in/out item. \n + * \param ninput input stream length. \n + * \param noutput output stream length. \n + * \param constellation constellation used. \n + * \param hierarchy hierarchy used. \n + * \param code_rate_HP high priority stream code rate. \n + * \param code_rate_LP low priority stream code rate. \n + * \param guard_interval guard interval used. \n + * \param transmission_mode transmission mode used. \n + * \param include_cell_id include or not Cell ID. \n + * \param cell_id value of the Cell ID. + */ + static sptr make(int itemsize, int ninput, int noutput, dvb_constellation_t constellation, \ + dvbt_hierarchy_t hierarchy, dvb_code_rate_t code_rate_HP, dvb_code_rate_t code_rate_LP, \ + dvb_guardinterval_t guard_interval, dvbt_transmission_mode_t transmission_mode, int include_cell_id, int cell_id); + }; + + } // namespace dtv +} // namespace gr + +#endif /* INCLUDED_DTV_DVBT_REFERENCE_SIGNALS_H */ + diff --git a/gr-dtv/include/gnuradio/dtv/dvbt_symbol_inner_interleaver.h b/gr-dtv/include/gnuradio/dtv/dvbt_symbol_inner_interleaver.h new file mode 100644 index 0000000000..ae02c9192f --- /dev/null +++ b/gr-dtv/include/gnuradio/dtv/dvbt_symbol_inner_interleaver.h @@ -0,0 +1,66 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 Free Software Foundation, Inc. + * + * 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_DTV_DVBT_SYMBOL_INNER_INTERLEAVER_H +#define INCLUDED_DTV_DVBT_SYMBOL_INNER_INTERLEAVER_H + +#include <gnuradio/dtv/api.h> +#include <gnuradio/block.h> +#include <gnuradio/dtv/dvbt_config.h> + +namespace gr { + namespace dtv { + + /*! + * \brief Symbol interleaver. + * \ingroup dtv + * + * ETSI EN 300 744 Clause 4.3.4.2 \n + * One block is 12 groups x 126 datawords = 1512 datawords. + * + * Data Input format: \n + * 000000I0I1 - QPSK. \n + * 0000I0I1I2I3 - 16QAM. \n + * 00I0I1I2I3I4I5 - 64QAM. \n + * Data Output format: \n + * 000000Y0Y1 - QPSK. \n + * 0000Y0Y1Y2Y3 - 16QAM. \n + * 00Y0Y1Y2Y3Y4Y5 - 64QAM. + */ + class DTV_API dvbt_symbol_inner_interleaver : virtual public block + { + public: + typedef boost::shared_ptr<dvbt_symbol_inner_interleaver> sptr; + + /*! + * \brief Create a Symbol interleaver. + * + * \param ninput length of input stream. \n + * \param transmission transmission mode used \n + * \param direction interleave or deinterleave. \n + */ + static sptr make(int ninput, dvbt_transmission_mode_t transmission, int direction); + }; + + } // namespace dtv +} // namespace gr + +#endif /* INCLUDED_DTV_DVBT_SYMBOL_INNER_INTERLEAVER_H */ + diff --git a/gr-dtv/lib/CMakeLists.txt b/gr-dtv/lib/CMakeLists.txt index 65f50e471d..f2128e9a83 100644 --- a/gr-dtv/lib/CMakeLists.txt +++ b/gr-dtv/lib/CMakeLists.txt @@ -94,6 +94,16 @@ list(APPEND dtv_sources dvbs2/dvbs2_interleaver_bb_impl.cc dvbs2/dvbs2_modulator_bc_impl.cc dvbs2/dvbs2_physical_cc_impl.cc + dvbt/dvbt_energy_dispersal_impl.cc + dvbt/dvbt_reed_solomon.cc + dvbt/dvbt_reed_solomon_enc_impl.cc + dvbt/dvbt_convolutional_interleaver_impl.cc + dvbt/dvbt_configure.cc + dvbt/dvbt_inner_coder_impl.cc + dvbt/dvbt_bit_inner_interleaver_impl.cc + dvbt/dvbt_symbol_inner_interleaver_impl.cc + dvbt/dvbt_map_impl.cc + dvbt/dvbt_reference_signals_impl.cc ) if(ENABLE_GR_CTRLPORT) diff --git a/gr-dtv/lib/dvb/dvb_bbheader_bb_impl.cc b/gr-dtv/lib/dvb/dvb_bbheader_bb_impl.cc index e0c80ea304..551191c0e5 100644 --- a/gr-dtv/lib/dvb/dvb_bbheader_bb_impl.cc +++ b/gr-dtv/lib/dvb/dvb_bbheader_bb_impl.cc @@ -406,29 +406,24 @@ namespace gr { m_frame[0] = 0; m_frame[1] = 1; m_frame_offset_bits = 2; - temp = 0; for (int n = 30; n >= 0; n--) { - m_frame[m_frame_offset_bits++] = temp & (1 << n) ? 1 : 0; + m_frame[m_frame_offset_bits++] = 0; } - temp = 0; for (int n = 21; n >= 0; n--) { - m_frame[m_frame_offset_bits++] = temp & (1 << n) ? 1 : 0; + m_frame[m_frame_offset_bits++] = 0; } - temp = 0; for (int n = 1; n >= 0; n--) { - m_frame[m_frame_offset_bits++] = temp & (1 << n) ? 1 : 0; + m_frame[m_frame_offset_bits++] = 0; } - temp = 0; for (int n = 9; n >= 0; n--) { - m_frame[m_frame_offset_bits++] = temp & (1 << n) ? 1 : 0; + m_frame[m_frame_offset_bits++] = 0; } temp = ts_rate; for (int n = 26; n >= 0; n--) { m_frame[m_frame_offset_bits++] = temp & (1 << n) ? 1 : 0; } - temp = 0; for (int n = 9; n >= 0; n--) { - m_frame[m_frame_offset_bits++] = temp & (1 << n) ? 1 : 0; + m_frame[m_frame_offset_bits++] = 0; } } diff --git a/gr-dtv/lib/dvb/dvb_ldpc_bb_impl.h b/gr-dtv/lib/dvb/dvb_ldpc_bb_impl.h index 3510ddf083..92c9eb370e 100644 --- a/gr-dtv/lib/dvb/dvb_ldpc_bb_impl.h +++ b/gr-dtv/lib/dvb/dvb_ldpc_bb_impl.h @@ -42,7 +42,6 @@ namespace gr { unsigned int nbch; unsigned int code_rate; unsigned int q_val; - unsigned int table_length; unsigned int dvb_standard; void ldpc_lookup_generate(void); ldpc_encode_table ldpc_encode; diff --git a/gr-dtv/lib/dvbt/dvbt_bit_inner_interleaver_impl.cc b/gr-dtv/lib/dvbt/dvbt_bit_inner_interleaver_impl.cc new file mode 100644 index 0000000000..0ab3003d50 --- /dev/null +++ b/gr-dtv/lib/dvbt/dvbt_bit_inner_interleaver_impl.cc @@ -0,0 +1,191 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 Free Software Foundation, Inc. + * + * 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 <gnuradio/io_signature.h> +#include "dvbt_bit_inner_interleaver_impl.h" +#include <stdio.h> + +namespace gr { + namespace dtv { + + const int dvbt_bit_inner_interleaver_impl::d_bsize = 126; + + int + dvbt_bit_inner_interleaver_impl::H(int e, int w) + { + int rez = 0; + + switch (e) { + case 0: + rez = w; + break; + case 1: + rez = (w + 63) % d_bsize; + break; + case 2: + rez = (w + 105) % d_bsize; + break; + case 3: + rez = (w + 42) % d_bsize; + break; + case 4: + rez = (w + 21) % d_bsize; + break; + case 5: + rez = (w + 84) % d_bsize; + break; + default: + break; + } + + return rez; + } + + dvbt_bit_inner_interleaver::sptr + dvbt_bit_inner_interleaver::make(int nsize, \ + dvb_constellation_t constellation, dvbt_hierarchy_t hierarchy, dvbt_transmission_mode_t transmission) + { + return gnuradio::get_initial_sptr + (new dvbt_bit_inner_interleaver_impl(nsize, constellation, hierarchy, transmission)); + } + + /* + * The private constructor + */ + dvbt_bit_inner_interleaver_impl::dvbt_bit_inner_interleaver_impl(int nsize, dvb_constellation_t constellation, \ + dvbt_hierarchy_t hierarchy, dvbt_transmission_mode_t transmission) + : block("dvbt_bit_inner_interleaver", + io_signature::make(1, 2, sizeof(unsigned char) * nsize), + io_signature::make(1, 1, sizeof (unsigned char) * nsize)), + config(constellation, hierarchy, gr::dtv::C1_2, gr::dtv::C1_2, gr::dtv::GI_1_32, transmission), + d_nsize(nsize), + d_hierarchy(hierarchy) + { + d_v = config.d_m; + d_hierarchy = config.d_hierarchy; + + d_perm = (unsigned char *)new unsigned char[d_v * d_bsize]; + if (d_perm == NULL) { + std::cout << "Cannot allocate memory for d_perm" << std::endl; + exit(1); + } + + //Init permutation table (used for b[e][do]) + for (int i = 0; i < d_bsize * d_v; i++) { + if (d_hierarchy == NH) { + d_perm[i] = ((i % d_v) / (d_v / 2)) + 2 * (i % (d_v / 2)); + } + else { + d_perm[i] = (i % (d_v - 2)) / ((d_v - 2) / 2) + 2 * (i % ((d_v - 2) / 2)) + 2; + } + } + + if (d_nsize % d_bsize) { + std::cout << "Error: Input size must be multiple of block size: " \ + << "nsize: " << d_nsize << "bsize: " << d_bsize << std::endl; + } + } + + /* + * Our virtual destructor. + */ + dvbt_bit_inner_interleaver_impl::~dvbt_bit_inner_interleaver_impl() + { + delete [] d_perm; + } + + 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; + } + + int + dvbt_bit_inner_interleaver_impl::general_work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const unsigned char *inh = (const unsigned char *) input_items[0]; + const unsigned char *inl = (const unsigned char *) input_items[1]; + unsigned char *out = (unsigned char *) output_items[0]; + + int bmax = noutput_items * d_nsize / d_bsize; + + // First index of d_b is Bit interleaver number + // Second index of d_b is the position inside the Bit interleaver + unsigned char d_b[d_v][d_bsize]; + + for (int bcount = 0; bcount < bmax; bcount++) { + for (int i = 0; i < d_bsize; i++) { + if (d_hierarchy == NH) { + int c = inh[bcount * d_bsize + i]; + + // Create the demultiplexer + for (int k = 0; k < d_v; k++) { + d_b[d_perm[(d_v * i) + k]][i] = (c >> (d_v - k - 1)) & 1; + } + } + else { + int ch = inh[(bcount * d_bsize) + i]; + int cl = inl[(bcount * d_bsize) + i]; + + // High priority input - first 2 streams + for (int k = 0; k < 2; k++) { + d_b[(d_v * i + k) % 2][(d_v * i + k) / 2] = (ch >> (1 - k)) & 1; + } + + // Low priority input - (v - 2) streams + for (int k = 2; k < (d_v - 2); k++) { + d_b[d_perm[d_v * i + k]][(d_v * i + k) / (d_v - 2)] = (cl >> (d_v - k - 1)) & 1; + } + } + } + + // Take one bit from each interleaver + // and format the output + + for (int w = 0; w < d_bsize; w++) { + int val = 0; + + for (int e = 0; e < d_v; e++) { + val = (val << 1) | d_b[e][H(e, w)]; + } + + out[(bcount * d_bsize) + w] = val; + } + } + + // Tell runtime system how many input items we consumed on + // each input stream. + consume_each (noutput_items); + + // Tell runtime system how many output items we produced. + return noutput_items; + } + + } /* namespace dtv */ +} /* namespace gr */ + diff --git a/gr-dtv/lib/dvbt/dvbt_bit_inner_interleaver_impl.h b/gr-dtv/lib/dvbt/dvbt_bit_inner_interleaver_impl.h new file mode 100644 index 0000000000..c5fcbe2d82 --- /dev/null +++ b/gr-dtv/lib/dvbt/dvbt_bit_inner_interleaver_impl.h @@ -0,0 +1,65 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 Free Software Foundation, Inc. + * + * 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_DTV_DVBT_BIT_INNER_INTERLEAVER_IMPL_H +#define INCLUDED_DTV_DVBT_BIT_INNER_INTERLEAVER_IMPL_H + +#include <gnuradio/dtv/dvbt_bit_inner_interleaver.h> +#include "dvbt_configure.h" + +namespace gr { + namespace dtv { + + class dvbt_bit_inner_interleaver_impl : public dvbt_bit_inner_interleaver + { + private: + const dvbt_configure config; + + int d_nsize; + dvbt_hierarchy_t d_hierarchy; + + // constellation + int d_v; + // Bit interleaver block size + static const int d_bsize; + + // Table to keep interleaved indices + unsigned char * d_perm; + + // Permutation function + int H(int e, int w); + + public: + dvbt_bit_inner_interleaver_impl(int nsize, dvb_constellation_t constellation, dvbt_hierarchy_t hierarchy, dvbt_transmission_mode_t transmission); + ~dvbt_bit_inner_interleaver_impl(); + + void forecast (int noutput_items, gr_vector_int &ninput_items_required); + + int general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } // namespace dtv +} // namespace gr + +#endif /* INCLUDED_DTV_DVBT_BIT_INNER_INTERLEAVER_IMPL_H */ + diff --git a/gr-dtv/lib/dvbt/dvbt_configure.cc b/gr-dtv/lib/dvbt/dvbt_configure.cc new file mode 100644 index 0000000000..a6d1af7874 --- /dev/null +++ b/gr-dtv/lib/dvbt/dvbt_configure.cc @@ -0,0 +1,277 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 Free Software Foundation, Inc. + * + * 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 <gnuradio/io_signature.h> +#include "dvbt_configure.h" +#include <iostream> +#include <stdio.h> + +namespace gr { + namespace dtv { + + void + dvbt_configure::set_frame_number(int fn) + { + d_frame_index = fn; + } + int + dvbt_configure::get_frame_mumber() + { + return (d_frame_index); + } + void + dvbt_configure::set_constellation(dvb_constellation_t constellation) + { + d_constellation = constellation; + } + dvb_constellation_t + dvbt_configure::get_constellation() + { + return (d_constellation); + } + void + dvbt_configure::set_hierarchical(dvbt_hierarchy_t hierarchy) + { + d_hierarchy = hierarchy; + } + dvbt_hierarchy_t + dvbt_configure::get_hierarchical() + { + return d_hierarchy; + } + void + dvbt_configure::set_code_rate_HP(dvb_code_rate_t code_rate) + { + d_code_rate_HP = code_rate; + } + void + dvbt_configure::set_code_rate_LP(dvb_code_rate_t code_rate) + { + d_code_rate_LP = code_rate; + } + dvb_code_rate_t + dvbt_configure::get_code_rate_HP() + { + return d_code_rate_HP; + } + dvb_code_rate_t + dvbt_configure::get_code_rate_LP() + { + return d_code_rate_LP; + } + void + dvbt_configure::set_transmission_mode(dvbt_transmission_mode_t transmission_mode) + { + d_transmission_mode = transmission_mode; + } + dvbt_transmission_mode_t + dvbt_configure::get_transmission_mode() + { + return d_transmission_mode; + } + + dvbt_configure::dvbt_configure(dvb_constellation_t constellation, \ + dvbt_hierarchy_t hierarchy, dvb_code_rate_t code_rate_HP, \ + dvb_code_rate_t code_rate_LP, dvb_guardinterval_t guard_interval, \ + dvbt_transmission_mode_t transmission_mode, int include_cell_id, int cell_id) : + d_constellation(constellation), d_hierarchy(hierarchy), d_code_rate_HP(code_rate_HP), + d_code_rate_LP(code_rate_LP), d_guard_interval(guard_interval), d_transmission_mode(transmission_mode), + d_include_cell_id(include_cell_id), d_cell_id(cell_id) + { + d_symbols_per_frame = 68; + d_frames_per_superframe = 4; + d_symbol_index = 0; + d_frame_index = 0; + d_superframe_index = 0; + + switch (d_transmission_mode) { + case T2k: + d_Kmin = 0; d_Kmax = 1704; + d_fft_length = 2048; + d_payload_length = 1512; + break; + case T8k: + d_Kmin = 0; d_Kmax = 6816; + d_fft_length = 8192; + d_payload_length = 6048; + break; + default: + d_Kmin = 0; d_Kmax = 1704; + d_fft_length = 2048; + d_payload_length = 1512; + break; + } + d_zeros_on_left = int(ceil((d_fft_length - (d_Kmax - d_Kmin + 1)) / 2.0)); + d_zeros_on_right = d_fft_length - d_zeros_on_left - (d_Kmax - d_Kmin + 1); + + switch (d_constellation) { + case MOD_QPSK: + d_constellation_size = 4; + d_step = 2; + d_m = 2; + break; + case MOD_16QAM: + d_constellation_size = 16; + d_step = 2; + d_m = 4; + break; + case MOD_64QAM: + d_constellation_size = 64; + d_step = 2; + d_m = 6; + break; + default: + d_constellation_size = 16; + d_step = 2; + d_m = 4; + break; + } + + switch (d_code_rate_HP) { + case C1_2: + d_cr_k = 1; d_cr_n = 2; d_cr_p = 1; + break; + case C2_3: + d_cr_k = 2; d_cr_n = 3; d_cr_p = 2; + break; + case C3_4: + d_cr_k = 3; d_cr_n = 4; d_cr_p = 3; + break; + case C5_6: + d_cr_k = 5; d_cr_k = 6; d_cr_p = 5; + break; + case C7_8: + d_cr_k = 7; d_cr_n = 8; d_cr_p = 7; + break; + default: + d_cr_k = 1; d_cr_n = 2; d_cr_p = 1; + break; + } + + switch (d_code_rate_LP) { + case C1_2: + d_cr_k = 1; d_cr_n = 2; + break; + case C2_3: + d_cr_k = 2; d_cr_n = 3; + break; + case C3_4: + d_cr_k = 3; d_cr_n = 4; + break; + case C5_6: + d_cr_k = 5; d_cr_n = 6; + break; + case C7_8: + d_cr_k = 7; d_cr_n = 8; + break; + default: + d_cr_k = 1; d_cr_n = 2; + break; + } + + switch (guard_interval) { + case GI_1_32: + d_cp_length = d_fft_length / 32; + break; + case GI_1_16: + d_cp_length = d_fft_length / 16; + break; + case GI_1_8: + d_cp_length = d_fft_length / 8; + break; + case GI_1_4: + d_cp_length = d_fft_length / 4; + break; + default: + d_cp_length = d_fft_length / 32; + break; + } + + switch (d_hierarchy) { + case NH: + d_alpha = 1; + break; + case ALPHA1: + d_alpha = 1; + break; + case ALPHA2: + d_alpha = 2; + break; + case ALPHA4: + d_alpha = 4; + break; + default: + d_alpha = 1; + break; + } + + // ETSI EN 400 744 Clause 4.4 + // Normalization factor + switch (d_m) { + case 2: + d_norm = 1.0 / sqrt(2); + break; + case 4: + if (d_alpha == 1) { + d_norm = 1.0 / sqrt(10); + } + if (d_alpha == 2) { + d_norm = 1.0 / sqrt(20); + } + if (d_alpha == 4) { + d_norm = 1.0 / sqrt(52); + } + break; + case 6: + if (d_alpha == 1) { + d_norm = 1.0 / sqrt(42); + } + if (d_alpha == 2) { + d_norm = 1.0 / sqrt(60); + } + if (d_alpha == 4) { + d_norm = 1.0 / sqrt(108); + } + break; + default: + if (d_alpha == 1) { + d_norm = 1.0 / sqrt(10); + } + if (d_alpha == 2) { + d_norm = 1.0 / sqrt(20); + } + if (d_alpha == 4) { + d_norm = 1.0 / sqrt(52); + } + break; + } + } + + dvbt_configure::~dvbt_configure() + { + } + + } /* namespace dtv */ +} /* namespace gr */ + diff --git a/gr-dtv/lib/dvbt/dvbt_configure.h b/gr-dtv/lib/dvbt/dvbt_configure.h new file mode 100644 index 0000000000..5e87410c90 --- /dev/null +++ b/gr-dtv/lib/dvbt/dvbt_configure.h @@ -0,0 +1,103 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 Free Software Foundation, Inc. + * + * 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_DTV_DVBT_CONFIGURE_H +#define INCLUDED_DTV_DVBT_CONFIGURE_H + +#include <gnuradio/dtv/dvb_config.h> +#include <gnuradio/dtv/dvbt_config.h> + +namespace gr { + namespace dtv { + + class dvbt_configure + { + public: + int d_symbols_per_frame; + int d_frames_per_superframe; + + int d_symbol_index; + int d_frame_index; + int d_superframe_index; + + //Constelaltion parameters + dvb_constellation_t d_constellation; + int d_constellation_size; + int d_step; + int d_m; + float d_norm; + + //Hierarchy information + dvbt_hierarchy_t d_hierarchy; + int d_alpha; + + //Inner Coding parameters + dvb_code_rate_t d_code_rate_HP; + dvb_code_rate_t d_code_rate_LP; + + // Guard interval length + dvb_guardinterval_t d_guard_interval; + + //Transmission type parameters + dvbt_transmission_mode_t d_transmission_mode; + + //Include cell id + cell id parameters + int d_include_cell_id; + int d_cell_id; + + // Puncturer parameters + int d_cr_k; + int d_cr_n; + int d_cr_p; + + //Other DVB-T parameters + int d_Kmin; + int d_Kmax; + int d_fft_length; + int d_payload_length; + int d_zeros_on_left; + int d_zeros_on_right; + int d_cp_length; + + void set_frame_number(int fn); + int get_frame_mumber(); + void set_constellation(dvb_constellation_t constellation); + dvb_constellation_t get_constellation(); + void set_hierarchical(dvbt_hierarchy_t hierarchy); + dvbt_hierarchy_t get_hierarchical(); + void set_code_rate_HP(dvb_code_rate_t coderate); + dvb_code_rate_t get_code_rate_HP(); + void set_code_rate_LP(dvb_code_rate_t coderate); + dvb_code_rate_t get_code_rate_LP(); + void set_transmission_mode(dvbt_transmission_mode_t transmission_mode); + dvbt_transmission_mode_t get_transmission_mode(); + + dvbt_configure(dvb_constellation_t constellation = gr::dtv::MOD_16QAM, \ + dvbt_hierarchy_t hierarchy = gr::dtv::NH, dvb_code_rate_t code_rate_HP = gr::dtv::C1_2, \ + dvb_code_rate_t code_rate_LP = gr::dtv::C1_2, dvb_guardinterval_t guard_interval = gr::dtv::GI_1_32, \ + dvbt_transmission_mode_t transmission_mode = gr::dtv::T2k, int include_cell_id = 0, int cell_id = 0); + ~dvbt_configure(); + }; + + } // namespace dtv +} // namespace gr + +#endif /* INCLUDED_DTV_DVBT_CONFIGURE_H */ + diff --git a/gr-dtv/lib/dvbt/dvbt_convolutional_interleaver_impl.cc b/gr-dtv/lib/dvbt/dvbt_convolutional_interleaver_impl.cc new file mode 100644 index 0000000000..e29ec8cfe2 --- /dev/null +++ b/gr-dtv/lib/dvbt/dvbt_convolutional_interleaver_impl.cc @@ -0,0 +1,89 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 Free Software Foundation, Inc. + * + * 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 <gnuradio/io_signature.h> +#include "dvbt_convolutional_interleaver_impl.h" +#include <deque> + +namespace gr { + namespace dtv { + + dvbt_convolutional_interleaver::sptr + dvbt_convolutional_interleaver::make(int nsize, int I, int M) + { + return gnuradio::get_initial_sptr + (new dvbt_convolutional_interleaver_impl(nsize, I, M)); + } + + /* + * The private constructor + */ + dvbt_convolutional_interleaver_impl::dvbt_convolutional_interleaver_impl(int blocks, int I, int M) + : sync_interpolator("dvbt_convolutional_interleaver", + io_signature::make(1, 1, sizeof (unsigned char) * I * blocks), + io_signature::make(1, 1, sizeof (unsigned char)), I * blocks), + d_blocks(blocks), d_I(I), d_M(M) + { + //Positions are shift registers (FIFOs) + //of length i*M + for (int i = 0; i < d_I; i++) { + d_shift.push_back(new std::deque<unsigned char>(d_M * i, 0)); + } + } + + /* + * Our virtual destructor. + */ + dvbt_convolutional_interleaver_impl::~dvbt_convolutional_interleaver_impl() + { + for (unsigned int i = 0; i < d_shift.size(); i++) { + delete d_shift.back(); + d_shift.pop_back(); + } + } + + int + dvbt_convolutional_interleaver_impl::work (int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const unsigned char *in = (const unsigned char *) input_items[0]; + unsigned char *out = (unsigned char *) output_items[0]; + + for (int i = 0; i < (noutput_items / d_I); i++) { + //Process one block of I symbols + for (unsigned int j = 0; j < d_shift.size(); j++) { + d_shift[j]->push_front(in[(d_I * i) + j]); + out[(d_I * i) + j] = d_shift[j]->back(); + d_shift[j]->pop_back(); + } + } + + // Tell runtime system how many output items we produced. + return noutput_items; + } + + } /* namespace dtv */ +} /* namespace gr */ + diff --git a/gr-dtv/lib/dvbt/dvbt_convolutional_interleaver_impl.h b/gr-dtv/lib/dvbt/dvbt_convolutional_interleaver_impl.h new file mode 100644 index 0000000000..2de1fab282 --- /dev/null +++ b/gr-dtv/lib/dvbt/dvbt_convolutional_interleaver_impl.h @@ -0,0 +1,52 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 Free Software Foundation, Inc. + * + * 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_DTV_DVBT_CONVOLUTIONAL_INTERLEAVER_IMPL_H +#define INCLUDED_DTV_DVBT_CONVOLUTIONAL_INTERLEAVER_IMPL_H + +#include <gnuradio/dtv/dvbt_convolutional_interleaver.h> +#include <vector> +#include <deque> + +namespace gr { + namespace dtv { + + class dvbt_convolutional_interleaver_impl : public dvbt_convolutional_interleaver + { + private: + int d_blocks; + int d_I; + int d_M; + std::vector< std::deque<unsigned char> * > d_shift; + + public: + dvbt_convolutional_interleaver_impl(int nsize, int I, int M); + ~dvbt_convolutional_interleaver_impl(); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } // namespace dtv +} // namespace gr + +#endif /* INCLUDED_DTV_DVBT_CONVOLUTIONAL_INTERLEAVER_IMPL_H */ + diff --git a/gr-dtv/lib/dvbt/dvbt_energy_dispersal_impl.cc b/gr-dtv/lib/dvbt/dvbt_energy_dispersal_impl.cc new file mode 100644 index 0000000000..03dd0ffec5 --- /dev/null +++ b/gr-dtv/lib/dvbt/dvbt_energy_dispersal_impl.cc @@ -0,0 +1,151 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 Free Software Foundation, Inc. + * + * 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 <gnuradio/io_signature.h> +#include "dvbt_energy_dispersal_impl.h" +#include <stdio.h> + +namespace gr { + namespace dtv { + + const int dvbt_energy_dispersal_impl::d_npacks = 8; + const int dvbt_energy_dispersal_impl::d_psize = 188; + const int dvbt_energy_dispersal_impl::d_SYNC = 0x47; + const int dvbt_energy_dispersal_impl::d_NSYNC = 0xB8; + + void + dvbt_energy_dispersal_impl::init_prbs() + { + d_reg = 0xa9; + } + + int + dvbt_energy_dispersal_impl::clock_prbs(int clocks) + { + int res = 0; + int feedback = 0; + + for (int i = 0; i < clocks; i++) { + feedback = ((d_reg >> (14 - 1)) ^ (d_reg >> (15 - 1))) & 0x1; + d_reg = ((d_reg << 1) | feedback) & 0x7fff; + res = (res << 1) | feedback; + } + return res; + } + + dvbt_energy_dispersal::sptr + dvbt_energy_dispersal::make(int nblocks) + { + return gnuradio::get_initial_sptr + (new dvbt_energy_dispersal_impl(nblocks)); + } + + /* + * The private constructor + */ + dvbt_energy_dispersal_impl::dvbt_energy_dispersal_impl(int nblocks) + : gr::block("dvbt_energy_dispersal", + gr::io_signature::make(1, 1, sizeof(unsigned char)), + gr::io_signature::make(1, 1, sizeof(unsigned char) * nblocks * d_npacks * d_psize)), + d_nblocks(nblocks), + d_reg(0xa9) + { + set_relative_rate(1.0/(double) (d_nblocks * d_npacks * d_psize)); + } + + /* + * Our virtual destructor. + */ + dvbt_energy_dispersal_impl::~dvbt_energy_dispersal_impl() + { + } + + void + dvbt_energy_dispersal_impl::forecast (int noutput_items, gr_vector_int &ninput_items_required) + { + // Add one block size for SYNC search + ninput_items_required[0] = d_npacks * (d_psize + 1) * d_nblocks * noutput_items; + } + + int + dvbt_energy_dispersal_impl::general_work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const unsigned char *in = (const unsigned char *) input_items[0]; + unsigned char *out = (unsigned char *) output_items[0]; + + int index = 0; + int count = 0; + int ret = 0; + int is_sync = 0; + + // Search for SYNC byte + while (is_sync == 0 && index < d_psize) { + if (in[index] == d_SYNC) { + is_sync = 1; + } + else { + index++; + } + } + + // If we found a SYNC byte + if (is_sync) { + for (int i = 0; i < (d_nblocks * noutput_items); i++) { + init_prbs(); + + int sync = d_NSYNC; + + for (int j = 0; j < d_npacks; j++) { + if (in[index + count] != d_SYNC) { + printf("error: Malformed MPEG-TS!\n"); + } + + out[count++] = sync; + + for (int k = 1; k < d_psize; k++) { + out[count] = in[index + count] ^ clock_prbs(d_npacks); + count++; + } + + sync = d_SYNC; + clock_prbs(d_npacks); + } + } + consume_each(index + d_npacks * d_psize * d_nblocks * noutput_items); + ret = noutput_items; + } + else { + consume_each(index); + ret = 0; + } + + // Tell runtime system how many output items we produced. + return ret; + } + } /* namespace dtv */ +} /* namespace gr */ + diff --git a/gr-dtv/lib/dvbt/dvbt_energy_dispersal_impl.h b/gr-dtv/lib/dvbt/dvbt_energy_dispersal_impl.h new file mode 100644 index 0000000000..e1cfe4e925 --- /dev/null +++ b/gr-dtv/lib/dvbt/dvbt_energy_dispersal_impl.h @@ -0,0 +1,65 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 Free Software Foundation, Inc. + * + * 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_DTV_DVBT_ENERGY_DISPERSAL_IMPL_H +#define INCLUDED_DTV_DVBT_ENERGY_DISPERSAL_IMPL_H + +#include <gnuradio/dtv/dvbt_energy_dispersal.h> + +namespace gr { + namespace dtv { + + class dvbt_energy_dispersal_impl : public dvbt_energy_dispersal + { + private: + // Packet size + static const int d_psize; + // Number of packets after which PRBS is reset + static const int d_npacks; + // Number of blocks + int d_nblocks; + // SYNC value + static const int d_SYNC; + // Negative SYNC value + static const int d_NSYNC; + + // Register for PRBS + int d_reg; + + void init_prbs(); + int clock_prbs(int clocks); + + public: + dvbt_energy_dispersal_impl(int nsize); + ~dvbt_energy_dispersal_impl(); + + void forecast (int noutput_items, gr_vector_int &ninput_items_required); + + int general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } // namespace dtv +} // namespace gr + +#endif /* INCLUDED_DTV_DVBT_ENERGY_DISPERSAL_IMPL_H */ + diff --git a/gr-dtv/lib/dvbt/dvbt_inner_coder_impl.cc b/gr-dtv/lib/dvbt/dvbt_inner_coder_impl.cc new file mode 100644 index 0000000000..4f24f0258f --- /dev/null +++ b/gr-dtv/lib/dvbt/dvbt_inner_coder_impl.cc @@ -0,0 +1,257 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 Free Software Foundation, Inc. + * + * 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 <gnuradio/io_signature.h> +#include "dvbt_inner_coder_impl.h" +#include <stdio.h> +#include <assert.h> + +namespace gr { + namespace dtv { + + void + dvbt_inner_coder_impl::generate_codeword(unsigned char in, int &x, int &y) + { + //insert input bit + d_reg |= ((in & 0x1) << 7); + + d_reg = d_reg >> 1; + + // TODO - do this with polynoms and bitcnt + //generate output G1=171(OCT) + x = ((d_reg >> 6) ^ (d_reg >> 5) ^ (d_reg >> 4) ^ \ + (d_reg >> 3) ^ d_reg) & 0x1; + //generate output G2=133(OCT) + y = ((d_reg >> 6) ^ (d_reg >> 4) ^ (d_reg >> 3) ^ \ + (d_reg >> 1) ^ d_reg) & 0x1; + } + + //TODO - do this based on puncturing matrix + /* + * Input e.g rate 2/3: + * 000000x0x1 + * Output e.g. rate 2/3 + * 00000c0c1c2 + */ + + void + dvbt_inner_coder_impl::generate_punctured_code(dvb_code_rate_t coderate, unsigned char * in, unsigned char * out) + { + int x, y; + + switch(coderate) { + //X1Y1 + case C1_2: + generate_codeword(in[0], x, y); + out[0] = x; out[1] = y; + break; + //X1Y1Y2 + case C2_3: + generate_codeword(in[0], x, y); + out[0] = x; out[1] = y; + generate_codeword(in[1], x, y); + out[2] = y; + break; + //X1Y1Y2X3 + case C3_4: + generate_codeword(in[0], x, y); + out[0] = x; out[1] = y; + generate_codeword(in[1], x, y); + out[2] = y; + generate_codeword(in[2], x, y); + out[3] = x; + break; + //X1Y1Y2X3Y4X5 + case C5_6: + generate_codeword(in[0], x, y); + out[0] = x; out[1] = y; + generate_codeword(in[1], x, y); + out[2] = y; + generate_codeword(in[2], x, y); + out[3] = x; + generate_codeword(in[3], x, y); + out[4] = y; + generate_codeword(in[4], x, y); + out[5] = x; + break; + //X1Y1Y2X3Y4X5Y6X7 + case C7_8: + generate_codeword(in[0], x, y); + out[0] = x; out[1] = y; + generate_codeword(in[1], x, y); + out[2] = y; + generate_codeword(in[2], x, y); + out[3] = y; + generate_codeword(in[3], x, y); + out[4] = y; + generate_codeword(in[4], x, y); + out[5] = x; + generate_codeword(in[5], x, y); + out[6] = y; + generate_codeword(in[6], x, y); + out[7] = x; + break; + default: + generate_codeword(in[0], x, y); + out[0] = x; out[1] = y; + break; + } + } + + dvbt_inner_coder::sptr + dvbt_inner_coder::make(int ninput, int noutput, dvb_constellation_t constellation, \ + dvbt_hierarchy_t hierarchy, dvb_code_rate_t coderate) + { + return gnuradio::get_initial_sptr + (new dvbt_inner_coder_impl(ninput, noutput, constellation, hierarchy, coderate)); + } + + /* + * The private constructor + */ + dvbt_inner_coder_impl::dvbt_inner_coder_impl(int ninput, int noutput, dvb_constellation_t constellation, \ + dvbt_hierarchy_t hierarchy, dvb_code_rate_t coderate) + : block("dvbt_inner_coder", + io_signature::make(1, 1, sizeof (unsigned char)), + io_signature::make(1, 1, sizeof (unsigned char) * noutput)), + config(constellation, hierarchy, coderate, coderate), + d_ninput(ninput), d_noutput(noutput), + d_reg(0), + d_bitcount(0) + { + //Determine k - input of encoder + d_k = config.d_cr_k; + //Determine n - output of encoder + d_n = config.d_cr_n; + //Determine m - constellation symbol size + d_m = config.d_m; + + // In order to accomodate all constalations (m=2,4,6) + // and rates (1/2, 2/3, 3/4, 5/6, 7/8) + // We need the following things to happen: + // - output item size multiple of 1512bytes + // - noutput_items multiple of 4 + // - in block size 4*(k*m/8) + // - out block size 4*n + // + // Rate calculation follows: + // We process km input bits(km/8 Bytes) + // We output nm bits + // We output one byte for a symbol of m bits + // The out/in rate in bytes is: 8n/km (Bytes) + + assert(d_ninput % 1); + assert(d_noutput % 1512); + + // Set output items multiple of 4 + set_output_multiple(4); + + // Set relative rate out/in + assert((d_noutput * d_k * d_m) % (d_ninput * 8 * d_n)); + set_relative_rate((float)(d_ninput * 8 * d_n) / (float)d_noutput * d_k * d_m); + + // calculate in and out block sizes + d_in_bs = (d_k * d_m) / 2; + d_out_bs = 4 * d_n; + + // allocate bit buffers + d_in_buff = new unsigned char[8 * d_in_bs]; + if (d_in_buff == NULL) { + std::cout << "Cannot allocate memory for d_in_buff" << std::endl; + exit(1); + } + + d_out_buff = new unsigned char[8 * d_in_bs * d_n / d_k]; + if (d_out_buff == NULL) { + std::cout << "Cannot allocate memory for d_out_buff" << std::endl; + delete [] d_in_buff; + exit(1); + } + } + + /* + * Our virtual destructor. + */ + dvbt_inner_coder_impl::~dvbt_inner_coder_impl() + { + delete [] d_out_buff; + delete [] d_in_buff; + } + + void + dvbt_inner_coder_impl::forecast (int noutput_items, gr_vector_int &ninput_items_required) + { + int input_required = noutput_items * d_noutput * d_k * d_m / (d_ninput * 8 * d_n); + + unsigned ninputs = ninput_items_required.size(); + for (unsigned int i = 0; i < ninputs; i++) { + ninput_items_required[i] = input_required; + } + } + + int + dvbt_inner_coder_impl::general_work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const unsigned char *in = (const unsigned char *) input_items[0]; + unsigned char *out = (unsigned char *) output_items[0]; + + for (int k = 0; k < (noutput_items * d_noutput / d_out_bs); k++) { + // Unpack input to bits + for (int i = 0; i < d_in_bs; i++) { + for (int j = 0; j < 8; j++) { + d_in_buff[8*i + j] = (in[k*d_in_bs + i] >> (7 - j)) & 1; + } + } + + // Encode the data + for (int in_bit = 0, out_bit = 0; in_bit < (8 * d_in_bs); in_bit += d_k, out_bit += d_n) { + generate_punctured_code(config.d_code_rate_HP, &d_in_buff[in_bit], &d_out_buff[out_bit]); + } + + // Pack d_m bit in one output byte + for (int i = 0; i < d_out_bs; i++) { + unsigned char c = 0; + + for (int j = 0; j < d_m; j++) { + c |= d_out_buff[d_m*i + j] << (d_m - 1 - j); + } + + out[k*d_out_bs + i] = c; + } + } + + // Tell runtime system how many input items we consumed on + // each input stream. + consume_each(noutput_items * d_noutput * d_k * d_m / (d_ninput * 8 * d_n)); + + // Tell runtime system how many output items we produced. + return noutput_items; + } + + } /* namespace dtv */ +} /* namespace gr */ + diff --git a/gr-dtv/lib/dvbt/dvbt_inner_coder_impl.h b/gr-dtv/lib/dvbt/dvbt_inner_coder_impl.h new file mode 100644 index 0000000000..7a46a2222c --- /dev/null +++ b/gr-dtv/lib/dvbt/dvbt_inner_coder_impl.h @@ -0,0 +1,78 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 Free Software Foundation, Inc. + * + * 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_DTV_DVBT_INNER_CODER_IMPL_H +#define INCLUDED_DTV_DVBT_INNER_CODER_IMPL_H + +#include <gnuradio/dtv/dvbt_inner_coder.h> +#include "dvbt_configure.h" + +namespace gr { + namespace dtv { + + class dvbt_inner_coder_impl : public dvbt_inner_coder + { + private: + const dvbt_configure config; + + int d_ninput; + int d_noutput; + + int d_reg; + + //counts the bits in the bytes + //in input stream + int d_bitcount; + + // Code rate k/n + int d_k; + int d_n; + // Constellation with m + int d_m; + + // input block size in bytes + int d_in_bs; + // bit input buffer + unsigned char * d_in_buff; + + // output block size in bytes + int d_out_bs; + // bit output buffer + unsigned char * d_out_buff; + + void generate_codeword(unsigned char in, int &x, int &y); + void generate_punctured_code(dvb_code_rate_t coderate, unsigned char * in, unsigned char * out); + + public: + dvbt_inner_coder_impl(int ninput, int noutput, dvb_constellation_t constellation, dvbt_hierarchy_t hierarchy, dvb_code_rate_t coderate); + ~dvbt_inner_coder_impl(); + void forecast (int noutput_items, gr_vector_int &ninput_items_required); + + int general_work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } // namespace dtv +} // namespace gr + +#endif /* INCLUDED_DTV_DVBT_INNER_CODER_IMPL_H */ + diff --git a/gr-dtv/lib/dvbt/dvbt_map_impl.cc b/gr-dtv/lib/dvbt/dvbt_map_impl.cc new file mode 100644 index 0000000000..05f6e7f69b --- /dev/null +++ b/gr-dtv/lib/dvbt/dvbt_map_impl.cc @@ -0,0 +1,163 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 Free Software Foundation, Inc. + * + * 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 <gnuradio/io_signature.h> +#include <complex> +#include "dvbt_map_impl.h" +#include <stdio.h> +#include <math.h> + +namespace gr { + namespace dtv { + + dvbt_map::sptr + dvbt_map::make(int nsize, dvb_constellation_t constellation, dvbt_hierarchy_t hierarchy, dvbt_transmission_mode_t transmission, float gain) + { + return gnuradio::get_initial_sptr + (new dvbt_map_impl(nsize, constellation, hierarchy, transmission, gain)); + } + + /* + * The private constructor + */ + dvbt_map_impl::dvbt_map_impl(int nsize, dvb_constellation_t constellation, dvbt_hierarchy_t hierarchy, dvbt_transmission_mode_t transmission, float gain) + : block("dvbt_map", + io_signature::make(1, 1, sizeof (unsigned char) * nsize), + io_signature::make(1, 1, sizeof (gr_complex) * nsize)), + config(constellation, hierarchy, gr::dtv::C1_2, gr::dtv::C1_2, gr::dtv::GI_1_32, transmission), + d_nsize(nsize), + d_constellation_size(0), + d_step(0), + d_alpha(0), + d_gain(0.0) + { + //Get parameters from config object + d_constellation_size = config.d_constellation_size; + d_transmission_mode = config.d_transmission_mode; + d_step = config.d_step; + d_alpha = config.d_alpha; + d_gain = gain * config.d_norm; + + d_constellation_points = new gr_complex[d_constellation_size]; + if (d_constellation_points == NULL) { + std::cout << "Cannot allocate memory for d_constellation_points" << std::endl; + exit(1); + } + + make_constellation_points(d_constellation_size, d_step, d_alpha); + } + + /* + * Our virtual destructor. + */ + dvbt_map_impl::~dvbt_map_impl() + { + delete [] d_constellation_points; + } + + unsigned int + dvbt_map_impl::bin_to_gray(unsigned int val) + { + return (val >> 1) ^ val; + } + + void + dvbt_map_impl::make_constellation_points(int size, int step, int alpha) + { + // The symmetry of the constellation is used to calculate + // 16-QAM from QPSK and 64-QAM form 16-QAM + + int bits_per_axis = log2(size) / 2; + int steps_per_axis = sqrt(size) / 2 - 1; + + for (int i = 0; i < size; i++) { + // This is the quadrant made of the first two bits starting from MSB + int q = i >> (2 * (bits_per_axis - 1)) & 3; + // Sign for correctly calculate I and Q in each quadrant + int sign0 = (q >> 1) ? -1 : 1; int sign1 = (q & 1) ? -1 : 1; + + int x = (i >> (bits_per_axis - 1)) & ((1 << (bits_per_axis - 1)) - 1); + int y = i & ((1 << (bits_per_axis - 1)) - 1); + + int xval = alpha + (steps_per_axis - x) * step; + int yval = alpha + (steps_per_axis - y) * step; + + int val = (bin_to_gray(x) << (bits_per_axis - 1)) + bin_to_gray(y); + + // ETSI EN 300 744 Clause 4.3.5 + // Actually the constellation is gray coded + // but the bits on each axis are not taken in consecutive order + // So we need to convert from b0b2b4b1b3b5->b0b1b2b3b4b5(QAM64) + + x = 0; y = 0; + + for (int j = 0; j < (bits_per_axis - 1); j++) { + x += ((val >> (1 + 2 * j)) & 1) << j; + y += ((val >> (2 * j)) & 1) << j; + } + + val = (q << 2 * (bits_per_axis - 1)) + (x << (bits_per_axis - 1)) + y; + + // Keep corresponding symbol bits->complex symbol in one vector + // Normalize the signal using gain + d_constellation_points[val] = d_gain * gr_complex(sign0 * xval, sign1 * yval); + } + } + + gr_complex + dvbt_map_impl::find_constellation_point(int val) + { + return d_constellation_points[val]; + } + + void + dvbt_map_impl::forecast (int noutput_items, gr_vector_int &ninput_items_required) + { + ninput_items_required[0] = noutput_items; + } + + int + dvbt_map_impl::general_work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const unsigned char *in = (const unsigned char *) input_items[0]; + gr_complex *out = (gr_complex *) output_items[0]; + + for (int i = 0; i < (noutput_items * d_nsize); i++) { + out[i] = find_constellation_point(in[i]); + } + + // Tell runtime system how many input items we consumed on + // each input stream. + consume_each (noutput_items); + + // Tell runtime system how many output items we produced. + return noutput_items; + } + + } /* namespace dtv */ +} /* namespace gr */ + diff --git a/gr-dtv/lib/dvbt/dvbt_map_impl.h b/gr-dtv/lib/dvbt/dvbt_map_impl.h new file mode 100644 index 0000000000..045a8e0e6d --- /dev/null +++ b/gr-dtv/lib/dvbt/dvbt_map_impl.h @@ -0,0 +1,72 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 Free Software Foundation, Inc. + * + * 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_DTV_DVBT_MAP_IMPL_H +#define INCLUDED_DTV_DVBT_MAP_IMPL_H + +#include <gnuradio/dtv/dvbt_map.h> +#include "dvbt_configure.h" + +namespace gr { + namespace dtv { + + class dvbt_map_impl : public dvbt_map + { + private: + const dvbt_configure config; + + int d_nsize; + + //Constellation size + unsigned char d_constellation_size; + // Keeps transmission mode + dvbt_transmission_mode_t d_transmission_mode; + //Step on each axis of the constellation + unsigned char d_step; + //Keep Alpha internally + unsigned char d_alpha; + //Gain for the complex values + float d_gain; + + gr_complex * d_constellation_points; + + void make_constellation_points(int size, int step, int alpha); + gr_complex find_constellation_point(int val); + + //Return gray representation from natural binary + unsigned int bin_to_gray(unsigned int val); + + public: + dvbt_map_impl(int nsize, dvb_constellation_t constellation, dvbt_hierarchy_t hierarchy, dvbt_transmission_mode_t transmission, float gain); + ~dvbt_map_impl(); + + void forecast (int noutput_items, gr_vector_int &ninput_items_required); + + int general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } // namespace dtv +} // namespace gr + +#endif /* INCLUDED_DTV_DVBT_MAP_IMPL_H */ + diff --git a/gr-dtv/lib/dvbt/dvbt_reed_solomon.cc b/gr-dtv/lib/dvbt/dvbt_reed_solomon.cc new file mode 100644 index 0000000000..6277350b42 --- /dev/null +++ b/gr-dtv/lib/dvbt/dvbt_reed_solomon.cc @@ -0,0 +1,475 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 Free Software Foundation, Inc. + * + * 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 <gnuradio/io_signature.h> +#include "dvbt_reed_solomon.h" +#include <iostream> +#include <stdio.h> +#include <string.h> +#include <fstream> + +using namespace std; + +#define min(a,b) ((a) < (b)) ? (a) : (b) + +namespace gr { + namespace dtv { + + void + dvbt_reed_solomon::gf_init(int p, int m, int gfpoly) + { + d_p = p; d_m = m; + + //maximum number of elements in the GF(p^m) + int q = powl(p, m); + + d_gf_exp = new unsigned char[q]; + if (d_gf_exp == NULL) { + std::cout << "Cannot allocate memory for d_gf_exp" << std::endl; + return; + } + + d_gf_log = new unsigned char[q]; + if (d_gf_log == NULL) { + std::cout << "Cannot allocate memory for d_gf_log" << std::endl; + delete [] d_gf_exp; + return; + } + + int reg_rs = 1; + + d_gf_exp[q - 1] = 0; + d_gf_log[0] = q - 1; + + for (int i = 0; i < (q - 1); i++) { + d_gf_exp[i] = reg_rs; + d_gf_log[reg_rs] = i; + + //This is equvalent with raise to power + reg_rs = reg_rs << 1; + + if (reg_rs & (1 << m)) { + reg_rs = reg_rs ^ gfpoly; + } + + reg_rs = reg_rs & ((1 << m) - 1); + } + } + + void + dvbt_reed_solomon::gf_uninit() + { + delete [] d_gf_log; + delete [] d_gf_exp; + } + + int + dvbt_reed_solomon::gf_exp(int a) + { + return d_gf_exp[a % d_n]; + } + + int + dvbt_reed_solomon::gf_log(int a) + { + return d_gf_log[a % d_n]; + } + + + int + dvbt_reed_solomon::gf_add(int a, int b) + { + return (a ^ b); + } + + int + dvbt_reed_solomon::gf_mul(int a, int b) + { + if (a == 0 || b == 0) { + return 0; + } + else { + return gf_exp(d_gf_log[a] + d_gf_log[b]); + } + } + + int + dvbt_reed_solomon::gf_div(int a, int b) + { + if (a == 0 || b == 0) { + return (0); + } + + return (gf_exp(d_n + d_gf_log[a] - d_gf_log[b])); + } + + int + dvbt_reed_solomon::gf_pow(int a, int power) + { + if (a == 0) { + return (0); + } + + return gf_exp(d_n + d_gf_log[a] + power); + } + + int + dvbt_reed_solomon::gf_lpow(int power) + { + return d_l[power % d_n]; + } + + void + dvbt_reed_solomon::rs_init(int lambda, int n, int k, int t) + { + d_n = n; d_k = k; d_t = t; + // 2t = n - k, dmin = 2t + 1 = n -k + 1 + + d_l = new unsigned char[d_n + 1]; + if (d_l == NULL) { + std::cout << "Cannot allocate memory for d_l" << std::endl; + exit(1); + } + + d_g = new unsigned char[2 * d_t + 1]; + if (d_g == NULL) { + std::cout << "Cannot allocate memory for d_g" << std::endl; + delete [] d_l; + exit(1); + } + + //Generate roots of lambda + d_l[0] = 1; + + for (int i = 1; i <= d_n; i++) { + d_l[i] = gf_mul(d_l[i - 1], lambda); + } + + //Init Generator polynomial buffer + for (int i = 0; i <= (2*t); i++) { + d_g[i] = 0; + } + + //Start with x+lambda^0 + d_g[0] = 1; + + //Create generator polynomial + for (int i = 1; i <= (2 * t); i++) { + for (int j = i; j > 0; j--) { + if (d_g[j] != 0) { + d_g[j] = gf_add(d_g[j - 1], gf_mul(d_g[j], d_l[i - 1])); + } + else { + d_g[j] = d_g[j - 1]; + } + } + + d_g[0] = gf_mul(d_g[0], d_l[i - 1]); + } + + // Init syndrome array + d_syn = new unsigned char[2 * d_t + 1]; + if (d_syn == NULL) { + std::cout << "Cannot allocate memory for d_syn" << std::endl; + delete [] d_g; + delete [] d_l; + exit(1); + } + } + + void + dvbt_reed_solomon::rs_uninit() + { + if (d_syn) { + delete [] d_syn; + } + if (d_g) { + delete [] d_g; + } + if (d_l) { + delete [] d_l; + } + } + + int + dvbt_reed_solomon::rs_encode(unsigned char *data_in, unsigned char *parity) + { + memset(parity, 0, 2 * d_t); + + for (int i = 0; i < d_k; i++) { + int feedback = gf_add(data_in[i], parity[0]); + + if (feedback != 0) { + for (int j = 1; j < (2 * d_t); j++) { + if (d_g[2 * d_t - j] != 0) { + parity[j] = gf_add(parity[j], gf_mul(feedback, d_g[2 * d_t - j])); + } + } + } + + //Shift the register + memmove(&parity[0], &parity[1], (2 * d_t) - 1); + + if (feedback != 0) { + parity[2 * d_t - 1] = gf_mul(feedback, d_g[0]); + } + else { + parity[2 * d_t - 1] = 0; + } + } + + return (0); + } + + int + dvbt_reed_solomon::rs_decode(unsigned char *data, unsigned char *eras, const int no_eras) + { + unsigned char sigma[2 * d_t + 1]; + unsigned char b[2 * d_t + 1]; + unsigned char T[2 * d_t + 1]; + unsigned char reg[2 * d_t + 1]; + unsigned char root[2 * d_t + 1]; + unsigned char loc[2 * d_t + 1]; + unsigned char omega[2 * d_t]; + + // Compute erasure locator polynomial + memset(sigma, 0, 2 * d_t + 1); + sigma[0] = 1; + + if (no_eras > 0) { + // In this case we know the locations of errors + // Init sigma to be the erasure locator polynomial + sigma[1] = gf_exp(d_n-1-eras[0]); + + for (int i = 1; i < no_eras; i++) { + int u = d_n-1-eras[i]; + + for (int j = i+1; j > 0; j--) { + sigma[j] = gf_add(sigma[j], gf_pow(sigma[j - 1], u)); + } + } + } + + // Calculate syndrome + + for (int j = 0; j < 2 * d_t; j++) { + d_syn[j] = data[0]; + } + + for (int j = 1; j < d_n; j++) { + for (int i = 0; i < 2 * d_t; i++) { + d_syn[i] = gf_add(data[j], gf_pow(d_syn[i], i)); + } + } + + int syn_error = 0; + + // Verify all syndromes + for (int i = 0; i < 2 * d_t; i++) { + syn_error |= d_syn[i]; + } + + if (!syn_error) { + // The syndrome is a codeword + // Return data unmodified + return (0); + } + + // Use Modified (errors+erasures) BMA. Algorithm of Berlekamp-Massey + // S(i)=r(lambda^i)=e(lambda^i) + + int r = no_eras; + int el = no_eras; + + memcpy(b, sigma, 2 * d_t + 1); + + while (++r <= 2 * d_t) { + int d_discr = 0; + + for (int i = 0; i < r; i++) { + d_discr = gf_add(d_discr, gf_mul(sigma[i], d_syn[r - i - 1])); + } + + if (d_discr == 0) { + // b(x) = x * b(x) + memmove(&b[1], b, 2 * d_t); + b[0] = 0; + } + else { + T[0] = sigma[0]; + + // T(x) = sigma(x) + d*x*b(x) + for (int i = 0; i < 2 * d_t; i++) { + T[i + 1] = gf_add(sigma[i + 1], gf_mul(d_discr, b[i])); + } + + if (2 * el <= r + no_eras - 1) { + el = r + no_eras - el; + + // b(i) = sigma(i) / discr + for (int i = 0; i <= 2 * d_t; i++) { + b[i] = gf_div(sigma[i], d_discr); + } + } + else { + // b(x) = x*b(x) + memmove(&b[1], b, 2 * d_t); + b[0] = 0; + } + memcpy(sigma, T, 2 * d_t + 1); + } + } + + // Compute degree(sigma) + int deg_sigma = 0; + + for (int i = 0; i < 2 * d_t + 1; i++) { + if (sigma[i] != 0) { + deg_sigma = i; + } + } + + // Find the roots of sigma(x) by Chien search + // Test sum(1)=1+sigma(1)*(lambda^1)+...+sigma(nu)*lambda(^nu) + // Test sum(2)=1+sigma(1)*(lambda^2)+...+sigma(nu)*lambda(^nu*2) + // ... + // Test sum(l)=1+sigma(1)*(lambda^l)+...+sigma(nu)*lambda(^nu*l) + // in order to see if lambda^(-1) is a root + // where nu is degree(sigma) + + int no_roots = 0; + + memcpy(®[1], &sigma[1], 2 * d_t); + + for (int i = 1; i <= d_n; i++) { + int q = 1; + + for (int j = deg_sigma; j > 0; j--) { + reg[j] = gf_pow(reg[j], j); + q = gf_add(q, reg[j]); + } + + if (q != 0) { + continue; + } + + // We are here when we found roots of the sigma(x) + // Keep roots in index form + root[no_roots] = i; + loc[no_roots] = i - 1; + + if (++no_roots == deg_sigma) { + break; + } + } + + if (no_roots != deg_sigma) { + // Uncorrectable error detected + if (eras) { + for (int i = 0; i < no_roots; i++) + eras[i] = loc[i]; + } + + return (-1); + } + + // Compute erros+erasures evaluator polynomial + // omega(x)=sigma(x)S(x) mod (x ^ 2 * t) + int deg_omega = 0; + + for (int i = 0; i < 2 * d_t; i++) { + int tmp = 0; + int j = (deg_sigma < i) ? deg_sigma : i; + + for(;j >= 0; j--) { + tmp = gf_add(tmp, gf_mul(d_syn[i - j], sigma[j])); + } + + if(tmp != 0) { + deg_omega = i; + } + + omega[i] = tmp; + } + omega[2 * d_t] = 0; + + // Compute error values using Forney formula (poly form) + // e(j(l))) = (lambda(j(l)) ^ 2) * omega(lambda ^ (-j(l))) / sigma_pr(lambda ^ (-j(l))) + // where sigma_pr is the formal derivative of sigma + + for (int j = no_roots - 1; j >= 0; j--) { + int num1 = 0; + + // roots[] are in index form + for (int i = deg_omega; i >= 0; i--) { + num1 = gf_add(num1, gf_pow(omega[i], i * root[j])); + } + + // root[] is in index form + int num2 = gf_exp(root[j] * (-1) + d_n); + + int den = 0; + + // sigma[i+1] for i even is the formal derivative lambda_pr of sigma[i] + int deg_max = min(deg_sigma, 2 * d_t - 1); + + for (int i = 1; i <= deg_max; i += 2) { + if (sigma[i] != 0) + den = gf_add(den, gf_exp(d_gf_log[sigma[i]] + (i - 1) * root[j])); + } + + if (den == 0) { + if (eras) { + for (int i = 0; i < no_roots; i++) { + eras[i] = loc[i]; + } + } + return (-1); + } + + int err = gf_div(gf_mul(num1, num2), den); + + data[loc[j]] = gf_add(data[loc[j]], err); + } + + return(no_roots); + } + + + dvbt_reed_solomon::dvbt_reed_solomon(int p, int m, int gfpoly, int n, int k, int t, int s, int blocks): + d_p(p), d_m(m), d_gfpoly(gfpoly), d_n(n), d_k(k), d_t(t), d_s(s), d_blocks(blocks) + { + gf_init(d_p, d_m, d_gfpoly); + rs_init(d_p, d_n, d_k, d_t); + } + + dvbt_reed_solomon::~dvbt_reed_solomon() + { + rs_uninit(); + gf_uninit(); + } + + } /* namespace dtv */ +} /* namespace gr */ + diff --git a/gr-dtv/lib/dvbt/dvbt_reed_solomon.h b/gr-dtv/lib/dvbt/dvbt_reed_solomon.h new file mode 100644 index 0000000000..b9286d0ffd --- /dev/null +++ b/gr-dtv/lib/dvbt/dvbt_reed_solomon.h @@ -0,0 +1,70 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 Free Software Foundation, Inc. + * + * 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_DTV_DVBT_REED_SOLOMON_H +#define INCLUDED_DTV_DVBT_REED_SOLOMON_H + +namespace gr { + namespace dtv { + + class dvbt_reed_solomon + { + private: + int d_p; + int d_m; + int d_gfpoly; + int d_n; + int d_k; + int d_t; + int d_s; + int d_blocks; + unsigned char *d_gf_exp; + unsigned char *d_gf_log; + unsigned char *d_l; + unsigned char *d_g; + + unsigned char *d_syn; + + int gf_add(int a, int b); + int gf_mul(int a, int b); + int gf_div(int a, int b); + int gf_exp(int a); + int gf_log(int a); + int gf_pow(int a, int power); + int gf_lpow(int power); + + void gf_init(int p, int m, int gfpoly); + void gf_uninit(); + void rs_init(int lambda, int n, int k, int t); + void rs_uninit(); + + public: + int rs_encode(unsigned char *data, unsigned char *parity); + int rs_decode(unsigned char *data, unsigned char *eras, const int no_eras); + + dvbt_reed_solomon(int p, int m, int gfpoly, int n, int k, int t, int s, int blocks); + ~dvbt_reed_solomon(); + }; + + } // namespace dtv +} // namespace gr + +#endif /* INCLUDED_DTV_DVBT_REED_SOLOMON_H */ + diff --git a/gr-dtv/lib/dvbt/dvbt_reed_solomon_enc_impl.cc b/gr-dtv/lib/dvbt/dvbt_reed_solomon_enc_impl.cc new file mode 100644 index 0000000000..561ea08ded --- /dev/null +++ b/gr-dtv/lib/dvbt/dvbt_reed_solomon_enc_impl.cc @@ -0,0 +1,103 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 Free Software Foundation, Inc. + * + * 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 <gnuradio/io_signature.h> +#include "dvbt_reed_solomon_enc_impl.h" +#include <stdio.h> + +namespace gr { + namespace dtv { + + dvbt_reed_solomon_enc::sptr + dvbt_reed_solomon_enc::make(int p, int m, int gfpoly, int n, int k, int t, int s, int blocks) + { + return gnuradio::get_initial_sptr + (new dvbt_reed_solomon_enc_impl(p, m, gfpoly, n, k, t, s, blocks)); + } + + /* + * The private constructor + */ + dvbt_reed_solomon_enc_impl::dvbt_reed_solomon_enc_impl(int p, int m, int gfpoly, int n, int k, int t, int s, int blocks) + : block("dvbt_reed_solomon", + io_signature::make(1, 1, sizeof(unsigned char) * blocks * (k - s)), + io_signature::make(1, 1, sizeof(unsigned char) * blocks * (n - s))), + d_p(p), d_m(m), d_gfpoly(gfpoly), d_n(n), d_k(k), d_t(t), d_s(s), d_blocks(blocks), + d_rs(p, m, gfpoly, n, k, t, s, blocks) + { + d_in = new unsigned char[d_n]; + if (d_in == NULL) { + std::cout << "Cannot allocate memory for d_in" << std::endl; + return; + } + memset(&d_in[0], 0, d_n); + } + + /* + * Our virtual destructor. + */ + dvbt_reed_solomon_enc_impl::~dvbt_reed_solomon_enc_impl() + { + delete [] d_in; + } + + void + dvbt_reed_solomon_enc_impl::forecast (int noutput_items, gr_vector_int &ninput_items_required) + { + ninput_items_required[0] = noutput_items; + } + + int + dvbt_reed_solomon_enc_impl::general_work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const unsigned char *in = (const unsigned char *) input_items[0]; + unsigned char *out = (unsigned char *) output_items[0]; + + int in_bsize = d_k - d_s; + int out_bsize = d_n - d_s; + + // We get a superblock of d_blocks blocks + for (int i = 0; i < (d_blocks * noutput_items); i++) { + //TODO - zero copy between in/out ? + memcpy(&d_in[d_s], &in[i * in_bsize], in_bsize); + + d_rs.rs_encode(&d_in[0], &d_in[d_k]); + + memcpy(&out[i * out_bsize], &d_in[d_s], out_bsize); + } + + // Tell runtime system how many input items we consumed on + // each input stream. + consume_each (noutput_items); + + // Tell runtime system how many output items we produced. + return noutput_items; + } + + } /* namespace dtv */ +} /* namespace gr */ + diff --git a/gr-dtv/lib/dvbt/dvbt_reed_solomon_enc_impl.h b/gr-dtv/lib/dvbt/dvbt_reed_solomon_enc_impl.h new file mode 100644 index 0000000000..669ee2761a --- /dev/null +++ b/gr-dtv/lib/dvbt/dvbt_reed_solomon_enc_impl.h @@ -0,0 +1,62 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 Free Software Foundation, Inc. + * + * 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_DTV_DVBT_REED_SOLOMON_ENC_IMPL_H +#define INCLUDED_DTV_DVBT_REED_SOLOMON_ENC_IMPL_H + +#include <gnuradio/dtv/dvbt_reed_solomon_enc.h> +#include "dvbt_reed_solomon.h" + +namespace gr { + namespace dtv { + + class dvbt_reed_solomon_enc_impl : public dvbt_reed_solomon_enc + { + private: + int d_p; + int d_m; + int d_gfpoly; + int d_n; + int d_k; + int d_t; + int d_s; + int d_blocks; + + unsigned char * d_in; + + dvbt_reed_solomon d_rs; + + public: + dvbt_reed_solomon_enc_impl(int p, int m, int gfpoly, int n, int k, int t, int s, int blocks); + ~dvbt_reed_solomon_enc_impl(); + + void forecast (int noutput_items, gr_vector_int &ninput_items_required); + + int general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } // namespace dtv +} // namespace gr + +#endif /* INCLUDED_DTV_DVBT_REED_SOLOMON_ENC_IMPL_H */ + diff --git a/gr-dtv/lib/dvbt/dvbt_reference_signals_impl.cc b/gr-dtv/lib/dvbt/dvbt_reference_signals_impl.cc new file mode 100644 index 0000000000..58fc76c64e --- /dev/null +++ b/gr-dtv/lib/dvbt/dvbt_reference_signals_impl.cc @@ -0,0 +1,1284 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 Free Software Foundation, Inc. + * + * 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 <gnuradio/io_signature.h> +#include "dvbt_reference_signals_impl.h" +#include <complex> +#include <stdio.h> +#include <gnuradio/expj.h> +#include <gnuradio/math.h> + +namespace gr { + namespace dtv { + + //Number of symbols in a frame + const int dvbt_pilot_gen::d_symbols_per_frame = SYMBOLS_PER_FRAME; + //Number of frames in a superframe + const int dvbt_pilot_gen::d_frames_per_superframe = FRAMES_PER_SUPERFRAME; + + // 2k mode + // Scattered pilots # of carriers + const int dvbt_pilot_gen::d_spilot_carriers_size_2k = SCATTERED_PILOT_SIZE_2k; + // Continual pilots # of carriers and positions + const int dvbt_pilot_gen::d_cpilot_carriers_size_2k = CONTINUAL_PILOT_SIZE_2k; + const int dvbt_pilot_gen::d_cpilot_carriers_2k[dvbt_pilot_gen::d_cpilot_carriers_size_2k] = { + 0, 48, 54, 87, 141, 156, 192, \ + 201, 255, 279, 282, 333, 432, 450, \ + 483, 525, 531, 618, 636, 714, 759, \ + 765, 780, 804, 873, 888, 918, 939, \ + 942, 969, 984, 1050, 1101, 1107, 1110, \ + 1137, 1140, 1146, 1206, 1269, 1323, 1377, \ + 1491, 1683, 1704 + }; + // TPS pilots # of carriers and positions + const int dvbt_pilot_gen::d_tps_carriers_size_2k = TPS_PILOT_SIZE_2k; + const int dvbt_pilot_gen::d_tps_carriers_2k[dvbt_pilot_gen::d_tps_carriers_size_2k] = { + 34, 50, 209, 346, 413, \ + 569, 595, 688, 790, 901, \ + 1073, 1219, 1262, 1286, 1469, \ + 1594, 1687 + }; + + // 8k mode + // Scattered pilots # of carriers + const int dvbt_pilot_gen::d_spilot_carriers_size_8k = SCATTERED_PILOT_SIZE_8k; + // Continual pilots # of carriers and positions + const int dvbt_pilot_gen::d_cpilot_carriers_size_8k = CONTINUAL_PILOT_SIZE_8k; + const int dvbt_pilot_gen::d_cpilot_carriers_8k[dvbt_pilot_gen::d_cpilot_carriers_size_8k] = { + 0, 48, 54, 87, 141, 156, 192, + 201, 255, 279, 282, 333, 432, 450, + 483, 525, 531, 618, 636, 714, 759, + 765, 780, 804, 873, 888, 918, 939, + 942, 969, 984, 1050, 1101, 1107, 1110, + 1137, 1140, 1146, 1206, 1269, 1323, 1377, + 1491, 1683, 1704, 1752, 1758, 1791, 1845, + 1860, 1896, 1905, 1959, 1983, 1986, 2037, + 2136, 2154, 2187, 2229, 2235, 2322, 2340, + 2418, 2463, 2469, 2484, 2508, 2577, 2592, + 2622, 2643, 2646, 2673, 2688, 2754, 2805, + 2811, 2814, 2841, 2844, 2850, 2910, 2973, + 3027, 3081, 3195, 3387, 3408, 3456, 3462, + 3495, 3549, 3564, 3600, 3609, 3663, 3687, + 3690, 3741, 3840, 3858, 3891, 3933, 3939, + 4026, 4044, 4122, 4167, 4173, 4188, 4212, + 4281, 4296, 4326, 4347, 4350, 4377, 4392, + 4458, 4509, 4515, 4518, 4545, 4548, 4554, + 4614, 4677, 4731, 4785, 4899, 5091, 5112, + 5160, 5166, 5199, 5253, 5268, 5304, 5313, + 5367, 5391, 5394, 5445, 5544, 5562, 5595, + 5637, 5643, 5730, 5748, 5826, 5871, 5877, + 5892, 5916, 5985, 6000, 6030, 6051, 6054, + 6081, 6096, 6162, 6213, 6219, 6222, 6249, + 6252, 6258, 6318, 6381, 6435, 6489, 6603, + 6795, 6816 + }; + // TPS pilots # of carriers and positions + const int dvbt_pilot_gen::d_tps_carriers_size_8k = TPS_PILOT_SIZE_8k; + const int dvbt_pilot_gen::d_tps_carriers_8k[dvbt_pilot_gen::d_tps_carriers_size_8k] = { + 34, 50, 209, 346, 413, 569, 595, 688, \ + 790, 901, 1073, 1219, 1262, 1286, 1469, 1594, \ + 1687, 1738, 1754, 1913, 2050, 2117, 2273, 2299, \ + 2392, 2494, 2605, 2777, 2923, 2966, 2990, 3173, \ + 3298, 3391, 3442, 3458, 3617, 3754, 3821, 3977, \ + 4003, 4096, 4198, 4309, 4481, 4627, 4670, 4694, \ + 4877, 5002, 5095, 5146, 5162, 5321, 5458, 5525, \ + 5681, 5707, 5800, 5902, 6013, 6185, 6331, 6374, \ + 6398, 6581, 6706, 6799 + }; + + // TPS sync sequence for odd and even frames + const int dvbt_pilot_gen::d_tps_sync_size = 16; // TODO + const int dvbt_pilot_gen::d_tps_sync_even[d_tps_sync_size] = { + 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0 + }; + const int dvbt_pilot_gen::d_tps_sync_odd[d_tps_sync_size] = { + 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1 + }; + + /* + * Constructor of class + */ + dvbt_pilot_gen::dvbt_pilot_gen(const dvbt_configure &c) : config(c), + d_spilot_index(0), + d_cpilot_index(0), + d_tpilot_index(0), + d_symbol_index(0), + d_symbol_index_known(0), + d_frame_index(0), + d_superframe_index(0), + d_freq_offset_max(8), + d_trigger_index(0), + d_payload_index(0), + d_chanestim_index(0), + d_prev_mod_symbol_index(0), + d_mod_symbol_index(0) + { + //Determine parameters from config file + d_Kmin = config.d_Kmin; + d_Kmax = config.d_Kmax; + d_fft_length = config.d_fft_length; + d_payload_length = config.d_payload_length; + d_zeros_on_left = config.d_zeros_on_left; + d_zeros_on_right = config.d_zeros_on_right; + d_cp_length = config.d_cp_length; + + //Set-up pilot data depending on transmission mode + if (config.d_transmission_mode == T2k) { + d_spilot_carriers_size = d_spilot_carriers_size_2k; + d_cpilot_carriers_size = d_cpilot_carriers_size_2k; + d_cpilot_carriers = d_cpilot_carriers_2k; + d_tps_carriers_size = d_tps_carriers_size_2k; + d_tps_carriers = d_tps_carriers_2k; + } + else if (config.d_transmission_mode == T8k) { + d_spilot_carriers_size = d_spilot_carriers_size_8k; + d_cpilot_carriers_size = d_cpilot_carriers_size_8k; + d_cpilot_carriers = d_cpilot_carriers_8k; + d_tps_carriers_size = d_tps_carriers_size_8k; + d_tps_carriers = d_tps_carriers_8k; + } + else { + d_spilot_carriers_size = d_spilot_carriers_size_2k; + d_cpilot_carriers_size = d_cpilot_carriers_size_2k; + d_cpilot_carriers = d_cpilot_carriers_2k; + d_tps_carriers_size = d_tps_carriers_size_2k; + d_tps_carriers = d_tps_carriers_2k; + } + + d_freq_offset = 0; + d_carrier_freq_correction = 0.0; + d_sampling_freq_correction = 0.0; + + //allocate PRBS buffer + d_wk = new char[d_Kmax - d_Kmin + 1]; + if (d_wk == NULL) { + std::cout << "Cannot allocate memory for d_wk" << std::endl; + exit(1); + } + // Generate wk sequence + generate_prbs(); + + // allocate buffer for scattered pilots + d_spilot_carriers_val = new gr_complex[d_Kmax - d_Kmin + 1]; + if (d_spilot_carriers_val == NULL) { + std::cout << "Cannot allocate memory for d_tps_carriers_val" << std::endl; + delete [] d_wk; + exit(1); + } + + // allocate buffer for channel gains (for each useful carrier) + d_channel_gain = new gr_complex[d_Kmax - d_Kmin + 1]; + if (d_channel_gain == NULL) { + std::cout << "Cannot allocate memory for d_tps_carriers_val" << std::endl; + delete [] d_spilot_carriers_val; + delete [] d_wk; + exit(1); + } + + // Allocate buffer for continual pilots phase diffs + d_known_phase_diff = new float[d_cpilot_carriers_size - 1]; + if (d_known_phase_diff == NULL) { + std::cout << "Cannot allocate memory for d_tps_carriers_val" << std::endl; + delete [] d_channel_gain; + delete [] d_spilot_carriers_val; + delete [] d_wk; + exit(1); + } + + // Obtain phase diff for all continual pilots + for (int i = 0; i < (d_cpilot_carriers_size - 1); i++) { + d_known_phase_diff[i] = \ + norm(get_cpilot_value(d_cpilot_carriers[i + 1]) - get_cpilot_value(d_cpilot_carriers[i])); + } + + d_cpilot_phase_diff = new float[d_cpilot_carriers_size - 1]; + if (d_cpilot_phase_diff == NULL) { + std::cout << "Cannot allocate memory for d_tps_carriers_val" << std::endl; + delete [] d_known_phase_diff; + delete [] d_channel_gain; + delete [] d_spilot_carriers_val; + delete [] d_wk; + exit(1); + } + + // Allocate buffer for derotated input symbol + d_derot_in = new gr_complex[d_fft_length]; + if (d_derot_in == NULL) { + std::cout << "Cannot allocate memory for d_derot_in" << std::endl; + delete [] d_cpilot_phase_diff; + delete [] d_known_phase_diff; + delete [] d_channel_gain; + delete [] d_spilot_carriers_val; + delete [] d_wk; + exit(1); + } + + // allocate buffer for first tps symbol constellation + d_tps_carriers_val = new gr_complex[d_tps_carriers_size]; + if (d_tps_carriers_val == NULL) { + std::cout << "Cannot allocate memory for d_tps_carriers_val" << std::endl; + delete [] d_derot_in; + delete [] d_cpilot_phase_diff; + delete [] d_known_phase_diff; + delete [] d_channel_gain; + delete [] d_spilot_carriers_val; + delete [] d_wk; + exit(1); + } + + // allocate tps data buffer + d_tps_data = new unsigned char[d_symbols_per_frame]; + if (d_tps_data == NULL) { + std::cout << "Cannot allocate memory for d_tps_data" << std::endl; + delete [] d_tps_carriers_val; + delete [] d_derot_in; + delete [] d_cpilot_phase_diff; + delete [] d_known_phase_diff; + delete [] d_channel_gain; + delete [] d_spilot_carriers_val; + delete [] d_wk; + exit(1); + } + + d_prev_tps_symbol = new gr_complex[d_tps_carriers_size]; + if (d_prev_tps_symbol == NULL) { + std::cout << "Cannot allocate memory for d_tps_data" << std::endl; + delete [] d_tps_data; + delete [] d_tps_carriers_val; + delete [] d_derot_in; + delete [] d_cpilot_phase_diff; + delete [] d_known_phase_diff; + delete [] d_channel_gain; + delete [] d_spilot_carriers_val; + delete [] d_wk; + exit(1); + } + memset(d_prev_tps_symbol, 0, d_tps_carriers_size * sizeof(gr_complex)); + + d_tps_symbol = new gr_complex[d_tps_carriers_size]; + if (d_tps_symbol == NULL) { + std::cout << "Cannot allocate memory for d_tps_data" << std::endl; + delete [] d_prev_tps_symbol; + delete [] d_tps_data; + delete [] d_tps_carriers_val; + delete [] d_derot_in; + delete [] d_cpilot_phase_diff; + delete [] d_known_phase_diff; + delete [] d_channel_gain; + delete [] d_spilot_carriers_val; + delete [] d_wk; + exit(1); + } + memset(d_tps_symbol, 0, d_tps_carriers_size * sizeof(gr_complex)); + + // Init receive TPS data vector + for (int i = 0; i < d_symbols_per_frame; i++) { + d_rcv_tps_data.push_back(0); + } + + // Init TPS sync sequence + for (int i = 0; i < d_tps_sync_size; i++) { + d_tps_sync_evenv.push_back(d_tps_sync_even[i]); + d_tps_sync_oddv.push_back(d_tps_sync_odd[i]); + } + + // Allocate buffer for channel estimation carriers + d_chanestim_carriers = new int[d_Kmax - d_Kmin + 1]; + if (d_chanestim_carriers == NULL) { + std::cout << "Cannot allocate memory for d_tps_data" << std::endl; + delete [] d_tps_symbol; + delete [] d_prev_tps_symbol; + delete [] d_tps_data; + delete [] d_tps_carriers_val; + delete [] d_derot_in; + delete [] d_cpilot_phase_diff; + delete [] d_known_phase_diff; + delete [] d_channel_gain; + delete [] d_spilot_carriers_val; + delete [] d_wk; + exit(1); + } + + // Allocate buffer for payload carriers + d_payload_carriers = new int[d_Kmax - d_Kmin + 1]; + if (d_payload_carriers == NULL) { + std::cout << "Cannot allocate memory for d_tps_data" << std::endl; + delete [] d_chanestim_carriers; + delete [] d_tps_symbol; + delete [] d_prev_tps_symbol; + delete [] d_tps_data; + delete [] d_tps_carriers_val; + delete [] d_derot_in; + delete [] d_cpilot_phase_diff; + delete [] d_known_phase_diff; + delete [] d_channel_gain; + delete [] d_spilot_carriers_val; + delete [] d_wk; + exit(1); + } + + // Reset the pilot generator + reset_pilot_generator(); + // Format TPS data with current values + format_tps_data(); + } + + /* + * Destructor of class + */ + dvbt_pilot_gen::~dvbt_pilot_gen() + { + delete [] d_payload_carriers; + delete [] d_chanestim_carriers; + delete [] d_tps_symbol; + delete [] d_prev_tps_symbol; + delete [] d_tps_data; + delete [] d_tps_carriers_val; + delete [] d_derot_in; + delete [] d_cpilot_phase_diff; + delete [] d_known_phase_diff; + delete [] d_channel_gain; + delete [] d_spilot_carriers_val; + delete [] d_wk; + } + + /* + * Generate PRBS sequence + * X^11 + X^2 + 1 + * en 300 744 - section 4.5.2 + */ + void + dvbt_pilot_gen::generate_prbs() + { + // init PRBS register with 1s + unsigned int reg_prbs = (1 << 11) - 1; + + for (int k = 0; k < (d_Kmax - d_Kmin + 1); k++) { + d_wk[k] = (char)(reg_prbs & 0x01); + int new_bit = ((reg_prbs >> 2) ^ (reg_prbs >> 0)) & 0x01; + reg_prbs = (reg_prbs >> 1) | (new_bit << 10); + } + } + + /* + * Generate shortened BCH(67, 53) codes from TPS data + * Extend the code with 60 bits and use BCH(127, 113) + */ + void + dvbt_pilot_gen::generate_bch_code() + { + //TODO + //DO other way: if (feedback == 1) reg = reg ^ polymomial + //else nothing + + //(n, k) = (127, 113) = (60+67, 60+53) + unsigned int reg_bch = 0; + unsigned char data_in[113]; + + //fill in 60 zeros + memset(&data_in[0], 0, 60); + //fill in TPS data - start bit not included + memcpy(&data_in[60], &d_tps_data[1], 53); + + //X^14+X^9+X^8+X^6+X^5+X^4+X^2+X+1 + for (int i = 0; i < 113; i++) { + int feedback = 0x1 & (data_in[i] ^ reg_bch); + reg_bch = reg_bch >> 1; + reg_bch |= feedback << 13; + reg_bch = reg_bch \ + ^ (feedback << 12) ^ (feedback << 11) \ + ^ (feedback << 9) ^ (feedback << 8) \ + ^ (feedback << 7) ^ (feedback << 5) \ + ^ (feedback << 4); + } + + for (int i = 0; i < 14; i++) { + d_tps_data[i + 54] = 0x1 & (reg_bch >> i); + } + } + + int + dvbt_pilot_gen::verify_bch_code(std::deque<char> data) + { + int ret = 0; + + //TODO + //DO other way: if (feedback == 1) reg = reg ^ polymomial + //else nothing + + //(n, k) = (127, 113) = (60+67, 60+53) + unsigned int reg_bch = 0; + unsigned char data_in[113]; + + //fill in 60 zeros + memset(&data_in[0], 0, 60); + //fill in TPS data - start bit not included + //memcpy(&data_in[60], &data[1], 53); + for (int i = 0; i < 53; i++) + data_in[60 + i] = data[1 + i]; + + //X^14+X^9+X^8+X^6+X^5+X^4+X^2+X+1 + for (int i = 0; i < 113; i++) { + int feedback = 0x1 & (data_in[i] ^ reg_bch); + reg_bch = reg_bch >> 1; + reg_bch |= feedback << 13; + reg_bch = reg_bch \ + ^ (feedback << 12) ^ (feedback << 11) \ + ^ (feedback << 9) ^ (feedback << 8) \ + ^ (feedback << 7) ^ (feedback << 5) \ + ^ (feedback << 4); + } + + for (int i = 0; i < 14; i++) { + if ((unsigned int)data[i + 54] != (0x1 & (reg_bch >> i))) { + ret = -1; + break; + } + } + + return ret; + } + + void + dvbt_pilot_gen::set_symbol_index(int sindex) + { + d_symbol_index = sindex; + } + + int + dvbt_pilot_gen::get_symbol_index() + { + return d_symbol_index; + } + + void + dvbt_pilot_gen::set_tps_data() + { + } + + void + dvbt_pilot_gen::get_tps_data() + { + } + + /* + * Reset pilot generator + */ + void + dvbt_pilot_gen::reset_pilot_generator() + { + d_spilot_index = 0; d_cpilot_index = 0; d_tpilot_index = 0; + d_payload_index = 0; d_chanestim_index = 0; + d_symbol_index = 0; d_frame_index = 0; d_superframe_index = 0; + d_symbol_index_known = 0; + d_equalizer_ready = 0; + } + + /* + * Init scattered pilot generator + */ + int + dvbt_pilot_gen::get_current_spilot(int sindex) const + { + //TODO - can be optimized for same symbol_index + return (d_Kmin + 3 * (sindex % 4) + 12 * d_spilot_index); + } + + gr_complex + dvbt_pilot_gen::get_spilot_value(int spilot) + { + // TODO - can be calculated at the beginning + return gr_complex(4 * 2 * (0.5 - d_wk[spilot]) / 3, 0); + } + + void + dvbt_pilot_gen::set_spilot_value(int spilot, gr_complex val) + { + d_spilot_carriers_val[spilot] = val; + } + + void + dvbt_pilot_gen::set_channel_gain(int spilot, gr_complex val) + { + // Gain gval=rxval/txval + d_channel_gain[spilot] = gr_complex((4 * 2 * (0.5 - d_wk[spilot]) / 3), 0) / val; + } + void + dvbt_pilot_gen::advance_spilot(int sindex) + { + //TODO - do in a simpler way? + int size = d_spilot_carriers_size; + + if (sindex == 0) { + size = d_spilot_carriers_size + 1; + } + + // TODO - fix this - what value should we use? + ++d_spilot_index; + d_spilot_index = d_spilot_index % size; + } + + int + dvbt_pilot_gen::get_first_spilot() + { + d_spilot_index = 0; + + return (d_Kmin + 3 * (d_symbol_index % 4)); + } + + int + dvbt_pilot_gen::get_last_spilot() const + { + int size = d_spilot_carriers_size - 1; + + if (d_symbol_index == 0) { + size = d_spilot_carriers_size; + } + + return (d_Kmin + 3 * (d_symbol_index % 4) + 12 * size); + } + + int + dvbt_pilot_gen::get_next_spilot() + { + int pilot = (d_Kmin + 3 * (d_symbol_index % 4) + 12 * (++d_spilot_index)); + + if (pilot > d_Kmax) { + pilot = d_Kmax; + } + + return pilot; + } + + int + dvbt_pilot_gen::process_spilot_data(const gr_complex * in) + { + // This is channel estimator + // Interpolate the gain between carriers to obtain + // gain for non pilot carriers - we use linear interpolation + + /*************************************************************/ + // Find out the OFDM symbol index (value 0 to 3) sent + // in current block by correlating scattered symbols with + // current block - result is (symbol index % 4) + /*************************************************************/ + float max = 0; float sum = 0; + + for (int scount = 0; scount < 4; scount++) { + d_spilot_index = 0; d_cpilot_index = 0; + d_chanestim_index = 0; + + for (int k = 0; k < (d_Kmax - d_Kmin + 1); k++) { + // Keep data for channel estimation + if (k == get_current_spilot(scount)) { + set_chanestim_carrier(k); + advance_spilot(scount); + advance_chanestim(); + } + } + + gr_complex c = gr_complex(0.0, 0.0); + + // This should be of range 0 to d_chanestim_index bit for now we use just a + // small number of spilots to obtain the symbol index + for (int j = 0; j < 10; j++) { + c += get_spilot_value(d_chanestim_carriers[j]) * conj(in[d_zeros_on_left + d_chanestim_carriers[j]]); + } + sum = norm(c); + + if (sum > max) { + max = sum; + d_mod_symbol_index = scount; + } + } + + /*************************************************************/ + // Keep data for channel estimator + // This method interpolates scattered measurements across one OFDM symbol + // It does not use measurements from the previous OFDM symbols (does not use history) + // as it may have encountered a phase change for the current phase only + /*************************************************************/ + + d_spilot_index = 0; d_cpilot_index = 0; + d_chanestim_index = 0; + + for (int k = 0; k < (d_Kmax - d_Kmin + 1); k++) { + // Keep data for channel estimation + if (k == get_current_spilot(d_mod_symbol_index)) { + set_chanestim_carrier(k); + advance_spilot(d_mod_symbol_index); + advance_chanestim(); + } + + // Keep data for channel estimation + if (k == get_current_cpilot()) { + set_chanestim_carrier(k); + advance_cpilot(); + advance_chanestim(); + } + } + + // We use both scattered pilots and continual pilots + for (int i = 0, startk = d_chanestim_carriers[0]; i < d_chanestim_index; i++) { + // Get a carrier from the list of carriers + // used for channel estimation + int k = d_chanestim_carriers[i]; + + set_channel_gain(k, in[k + d_zeros_on_left]); + + // Calculate tg(alpha) due to linear interpolation + gr_complex tg_alpha = (d_channel_gain[k] - d_channel_gain[startk]) / gr_complex(11.0, 0.0); + + // Calculate interpolation for all intermediate values + for (int j = 1; j < (k - startk); j++) { + gr_complex current = d_channel_gain[startk] + tg_alpha * gr_complex(j, 0.0); + d_channel_gain[startk + j] = current; + } + + startk = k; + } + + // Signal that equalizer is ready + d_equalizer_ready = 1; + + int diff_sindex = (d_mod_symbol_index - d_prev_mod_symbol_index + 4) % 4; + + d_prev_mod_symbol_index = d_mod_symbol_index; + + return diff_sindex; + } + + /* + * Init continual pilot generator + */ + int + dvbt_pilot_gen::get_current_cpilot() const + { + return d_cpilot_carriers[d_cpilot_index]; + } + + gr_complex + dvbt_pilot_gen::get_cpilot_value(int cpilot) + { + //TODO - can be calculated at the beginning + return gr_complex((float)(4 * 2 * (0.5 - d_wk[cpilot])) / 3, 0); + } + + void + dvbt_pilot_gen::advance_cpilot() + { + ++d_cpilot_index; + d_cpilot_index = d_cpilot_index % d_cpilot_carriers_size; + } + + void + dvbt_pilot_gen::process_cpilot_data(const gr_complex * in) + { + // Look for maximum correlation for cpilots + // in order to obtain post FFT integer frequency correction + + float max = 0; float sum = 0; + int start = 0; + float phase; + + for (int i = d_zeros_on_left - d_freq_offset_max; i < d_zeros_on_left + d_freq_offset_max; i++) { + sum = 0; + for (int j = 0; j < (d_cpilot_carriers_size - 1); j++) { + phase = norm(in[i + d_cpilot_carriers[j + 1]] - in[i + d_cpilot_carriers[j]]); + sum += d_known_phase_diff[j] * phase; + } + + if (sum > max) { + max = sum; + start = i; + } + } + + d_freq_offset = start - d_zeros_on_left; + } + + void + dvbt_pilot_gen::compute_oneshot_csft(const gr_complex * in) + { + gr_complex left_corr_sum = 0.0; gr_complex right_corr_sum = 0.0; + int half_size = (d_cpilot_carriers_size - 1) / 2; + + // TODO init this in constructor + float carrier_coeff = 1.0 / (2 * M_PI * (1 + float (d_cp_length) / float (d_fft_length)) * 2); + float sampling_coeff = 1.0 / (2 * M_PI * ((1 + float (d_cp_length) / float (d_fft_length)) * ((float)d_cpilot_carriers_size / 2.0))); + + float left_angle, right_angle; + + // Compute cpilots correlation between previous symbol and current symbol + // in both halves of the cpilots. The cpilots are distributed evenly + // on left and right sides of the center frequency. + + for (int j = 0; j < half_size; j++) { + left_corr_sum += in[d_freq_offset + d_zeros_on_left + d_cpilot_carriers[j]] * \ + std::conj(in[d_freq_offset + d_fft_length + d_zeros_on_left + d_cpilot_carriers[j]]); + } + + for (int j = half_size + 1; j < d_cpilot_carriers_size; j++) { + right_corr_sum += in[d_freq_offset + d_zeros_on_left + d_cpilot_carriers[j]] * \ + std::conj(in[d_freq_offset + d_fft_length + d_zeros_on_left + d_cpilot_carriers[j]]); + } + + left_angle = std::arg(left_corr_sum); + right_angle = std::arg(right_corr_sum); + + d_carrier_freq_correction = (right_angle + left_angle) * carrier_coeff; + d_sampling_freq_correction = (right_angle - left_angle) * sampling_coeff; + } + + gr_complex * + dvbt_pilot_gen::frequency_correction(const gr_complex * in, gr_complex * out) + { + // TODO - use PI control loop to calculate tracking corrections + int symbol_count = 1; + + for (int k = 0; k < d_fft_length; k++) { + // TODO - for 2k mode the continuous pilots are not split evenly + // between left/right center frequency. Probably the scattered + // pilots needs to be added. + + float correction = (float)d_freq_offset + d_carrier_freq_correction; + + gr_complex c = gr_expj(-2 * M_PI * correction * \ + (d_fft_length + d_cp_length) / d_fft_length * symbol_count); + + // TODO - vectorize this operation + out[k] = c * in[k + d_freq_offset]; + } + + return (out); + } + + /* + * Init tps sequence, return values for first position + * If first symbol then init tps DBPSK data + */ + int + dvbt_pilot_gen::get_current_tpilot() const + { + return d_tps_carriers[d_tpilot_index]; + } + + gr_complex + dvbt_pilot_gen::get_tpilot_value(int tpilot) + { + //TODO - it can be calculated at the beginnning + if (d_symbol_index == 0) { + d_tps_carriers_val[d_tpilot_index] = gr_complex(2 * (0.5 - d_wk[tpilot]), 0); + } + else { + if (d_tps_data[d_symbol_index] == 1) { + d_tps_carriers_val[d_tpilot_index] = gr_complex(-d_tps_carriers_val[d_tpilot_index].real(), 0); + } + } + + return d_tps_carriers_val[d_tpilot_index]; + } + + void + dvbt_pilot_gen::advance_tpilot() + { + ++d_tpilot_index; + d_tpilot_index = d_tpilot_index % d_tps_carriers_size; + } + + /* + * Set a number of bits to a specified value + */ + void + dvbt_pilot_gen::set_tps_bits(int start, int stop, unsigned int data) + { + for (int i = start; i >= stop; i--) { + d_tps_data[i] = data & 0x1; + data = data >> 1; + } + } + + /* + * Clause 4.6 + * Format data that will be sent with TPS signals + * en 300 744 - section 4.6.2 + * s0 Initialization + * s1-s16 Synchronization word + * s17-s22 Length Indicator + * s23-s24 Frame Number + * S25-s26 Constellation + * s27, s28, s29 Hierarchy information + * s30, s31, s32 Code rate, HP stream + * s33, s34, s35 Code rate, LP stream + * s36, s37 Guard interval + * s38, s39 Transmission mode + * s40, s47 Cell identifier + * s48-s53 All set to "0" + * s54-s67 Error protection (BCH code) + */ + void + dvbt_pilot_gen::format_tps_data() + { + //Clause 4.6.3 + set_tps_bits(0, 0, d_wk[0]); + //Clause 4.6.2.2 + if (d_frame_index % 2) { + set_tps_bits(16, 1, 0xca11); + } + else { + set_tps_bits(16, 1, 0x35ee); + } + //Clause 4.6.2.3 + if (config.d_include_cell_id) { + set_tps_bits(22, 17, 0x1f); + } + else { + set_tps_bits(22, 17, 0x17); + } + //Clause 4.6.2.4 + set_tps_bits(24, 23, d_frame_index); + //Clause 4.6.2.5 + set_tps_bits(26, 25, config.d_constellation); + //Clause 4.6.2.6 + set_tps_bits(29, 27, config.d_hierarchy); + //Clause 4.6.2.7 + switch (config.d_code_rate_HP) { + case C1_2: + set_tps_bits(32, 30, 0); + break; + case C2_3: + set_tps_bits(32, 30, 1); + break; + case C3_4: + set_tps_bits(32, 30, 2); + break; + case C5_6: + set_tps_bits(32, 30, 3); + break; + case C7_8: + set_tps_bits(32, 30, 4); + break; + default: + set_tps_bits(32, 30, 0); + break; + } + switch (config.d_code_rate_LP) { + case C1_2: + set_tps_bits(35, 33, 0); + break; + case C2_3: + set_tps_bits(35, 33, 1); + break; + case C3_4: + set_tps_bits(35, 33, 2); + break; + case C5_6: + set_tps_bits(35, 33, 3); + break; + case C7_8: + set_tps_bits(35, 33, 4); + break; + default: + set_tps_bits(35, 33, 0); + break; + } + //Clause 4.6.2.8 + set_tps_bits(37, 36, config.d_guard_interval); + //Clause 4.6.2.9 + set_tps_bits(39, 38, config.d_transmission_mode); + //Clause 4.6.2.10 + set_tps_bits(47, 40, config.d_cell_id); + //These bits are set to zero + set_tps_bits(53, 48, 0); + //Clause 4.6.2.11 + generate_bch_code(); + } + + int + dvbt_pilot_gen::process_tps_data(const gr_complex * in, const int diff_symbol_index) + { + int end_frame = 0; + + // Look for TPS data only - demodulate DBPSK + // Calculate phase difference between previous symbol + // and current one to determine the current bit. + // Use majority voting for decision + int tps_majority_zero = 0; + + for (int k = 0; k < d_tps_carriers_size; k++) { + // Use equalizer to correct data and frequency correction + gr_complex val = in[d_zeros_on_left + d_tps_carriers[k]] * d_channel_gain[d_tps_carriers[k]]; + + if (!d_symbol_index_known || (d_symbol_index != 0)) { + gr_complex phdiff = val * conj(d_prev_tps_symbol[k]); + + if (phdiff.real() >= 0.0) { + tps_majority_zero++; + } + else { + tps_majority_zero--; + } + } + + d_prev_tps_symbol[k] = val; + } + + // Insert obtained TPS bit into FIFO + // Insert the same bit into FIFO in the case + // diff_symbol_index is more than one. This will happen + // in the case of losing 1 to 3 symbols. + // This could be corrected by BCH decoder afterwards. + + for (int i = 0; i < diff_symbol_index; i++) { + // Take out the front entry first + d_rcv_tps_data.pop_front(); + + // Add data at tail + if (!d_symbol_index_known || (d_symbol_index != 0)) { + if (tps_majority_zero >= 0) { + d_rcv_tps_data.push_back(0); + } + else { + d_rcv_tps_data.push_back(1); + } + } + else { + d_rcv_tps_data.push_back(0); + } + } + + // Match synchronization signatures + if (std::equal(d_rcv_tps_data.begin() + 1, d_rcv_tps_data.begin() + d_tps_sync_evenv.size(), d_tps_sync_evenv.begin())) { + // Verify parity for TPS data + if (!verify_bch_code(d_rcv_tps_data)) { + d_frame_index = (d_rcv_tps_data[23] << 1) | (d_rcv_tps_data[24]); + + d_symbol_index_known = 1; + end_frame = 1; + } + else { + d_symbol_index_known = 0; + end_frame = 0; + } + + // Clear up FIFO + for (int i = 0; i < d_symbols_per_frame; i++) { + d_rcv_tps_data[i] = 0; + } + } + else if (std::equal(d_rcv_tps_data.begin() + 1, d_rcv_tps_data.begin() + d_tps_sync_oddv.size(), d_tps_sync_oddv.begin())) { + // Verify parity for TPS data + if (!verify_bch_code(d_rcv_tps_data)) { + d_frame_index = (d_rcv_tps_data[23] << 1) | (d_rcv_tps_data[24]); + + d_symbol_index_known = 1; + end_frame = 1; + } + else { + d_symbol_index_known = 0; + end_frame = 0; + } + + // Clear up FIFO + for (int i = 0; i < d_symbols_per_frame; i++) { + d_rcv_tps_data[i] = 0; + } + } + + return end_frame; + } + + void + dvbt_pilot_gen::set_chanestim_carrier(int k) + { + d_chanestim_carriers[d_chanestim_index] = k; + } + + void + dvbt_pilot_gen::advance_chanestim() + { + d_chanestim_index++; + } + + int + dvbt_pilot_gen::get_current_payload() + { + return d_payload_carriers[d_payload_index]; + } + + void + dvbt_pilot_gen::set_payload_carrier(int k) + { + d_payload_carriers[d_payload_index] = k; + } + + void + dvbt_pilot_gen::advance_payload() + { + d_payload_index++; + } + + void + dvbt_pilot_gen::process_payload_data(const gr_complex *in, gr_complex *out) + { + //reset indexes + d_spilot_index = 0; d_cpilot_index = 0; d_tpilot_index = 0; + d_payload_index = 0;d_chanestim_index = 0; + int is_payload = 1; + + //process one block - one symbol + for (int k = 0; k < (d_Kmax - d_Kmin + 1); k++) { + is_payload = 1; + + // Keep data for channel estimation + // This depends on the symbol index + if (k == get_current_spilot(d_mod_symbol_index)) { + advance_spilot(d_mod_symbol_index); + is_payload = 0; + } + + // Keep data for frequency correction + // and channel estimation + if (k == get_current_cpilot()) { + advance_cpilot(); + is_payload = 0; + } + + if (k == get_current_tpilot()) { + advance_tpilot(); + is_payload = 0; + } + + // Keep payload carrier number + // This depends on the symbol index + if (is_payload) { + set_payload_carrier(k); + advance_payload(); + } + } + + if (d_equalizer_ready) { + // Equalize payload data according to channel estimator + for (int i = 0; i < d_payload_index; i++) { + out[i] = in[d_zeros_on_left + d_payload_carriers[i]] * d_channel_gain[d_payload_carriers[i]]; + } + } + else { + // If equ not ready, return 0 + for (int i = 0; i < d_payload_length; i++) { + out[0] = gr_complex(0.0, 0.0); + } + } + } + + void + dvbt_pilot_gen::update_output(const gr_complex *in, gr_complex *out) + { + int is_payload = 1; + int payload_count = 0; + + //move to the next symbol + //re-genereate TPS data + format_tps_data(); + + //reset indexes + payload_count = 0; + d_spilot_index = 0; d_cpilot_index = 0; d_tpilot_index = 0; + + for (int i = 0; i < d_zeros_on_left; i++) { + out[i] = gr_complex(0.0, 0.0); + } + + //process one block - one symbol + for (int k = d_Kmin; k < (d_Kmax - d_Kmin + 1); k++) { + is_payload = 1; + if (k == get_current_spilot(d_symbol_index)) { + out[d_zeros_on_left + k] = get_spilot_value(k); + advance_spilot(d_symbol_index); + is_payload = 0; + } + + if (k == get_current_cpilot()) { + out[d_zeros_on_left + k] = get_cpilot_value(k); + advance_cpilot(); + is_payload = 0; + } + + if (k == get_current_tpilot()) { + out[d_zeros_on_left + k] = get_tpilot_value(k); + advance_tpilot(); + is_payload = 0; + } + + if (is_payload == 1) { + out[d_zeros_on_left + k] = in[payload_count++]; + } + } + + // update indexes + if (++d_symbol_index == d_symbols_per_frame) { + d_symbol_index = 0; + if (++d_frame_index == d_frames_per_superframe) { + d_frame_index = 0; + d_superframe_index++; + } + } + + for (int i = (d_fft_length - d_zeros_on_right); i < d_fft_length; i++) { + out[i] = gr_complex(0.0, 0.0); + } + } + + int + dvbt_pilot_gen::parse_input(const gr_complex *in, gr_complex *out, int * symbol_index, int * frame_index) + { + d_trigger_index++; + + // Obtain frequency correction based on cpilots. + // Obtain channel estimation based on both + // cpilots and spilots. + // We use spilot correlation for finding the symbol index modulo 4 + // The diff between previous sym index and current index is used + // to advance the symbol index inside a frame (0 to 67) + // Then based on the TPS data we find out the start of a frame + + // Process cpilot data + // This is post FFT integer frequency offset estimation + // This is called before all other processing + process_cpilot_data(in); + + // Compute one shot Post-FFT Carrier and Sampling Frequency Tracking + // Obtain fractional Carrer and Sampling frequency corrections + // Before this moment it is assumed to have corrected this: + // - symbol timing (pre-FFT) + // - symbol frequency correction (pre-FFT) + // - integer frequency correction (post-FFT) + // TODO - call this just in the aquisition mode + compute_oneshot_csft(in); + + // Gather all corrections and obtain a corrected OFDM symbol: + // - input symbol shift (post-FFT) + // - integer frequency correction (post-FFT) + // - fractional frequency (carrier and sampling) corrections (post-FFT) + // TODO - use PI to update the corrections + frequency_correction(in, d_derot_in); + + // Process spilot data + // This is channel estimation function + int diff_symbol_index = process_spilot_data(d_derot_in); + + // Correct symbol index so that all subsequent processing + // use correct symbol index + d_symbol_index = (d_symbol_index + diff_symbol_index) % d_symbols_per_frame; + + // Symbol index is used in other modules too + *symbol_index = d_symbol_index; + // Frame index is used in other modules too + *frame_index = d_frame_index; + + // Process TPS data + // If a frame is recognized then signal end of frame + int frame_end = process_tps_data(d_derot_in, diff_symbol_index); + + // We are just at the end of a frame + if (frame_end) { + d_symbol_index = d_symbols_per_frame - 1; + } + + // Process payload data with correct symbol index + process_payload_data(d_derot_in, out); + + // noutput_items should be 1 in this case + return 1; + } + + dvbt_reference_signals::sptr + dvbt_reference_signals::make(int itemsize, int ninput, int noutput, \ + dvb_constellation_t constellation, dvbt_hierarchy_t hierarchy, \ + dvb_code_rate_t code_rate_HP, dvb_code_rate_t code_rate_LP, \ + dvb_guardinterval_t guard_interval, dvbt_transmission_mode_t transmission_mode, \ + int include_cell_id, int cell_id) + { + return gnuradio::get_initial_sptr + (new dvbt_reference_signals_impl(itemsize, ninput, \ + noutput, constellation, hierarchy, code_rate_HP, code_rate_LP, \ + guard_interval, transmission_mode, include_cell_id, cell_id)); + } + + /* + * The private constructor + */ + dvbt_reference_signals_impl::dvbt_reference_signals_impl(int itemsize, int ninput, int noutput, \ + dvb_constellation_t constellation, dvbt_hierarchy_t hierarchy, dvb_code_rate_t code_rate_HP,\ + dvb_code_rate_t code_rate_LP, dvb_guardinterval_t guard_interval,\ + dvbt_transmission_mode_t transmission_mode, int include_cell_id, int cell_id) + : block("dvbt_reference_signals", + io_signature::make(1, 1, itemsize * ninput), + io_signature::make(1, 1, itemsize * noutput)), + config(constellation, hierarchy, code_rate_HP, code_rate_LP, \ + guard_interval, transmission_mode, include_cell_id, cell_id), + d_pg(config) + { + d_ninput = ninput; + d_noutput = noutput; + } + + /* + * Our virtual destructor. + */ + dvbt_reference_signals_impl::~dvbt_reference_signals_impl() + { + } + + void + dvbt_reference_signals_impl::forecast (int noutput_items, gr_vector_int &ninput_items_required) + { + ninput_items_required[0] = noutput_items; + } + + int + dvbt_reference_signals_impl::general_work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const gr_complex *in = (const gr_complex *) input_items[0]; + gr_complex *out = (gr_complex *) output_items[0]; + + for (int i = 0; i < noutput_items; i++) { + d_pg.update_output(&in[i * d_ninput], &out[i * d_noutput]); + } + + // Tell runtime system how many input items we consumed on + // each input stream. + consume_each (noutput_items); + + // Tell runtime system how many output items we produced. + return noutput_items; + } + + } /* namespace dtv */ +} /* namespace gr */ + + diff --git a/gr-dtv/lib/dvbt/dvbt_reference_signals_impl.h b/gr-dtv/lib/dvbt/dvbt_reference_signals_impl.h new file mode 100644 index 0000000000..7d356203cb --- /dev/null +++ b/gr-dtv/lib/dvbt/dvbt_reference_signals_impl.h @@ -0,0 +1,258 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 Free Software Foundation, Inc. + * + * 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_DTV_DVBT_REFERENCE_SIGNALS_IMPL_H +#define INCLUDED_DTV_DVBT_REFERENCE_SIGNALS_IMPL_H + +#include <gnuradio/dtv/dvbt_reference_signals.h> +#include "dvbt_configure.h" +#include <vector> +#include <deque> + + // This should eventually go into a const file + const int SYMBOLS_PER_FRAME = 68; + const int FRAMES_PER_SUPERFRAME = 4; + + const int SCATTERED_PILOT_SIZE_2k = 142; + const int CONTINUAL_PILOT_SIZE_2k = 45; + const int TPS_PILOT_SIZE_2k = 17; + + const int SCATTERED_PILOT_SIZE_8k = 568; + const int CONTINUAL_PILOT_SIZE_8k = 177; + const int TPS_PILOT_SIZE_8k = 68; + +namespace gr { + namespace dtv { + + class dvbt_pilot_gen { + private: + // this should be first in order to be initialized first + const dvbt_configure &config; + + int d_Kmin; + int d_Kmax; + int d_fft_length; + int d_payload_length; + int d_zeros_on_left; + int d_zeros_on_right; + int d_cp_length; + + static const int d_symbols_per_frame; + static const int d_frames_per_superframe; + + // 2k mode + // scattered pilot carriers info + static const int d_spilot_carriers_size_2k; + + // continual pilot carriers info + static const int d_cpilot_carriers_size_2k; + static const int d_cpilot_carriers_2k[]; + + // TPS carriers info + static const int d_tps_carriers_size_2k; + static const int d_tps_carriers_2k[]; + + //8k mode + // scattered pilot carriers info + static const int d_spilot_carriers_size_8k; + + // continual pilot carriers info + static const int d_cpilot_carriers_size_8k; + static const int d_cpilot_carriers_8k[]; + + // TPS carriers info + static const int d_tps_carriers_size_8k; + static const int d_tps_carriers_8k[]; + + // TPS sync data + static const int d_tps_sync_size; + static const int d_tps_sync_even[]; + static const int d_tps_sync_odd[]; + + // Variables to keep data for 2k, 8k, 4k + int d_spilot_carriers_size; + gr_complex * d_spilot_carriers_val; + gr_complex * d_channel_gain; + + int d_cpilot_carriers_size; + const int * d_cpilot_carriers; + float * d_known_phase_diff; + float * d_cpilot_phase_diff; + int d_freq_offset; + float d_carrier_freq_correction; + float d_sampling_freq_correction; + + // Variable to keep corrected OFDM symbol + gr_complex * d_derot_in; + + int d_tps_carriers_size; + const int * d_tps_carriers; + gr_complex * d_tps_carriers_val; + + // Keeps TPS data + unsigned char * d_tps_data; + // Keep TPS carriers values from previous symbol + gr_complex * d_prev_tps_symbol; + // Keep TPS carriers values from current symbol + gr_complex * d_tps_symbol; + // Keeps the rcv TPS data, is a FIFO + std::deque<char> d_rcv_tps_data; + // Keeps the TPS sync sequence + std::deque<char> d_tps_sync_evenv; + std::deque<char> d_tps_sync_oddv; + + // Keeps channel estimation carriers + // we use both continual and scattered carriers + int * d_chanestim_carriers; + + // Keeps paload carriers + int * d_payload_carriers; + + // Indexes for all carriers + int d_spilot_index; + int d_cpilot_index; + int d_tpilot_index; + int d_symbol_index; + int d_symbol_index_known; + int d_frame_index; + int d_superframe_index; + int d_freq_offset_max; + int d_trigger_index; + int d_payload_index; + int d_chanestim_index; + int d_prev_mod_symbol_index; + int d_mod_symbol_index; + int d_equalizer_ready; + + // PRPS generator data buffer + char * d_wk; + // Generate PRBS + void generate_prbs(); + + // TPS private methods + void set_tps_bits(int start, int stop, unsigned int data); + + void set_symbol_index(int index); + int get_symbol_index(); + void set_tps_data(); + void get_tps_data(); + + void reset_pilot_generator(); + + // Scattered pilot generator methods + int get_current_spilot(int spilot) const; + gr_complex get_spilot_value(int spilot); + void set_spilot_value(int spilot, gr_complex val); + void advance_spilot(int sindex); + // Methods used to quick iterate through all spilots + int get_first_spilot(); + int get_last_spilot() const; + int get_next_spilot(); + // Scattered pilot data processing method + int process_spilot_data(const gr_complex * in); + + // Channel estimation methods + void set_channel_gain(int spilot, gr_complex val); + + // Continual pilot generator methods + int get_current_cpilot() const; + gr_complex get_cpilot_value(int cpilot); + void advance_cpilot(); + // Continual pilot data processing methods + void process_cpilot_data(const gr_complex * in); + void compute_oneshot_csft(const gr_complex * in); + gr_complex * frequency_correction(const gr_complex * in, gr_complex * out); + + // TPS generator methods + int get_current_tpilot() const; + gr_complex get_tpilot_value(int tpilot); + void advance_tpilot(); + // TPS data + void format_tps_data(); + // Encode TPS data + void generate_bch_code(); + // Verify parity on TPS data + int verify_bch_code(std::deque<char> data); + // TPS data processing metods + int process_tps_data(const gr_complex * in, const int diff_symbo_index); + + // Channel estimation methods + void set_chanestim_carrier(int k); + + // Payload data processing methods + int get_current_payload(); + void advance_chanestim(); + void set_payload_carrier(int k); + void advance_payload(); + void process_payload_data(const gr_complex *in, gr_complex *out); + + public: + dvbt_pilot_gen(const dvbt_configure &config); + ~dvbt_pilot_gen(); + + /*! + * ETSI EN 300 744 Clause 4.5. \n + * Update a set of carriers with the pilot signals. \n + */ + void update_output(const gr_complex *in, gr_complex *out); + + /*! + * TODO + * ETSI EN 300 744 Clause 4.5. \n + * Extract data from a set of carriers using pilot signals. \n + * This is doing frequency correcton, equalization. \n + */ + int parse_input(const gr_complex *in, gr_complex *out, int * symbol_index, int * frame_index); + }; + + class dvbt_reference_signals_impl : public dvbt_reference_signals + { + // configuration object for this class + const dvbt_configure config; + + private: + // Pilot Generator object + dvbt_pilot_gen d_pg; + + //In and Out data length + int d_ninput; + int d_noutput; + + public: + dvbt_reference_signals_impl(int itemsize, int ninput, int noutput, \ + dvb_constellation_t constellation, dvbt_hierarchy_t hierarchy, \ + dvb_code_rate_t code_rate_HP, dvb_code_rate_t code_rate_LP, \ + dvb_guardinterval_t guard_interval, \ + dvbt_transmission_mode_t transmission_mode = gr::dtv::T2k, int include_cell_id = 0, int cell_id = 0); + ~dvbt_reference_signals_impl(); + + void forecast (int noutput_items, gr_vector_int &ninput_items_required); + + int general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } // namespace dtv +} // namespace gr + +#endif /* INCLUDED_DTV_DVBT_REFERENCE_SIGNALS_IMPL_H */ + diff --git a/gr-dtv/lib/dvbt/dvbt_symbol_inner_interleaver_impl.cc b/gr-dtv/lib/dvbt/dvbt_symbol_inner_interleaver_impl.cc new file mode 100644 index 0000000000..64d242d5fb --- /dev/null +++ b/gr-dtv/lib/dvbt/dvbt_symbol_inner_interleaver_impl.cc @@ -0,0 +1,222 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 Free Software Foundation, Inc. + * + * 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 <gnuradio/io_signature.h> +#include "dvbt_symbol_inner_interleaver_impl.h" +#include <stdio.h> + +namespace gr { + namespace dtv { + + const char dvbt_symbol_inner_interleaver_impl::d_bit_perm_2k[] = {4, 3, 9, 6, 2, 8, 1, 5, 7, 0}; + const char dvbt_symbol_inner_interleaver_impl::d_bit_perm_8k[] = {7, 1, 4, 2, 9, 6, 8, 10, 0, 3, 11, 5}; + + void + dvbt_symbol_inner_interleaver_impl::generate_H() + { + const int Mmax = d_fft_length; + const int Nmax = d_payload_length; + const int Nr = int(ceil(log2(d_fft_length))); + int q = 0; + + for (int i = 0; i < Mmax; i++) { + d_h[q] = ((i % 2) << (Nr - 1)) + calculate_R(i); + if (d_h[q] < Nmax) { + q++; + } + } + } + + int + dvbt_symbol_inner_interleaver_impl::H(int q) + { + return d_h[q]; + } + + int + dvbt_symbol_inner_interleaver_impl::calculate_R(int i) + { + const int Nr = int(ceil(log2(d_fft_length))); + int reg = 0; + + if (i == 0) { + reg = 0; + } + else if (i == 1) { + reg = 0; + } + else { + reg = 1; + for (int k = 3; k <= i; k++) { + char new_bit = 0; + + if (d_transmission_mode == T2k) { + new_bit = (reg ^ (reg >> 3)) & 1; + } + else if (d_transmission_mode == T8k) { + new_bit = (reg ^ (reg >> 1) ^ (reg >> 4) ^ (reg >> 6)) & 1; + } + else { + new_bit = (reg ^ (reg >> 3)) & 1; + } + + int mask = (1 << Nr) - 1; + reg = ((reg >> 1) | (new_bit << (Nr - 2))) & mask; + } + } + + int newreg = 0; + + for (int k = 0; k < (Nr - 1); k++) { + char bit = (reg >> k) & 1; + newreg = newreg | (bit << d_bit_perm[k]); + } + + return newreg; + } + + dvbt_symbol_inner_interleaver::sptr + dvbt_symbol_inner_interleaver::make(int nsize, dvbt_transmission_mode_t transmission, int direction) + { + return gnuradio::get_initial_sptr + (new dvbt_symbol_inner_interleaver_impl(nsize, transmission, direction)); + } + + /* + * The private constructor + */ + dvbt_symbol_inner_interleaver_impl::dvbt_symbol_inner_interleaver_impl(int nsize, dvbt_transmission_mode_t transmission, int direction) + : block("dvbt_symbol_inner_interleaver", + io_signature::make(1, 1, sizeof(unsigned char) * nsize), + io_signature::make(1, 1, sizeof(unsigned char) * nsize)), + config(gr::dtv::MOD_16QAM, gr::dtv::NH, gr::dtv::C1_2, gr::dtv::C1_2, gr::dtv::GI_1_32, transmission), + d_nsize(nsize), d_direction(direction), + d_fft_length(0), d_payload_length(0), + d_symbol_index(0) + { + d_symbols_per_frame = config.d_symbols_per_frame; + d_transmission_mode = config.d_transmission_mode; + d_fft_length = config.d_fft_length; + d_payload_length = config.d_payload_length; + d_direction = direction; + + // Verify if transmission mode matches with size of block + assert(d_payload_length == d_nsize); + + // Allocate memory for h vector + d_h = new int[d_fft_length]; + if (d_h == NULL) { + std::cout << "Cannot allocate memory for d_h" << std::endl; + exit(1); + } + + // Setup bit permutation vectors + if (d_transmission_mode == T2k) { + d_bit_perm = d_bit_perm_2k; + } + else if (d_transmission_mode == T8k) { + d_bit_perm = d_bit_perm_8k; + } + else { + d_bit_perm = d_bit_perm_2k; + } + + // Generate the h function + generate_H(); + } + + /* + * Our virtual destructor. + */ + dvbt_symbol_inner_interleaver_impl::~dvbt_symbol_inner_interleaver_impl() + { + delete [] d_h; + } + + void + dvbt_symbol_inner_interleaver_impl::forecast (int noutput_items, gr_vector_int &ninput_items_required) + { + ninput_items_required[0] = noutput_items; + } + + int + dvbt_symbol_inner_interleaver_impl::general_work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const unsigned char *in = (unsigned char *) input_items[0]; + unsigned char *out = (unsigned char *) output_items[0]; + + // Demod reference signals sends a tag per OFDM frame + // containing the symbol index. + std::vector<tag_t> tags; + const uint64_t nread = this->nitems_read(0); //number of items read on port 0 + + // Read all tags on the input buffer + this->get_tags_in_range(tags, 0, nread, nread + noutput_items, pmt::string_to_symbol("symbol_index")); + + for (int k = 0; k < noutput_items; k++) { + int blocks = k * d_nsize; + + if (d_direction) { + // Interleave + for (int q = 0; q < d_nsize; q++) { + if (d_symbol_index % 2) { + out[blocks + q] = in[blocks + H(q)]; + } + else { + out[blocks + H(q)] = in[blocks + q]; + } + } + + ++d_symbol_index; + d_symbol_index = d_symbol_index % d_symbols_per_frame; + } + else { + // Deinterleave + d_symbol_index = pmt::to_long(tags[k].value); + + for (int q = 0; q < d_nsize; q++) { + if (d_symbol_index % 2) { + out[blocks + H(q)] = in[blocks + q]; + } + else { + out[blocks + q] = in[blocks + H(q)]; + } + } + } + } + + // Tell runtime system how many input items we consumed on + // each input stream. + consume_each (noutput_items); + + // Tell runtime system how many output items we produced. + return noutput_items; + } + + } /* namespace dtv */ +} /* namespace gr */ + diff --git a/gr-dtv/lib/dvbt/dvbt_symbol_inner_interleaver_impl.h b/gr-dtv/lib/dvbt/dvbt_symbol_inner_interleaver_impl.h new file mode 100644 index 0000000000..6a7265d7e1 --- /dev/null +++ b/gr-dtv/lib/dvbt/dvbt_symbol_inner_interleaver_impl.h @@ -0,0 +1,70 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 Free Software Foundation, Inc. + * + * 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_DTV_DVBT_SYMBOL_INNER_INTERLEAVER_IMPL_H +#define INCLUDED_DTV_DVBT_SYMBOL_INNER_INTERLEAVER_IMPL_H + +#include <gnuradio/dtv/dvbt_symbol_inner_interleaver.h> +#include "dvbt_configure.h" + +namespace gr { + namespace dtv { + + class dvbt_symbol_inner_interleaver_impl : public dvbt_symbol_inner_interleaver + { + private: + const dvbt_configure config; + + int d_symbols_per_frame; + dvbt_transmission_mode_t d_transmission_mode; + int d_nsize; + int d_direction; + int d_fft_length; + int d_payload_length; + + int * d_h; + const char * d_bit_perm; + static const char d_bit_perm_2k[]; + static const char d_bit_perm_8k[]; + + //Keeps the symbol index + unsigned int d_symbol_index; + + void generate_H(); + int H(int q); + int calculate_R(int i); + + public: + dvbt_symbol_inner_interleaver_impl(int nsize, dvbt_transmission_mode_t transmission, int direction); + ~dvbt_symbol_inner_interleaver_impl(); + + void forecast (int noutput_items, gr_vector_int &ninput_items_required); + + int general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } // namespace dtv +} // namespace gr + +#endif /* INCLUDED_DTV_DVBT_SYMBOL_INNER_INTERLEAVER_IMPL_H */ + diff --git a/gr-dtv/lib/dvbt2/dvbt2_framemapper_cc_impl.cc b/gr-dtv/lib/dvbt2/dvbt2_framemapper_cc_impl.cc index a09af908c9..0c05285eda 100644 --- a/gr-dtv/lib/dvbt2/dvbt2_framemapper_cc_impl.cc +++ b/gr-dtv/lib/dvbt2/dvbt2_framemapper_cc_impl.cc @@ -30,7 +30,7 @@ namespace gr { namespace dtv { dvbt2_framemapper_cc::sptr - dvbt2_framemapper_cc::make(dvb_framesize_t framesize, dvb_code_rate_t rate, dvb_constellation_t constellation, dvbt2_rotation_t rotation, int fecblocks, int tiblocks, dvbt2_extended_carrier_t carriermode, dvbt2_fftsize_t fftsize, dvbt2_guardinterval_t guardinterval, dvbt2_l1constellation_t l1constellation, dvbt2_pilotpattern_t pilotpattern, int t2frames, int numdatasyms, dvbt2_papr_t paprmode, dvbt2_version_t version, dvbt2_preamble_t preamble, dvbt2_inputmode_t inputmode, dvbt2_reservedbiasbits_t reservedbiasbits, dvbt2_l1scrambled_t l1scrambled, dvbt2_inband_t inband) + dvbt2_framemapper_cc::make(dvb_framesize_t framesize, dvb_code_rate_t rate, dvb_constellation_t constellation, dvbt2_rotation_t rotation, int fecblocks, int tiblocks, dvbt2_extended_carrier_t carriermode, dvbt2_fftsize_t fftsize, dvb_guardinterval_t guardinterval, dvbt2_l1constellation_t l1constellation, dvbt2_pilotpattern_t pilotpattern, int t2frames, int numdatasyms, dvbt2_papr_t paprmode, dvbt2_version_t version, dvbt2_preamble_t preamble, dvbt2_inputmode_t inputmode, dvbt2_reservedbiasbits_t reservedbiasbits, dvbt2_l1scrambled_t l1scrambled, dvbt2_inband_t inband) { return gnuradio::get_initial_sptr (new dvbt2_framemapper_cc_impl(framesize, rate, constellation, rotation, fecblocks, tiblocks, carriermode, fftsize, guardinterval, l1constellation, pilotpattern, t2frames, numdatasyms, paprmode, version, preamble, inputmode, reservedbiasbits, l1scrambled, inband)); @@ -39,7 +39,7 @@ namespace gr { /* * The private constructor */ - dvbt2_framemapper_cc_impl::dvbt2_framemapper_cc_impl(dvb_framesize_t framesize, dvb_code_rate_t rate, dvb_constellation_t constellation, dvbt2_rotation_t rotation, int fecblocks, int tiblocks, dvbt2_extended_carrier_t carriermode, dvbt2_fftsize_t fftsize, dvbt2_guardinterval_t guardinterval, dvbt2_l1constellation_t l1constellation, dvbt2_pilotpattern_t pilotpattern, int t2frames, int numdatasyms, dvbt2_papr_t paprmode, dvbt2_version_t version, dvbt2_preamble_t preamble, dvbt2_inputmode_t inputmode, dvbt2_reservedbiasbits_t reservedbiasbits, dvbt2_l1scrambled_t l1scrambled, dvbt2_inband_t inband) + dvbt2_framemapper_cc_impl::dvbt2_framemapper_cc_impl(dvb_framesize_t framesize, dvb_code_rate_t rate, dvb_constellation_t constellation, dvbt2_rotation_t rotation, int fecblocks, int tiblocks, dvbt2_extended_carrier_t carriermode, dvbt2_fftsize_t fftsize, dvb_guardinterval_t guardinterval, dvbt2_l1constellation_t l1constellation, dvbt2_pilotpattern_t pilotpattern, int t2frames, int numdatasyms, dvbt2_papr_t paprmode, dvbt2_version_t version, dvbt2_preamble_t preamble, dvbt2_inputmode_t inputmode, dvbt2_reservedbiasbits_t reservedbiasbits, dvbt2_l1scrambled_t l1scrambled, dvbt2_inband_t inband) : gr::block("dvbt2_framemapper_cc", gr::io_signature::make(1, 1, sizeof(gr_complex)), gr::io_signature::make(1, 1, sizeof(gr_complex))) @@ -86,9 +86,6 @@ namespace gr { break; } } - fef_present = FALSE; /* for testing only */ - fef_length = 134144; /* " " " */ - fef_interval = 1; /* " " " */ l1preinit->type = STREAMTYPE_TS; l1preinit->bwt_ext = carriermode; fft_size = fftsize; @@ -100,12 +97,7 @@ namespace gr { l1preinit->l1_mod = l1constellation; l1preinit->l1_cod = 0; l1preinit->l1_fec_type = 0; - if (fef_present == FALSE) { - l1preinit->l1_post_info_size = KSIG_POST - 32; - } - else { - l1preinit->l1_post_info_size = KSIG_POST + 34 - 32; - } + l1preinit->l1_post_info_size = KSIG_POST - 32; l1preinit->pilot_pattern = pilotpattern; l1preinit->tx_id_availability = 0; l1preinit->cell_id = 0; @@ -144,12 +136,7 @@ namespace gr { l1postinit->ff_flag = 0; l1postinit->first_rf_idx = 0; l1postinit->first_frame_idx = 0; - if (fef_present == FALSE) { - l1postinit->plp_group_id = 1; - } - else { - l1postinit->plp_group_id = 0; - } + l1postinit->plp_group_id = 1; switch (rate) { case C1_3: l1postinit->plp_cod = 6; @@ -205,14 +192,8 @@ namespace gr { else { l1postinit->plp_mode = inputmode + 1; } - if (fef_present == FALSE) { - l1postinit->static_flag = 0; - l1postinit->static_padding_flag = 0; - } - else { - l1postinit->static_flag = 1; - l1postinit->static_padding_flag = 1; - } + l1postinit->static_flag = 0; + l1postinit->static_padding_flag = 0; l1postinit->fef_length_msb = 0; if (reservedbiasbits == RESERVED_ON && version == VERSION_131) { l1postinit->reserved_2 = 0x3fffffff; @@ -351,6 +332,11 @@ namespace gr { eta_mod = 6; break; } + N_P2 = 0; + C_P2 = 0; + N_FC = 0; + C_FC = 0; + C_DATA = 0; if ((preamble == PREAMBLE_T2_SISO) || (preamble == PREAMBLE_T2_LITE_SISO)) { switch (fft_size) { case FFTSIZE_1K: @@ -904,14 +890,8 @@ namespace gr { C_FC = 0; } } - if (fef_present == FALSE) { - N_punc_temp = (6 * (KBCH_1_2 - KSIG_POST)) / 5; - N_post_temp = KSIG_POST + NBCH_PARITY + 9000 - N_punc_temp; - } - else { - N_punc_temp = (6 * (KBCH_1_2 - (KSIG_POST + 34))) / 5; - N_post_temp = (KSIG_POST + 34) + NBCH_PARITY + 9000 - N_punc_temp; - } + N_punc_temp = (6 * (KBCH_1_2 - KSIG_POST)) / 5; + N_post_temp = KSIG_POST + NBCH_PARITY + 9000 - N_punc_temp; if (N_P2 == 1) { N_post = ceil((float)N_post_temp / (2 * (float)eta_mod)) * 2 * eta_mod; } @@ -1166,12 +1146,7 @@ namespace gr { for (int n = 2; n >= 0; n--) { l1pre[offset_bits++] = temp & (1 << n) ? 1 : 0; } - if (fef_present == FALSE) { - l1pre[offset_bits++] = 0; - } - else { - l1pre[offset_bits++] = 1; - } + l1pre[offset_bits++] = 0; l1pre[offset_bits++] = l1preinit->l1_repetition_flag; temp = l1preinit->guard_interval; for (int n = 2; n >= 0; n--) { @@ -1356,20 +1331,6 @@ namespace gr { for (int n = 31; n >= 0; n--) { l1post[offset_bits++] = temp & (1 << n) ? 1 : 0; } - if (fef_present == TRUE) { - temp = 0; - for (int n = 3; n >= 0; n--) { - l1post[offset_bits++] = temp & (1 << n) ? 1 : 0; - } - temp = fef_length; - for (int n = 21; n >= 0; n--) { - l1post[offset_bits++] = temp & (1 << n) ? 1 : 0; - } - temp = fef_interval; - for (int n = 7; n >= 0; n--) { - l1post[offset_bits++] = temp & (1 << n) ? 1 : 0; - } - } temp = l1postinit->plp_id; for (int n = 7; n >= 0; n--) { l1post[offset_bits++] = temp & (1 << n) ? 1 : 0; diff --git a/gr-dtv/lib/dvbt2/dvbt2_framemapper_cc_impl.h b/gr-dtv/lib/dvbt2/dvbt2_framemapper_cc_impl.h index 2b25b2ddd1..8d35493f45 100644 --- a/gr-dtv/lib/dvbt2/dvbt2_framemapper_cc_impl.h +++ b/gr-dtv/lib/dvbt2/dvbt2_framemapper_cc_impl.h @@ -139,9 +139,6 @@ namespace gr { int t2_frames; int t2_frame_num; int l1_scrambled; - int fef_present; - int fef_length; - int fef_interval; int N_P2; int C_P2; int N_FC; @@ -193,7 +190,7 @@ namespace gr { const static int mux64[12]; public: - dvbt2_framemapper_cc_impl(dvb_framesize_t framesize, dvb_code_rate_t rate, dvb_constellation_t constellation, dvbt2_rotation_t rotation, int fecblocks, int tiblocks, dvbt2_extended_carrier_t carriermode, dvbt2_fftsize_t fftsize, dvbt2_guardinterval_t guardinterval, dvbt2_l1constellation_t l1constellation, dvbt2_pilotpattern_t pilotpattern, int t2frames, int numdatasyms, dvbt2_papr_t paprmode, dvbt2_version_t version, dvbt2_preamble_t preamble, dvbt2_inputmode_t inputmode, dvbt2_reservedbiasbits_t reservedbiasbits, dvbt2_l1scrambled_t l1scrambled, dvbt2_inband_t inband); + dvbt2_framemapper_cc_impl(dvb_framesize_t framesize, dvb_code_rate_t rate, dvb_constellation_t constellation, dvbt2_rotation_t rotation, int fecblocks, int tiblocks, dvbt2_extended_carrier_t carriermode, dvbt2_fftsize_t fftsize, dvb_guardinterval_t guardinterval, dvbt2_l1constellation_t l1constellation, dvbt2_pilotpattern_t pilotpattern, int t2frames, int numdatasyms, dvbt2_papr_t paprmode, dvbt2_version_t version, dvbt2_preamble_t preamble, dvbt2_inputmode_t inputmode, dvbt2_reservedbiasbits_t reservedbiasbits, dvbt2_l1scrambled_t l1scrambled, dvbt2_inband_t inband); ~dvbt2_framemapper_cc_impl(); void forecast (int noutput_items, gr_vector_int &ninput_items_required); diff --git a/gr-dtv/lib/dvbt2/dvbt2_freqinterleaver_cc_impl.cc b/gr-dtv/lib/dvbt2/dvbt2_freqinterleaver_cc_impl.cc index acee74321b..f89d2af7f7 100644 --- a/gr-dtv/lib/dvbt2/dvbt2_freqinterleaver_cc_impl.cc +++ b/gr-dtv/lib/dvbt2/dvbt2_freqinterleaver_cc_impl.cc @@ -29,7 +29,7 @@ namespace gr { namespace dtv { dvbt2_freqinterleaver_cc::sptr - dvbt2_freqinterleaver_cc::make(dvbt2_extended_carrier_t carriermode, dvbt2_fftsize_t fftsize, dvbt2_pilotpattern_t pilotpattern, dvbt2_guardinterval_t guardinterval, int numdatasyms, dvbt2_papr_t paprmode, dvbt2_version_t version, dvbt2_preamble_t preamble) + dvbt2_freqinterleaver_cc::make(dvbt2_extended_carrier_t carriermode, dvbt2_fftsize_t fftsize, dvbt2_pilotpattern_t pilotpattern, dvb_guardinterval_t guardinterval, int numdatasyms, dvbt2_papr_t paprmode, dvbt2_version_t version, dvbt2_preamble_t preamble) { return gnuradio::get_initial_sptr (new dvbt2_freqinterleaver_cc_impl(carriermode, fftsize, pilotpattern, guardinterval, numdatasyms, paprmode, version, preamble)); @@ -38,7 +38,7 @@ namespace gr { /* * The private constructor */ - dvbt2_freqinterleaver_cc_impl::dvbt2_freqinterleaver_cc_impl(dvbt2_extended_carrier_t carriermode, dvbt2_fftsize_t fftsize, dvbt2_pilotpattern_t pilotpattern, dvbt2_guardinterval_t guardinterval, int numdatasyms, dvbt2_papr_t paprmode, dvbt2_version_t version, dvbt2_preamble_t preamble) + dvbt2_freqinterleaver_cc_impl::dvbt2_freqinterleaver_cc_impl(dvbt2_extended_carrier_t carriermode, dvbt2_fftsize_t fftsize, dvbt2_pilotpattern_t pilotpattern, dvb_guardinterval_t guardinterval, int numdatasyms, dvbt2_papr_t paprmode, dvbt2_version_t version, dvbt2_preamble_t preamble) : gr::sync_block("dvbt2_freqinterleaver_cc", gr::io_signature::make(1, 1, sizeof(gr_complex)), gr::io_signature::make(1, 1, sizeof(gr_complex))) diff --git a/gr-dtv/lib/dvbt2/dvbt2_freqinterleaver_cc_impl.h b/gr-dtv/lib/dvbt2/dvbt2_freqinterleaver_cc_impl.h index 18ce8895b9..a52dc9ed94 100644 --- a/gr-dtv/lib/dvbt2/dvbt2_freqinterleaver_cc_impl.h +++ b/gr-dtv/lib/dvbt2/dvbt2_freqinterleaver_cc_impl.h @@ -57,7 +57,7 @@ namespace gr { const static int bitperm32k[14]; public: - dvbt2_freqinterleaver_cc_impl(dvbt2_extended_carrier_t carriermode, dvbt2_fftsize_t fftsize, dvbt2_pilotpattern_t pilotpattern, dvbt2_guardinterval_t guardinterval, int numdatasyms, dvbt2_papr_t paprmode, dvbt2_version_t version, dvbt2_preamble_t preamble); + dvbt2_freqinterleaver_cc_impl(dvbt2_extended_carrier_t carriermode, dvbt2_fftsize_t fftsize, dvbt2_pilotpattern_t pilotpattern, dvb_guardinterval_t guardinterval, int numdatasyms, dvbt2_papr_t paprmode, dvbt2_version_t version, dvbt2_preamble_t preamble); ~dvbt2_freqinterleaver_cc_impl(); int work(int noutput_items, diff --git a/gr-dtv/lib/dvbt2/dvbt2_miso_cc_impl.cc b/gr-dtv/lib/dvbt2/dvbt2_miso_cc_impl.cc index 3f19c31c48..a3d2684650 100644 --- a/gr-dtv/lib/dvbt2/dvbt2_miso_cc_impl.cc +++ b/gr-dtv/lib/dvbt2/dvbt2_miso_cc_impl.cc @@ -29,7 +29,7 @@ namespace gr { namespace dtv { dvbt2_miso_cc::sptr - dvbt2_miso_cc::make(dvbt2_extended_carrier_t carriermode, dvbt2_fftsize_t fftsize, dvbt2_pilotpattern_t pilotpattern, dvbt2_guardinterval_t guardinterval, int numdatasyms, dvbt2_papr_t paprmode) + dvbt2_miso_cc::make(dvbt2_extended_carrier_t carriermode, dvbt2_fftsize_t fftsize, dvbt2_pilotpattern_t pilotpattern, dvb_guardinterval_t guardinterval, int numdatasyms, dvbt2_papr_t paprmode) { return gnuradio::get_initial_sptr (new dvbt2_miso_cc_impl(carriermode, fftsize, pilotpattern, guardinterval, numdatasyms, paprmode)); @@ -38,7 +38,7 @@ namespace gr { /* * The private constructor */ - dvbt2_miso_cc_impl::dvbt2_miso_cc_impl(dvbt2_extended_carrier_t carriermode, dvbt2_fftsize_t fftsize, dvbt2_pilotpattern_t pilotpattern, dvbt2_guardinterval_t guardinterval, int numdatasyms, dvbt2_papr_t paprmode) + dvbt2_miso_cc_impl::dvbt2_miso_cc_impl(dvbt2_extended_carrier_t carriermode, dvbt2_fftsize_t fftsize, dvbt2_pilotpattern_t pilotpattern, dvb_guardinterval_t guardinterval, int numdatasyms, dvbt2_papr_t paprmode) : gr::sync_block("dvbt2_miso_cc", gr::io_signature::make(1, 1, sizeof(gr_complex)), gr::io_signature::make(2, 2, sizeof(gr_complex))) diff --git a/gr-dtv/lib/dvbt2/dvbt2_miso_cc_impl.h b/gr-dtv/lib/dvbt2/dvbt2_miso_cc_impl.h index e33b201d21..8dcbdf9c7a 100644 --- a/gr-dtv/lib/dvbt2/dvbt2_miso_cc_impl.h +++ b/gr-dtv/lib/dvbt2/dvbt2_miso_cc_impl.h @@ -38,7 +38,7 @@ namespace gr { int C_DATA; public: - dvbt2_miso_cc_impl(dvbt2_extended_carrier_t carriermode, dvbt2_fftsize_t fftsize, dvbt2_pilotpattern_t pilotpattern, dvbt2_guardinterval_t guardinterval, int numdatasyms, dvbt2_papr_t paprmode); + dvbt2_miso_cc_impl(dvbt2_extended_carrier_t carriermode, dvbt2_fftsize_t fftsize, dvbt2_pilotpattern_t pilotpattern, dvb_guardinterval_t guardinterval, int numdatasyms, dvbt2_papr_t paprmode); ~dvbt2_miso_cc_impl(); int work(int noutput_items, diff --git a/gr-dtv/lib/dvbt2/dvbt2_p1insertion_cc_impl.cc b/gr-dtv/lib/dvbt2/dvbt2_p1insertion_cc_impl.cc index 22415af97b..9a2a41b395 100644 --- a/gr-dtv/lib/dvbt2/dvbt2_p1insertion_cc_impl.cc +++ b/gr-dtv/lib/dvbt2/dvbt2_p1insertion_cc_impl.cc @@ -30,7 +30,7 @@ namespace gr { namespace dtv { dvbt2_p1insertion_cc::sptr - dvbt2_p1insertion_cc::make(dvbt2_extended_carrier_t carriermode, dvbt2_fftsize_t fftsize, dvbt2_guardinterval_t guardinterval, int numdatasyms, dvbt2_preamble_t preamble, dvbt2_showlevels_t showlevels, float vclip) + dvbt2_p1insertion_cc::make(dvbt2_extended_carrier_t carriermode, dvbt2_fftsize_t fftsize, dvb_guardinterval_t guardinterval, int numdatasyms, dvbt2_preamble_t preamble, dvbt2_showlevels_t showlevels, float vclip) { return gnuradio::get_initial_sptr (new dvbt2_p1insertion_cc_impl(carriermode, fftsize, guardinterval, numdatasyms, preamble, showlevels, vclip)); @@ -39,13 +39,12 @@ namespace gr { /* * The private constructor */ - dvbt2_p1insertion_cc_impl::dvbt2_p1insertion_cc_impl(dvbt2_extended_carrier_t carriermode, dvbt2_fftsize_t fftsize, dvbt2_guardinterval_t guardinterval, int numdatasyms, dvbt2_preamble_t preamble, dvbt2_showlevels_t showlevels, float vclip) + dvbt2_p1insertion_cc_impl::dvbt2_p1insertion_cc_impl(dvbt2_extended_carrier_t carriermode, dvbt2_fftsize_t fftsize, dvb_guardinterval_t guardinterval, int numdatasyms, dvbt2_preamble_t preamble, dvbt2_showlevels_t showlevels, float vclip) : gr::block("dvbt2_p1insertion_cc", gr::io_signature::make(1, 1, sizeof(gr_complex)), gr::io_signature::make(1, 1, sizeof(gr_complex))) { int s1, s2, index = 0; - int fef_present = FALSE; /* for testing only */ const gr_complex *in = (const gr_complex *) p1_freq; gr_complex *out = (gr_complex *) p1_time; s1 = preamble; @@ -103,9 +102,6 @@ namespace gr { } init_p1_randomizer(); s2 = (fftsize & 0x7) << 1; - if (fef_present == TRUE) { - s2 |= 1; - } for (int i = 0; i < 8; i++) { for (int j = 7; j >= 0; j--) { modulation_sequence[index++] = (s1_modulation_patterns[s1][i] >> j) & 0x1; diff --git a/gr-dtv/lib/dvbt2/dvbt2_p1insertion_cc_impl.h b/gr-dtv/lib/dvbt2/dvbt2_p1insertion_cc_impl.h index 85537b5b34..3931723009 100644 --- a/gr-dtv/lib/dvbt2/dvbt2_p1insertion_cc_impl.h +++ b/gr-dtv/lib/dvbt2/dvbt2_p1insertion_cc_impl.h @@ -67,7 +67,7 @@ namespace gr { const static unsigned char s2_modulation_patterns[16][32]; public: - dvbt2_p1insertion_cc_impl(dvbt2_extended_carrier_t carriermode, dvbt2_fftsize_t fftsize, dvbt2_guardinterval_t guardinterval, int numdatasyms, dvbt2_preamble_t preamble, dvbt2_showlevels_t showlevels, float vclip); + dvbt2_p1insertion_cc_impl(dvbt2_extended_carrier_t carriermode, dvbt2_fftsize_t fftsize, dvb_guardinterval_t guardinterval, int numdatasyms, dvbt2_preamble_t preamble, dvbt2_showlevels_t showlevels, float vclip); ~dvbt2_p1insertion_cc_impl(); void forecast (int noutput_items, gr_vector_int &ninput_items_required); diff --git a/gr-dtv/lib/dvbt2/dvbt2_paprtr_cc_impl.cc b/gr-dtv/lib/dvbt2/dvbt2_paprtr_cc_impl.cc index db3fd00035..b4f17564af 100644 --- a/gr-dtv/lib/dvbt2/dvbt2_paprtr_cc_impl.cc +++ b/gr-dtv/lib/dvbt2/dvbt2_paprtr_cc_impl.cc @@ -31,7 +31,7 @@ namespace gr { namespace dtv { dvbt2_paprtr_cc::sptr - dvbt2_paprtr_cc::make(dvbt2_extended_carrier_t carriermode, dvbt2_fftsize_t fftsize, dvbt2_pilotpattern_t pilotpattern, dvbt2_guardinterval_t guardinterval, int numdatasyms, dvbt2_papr_t paprmode, dvbt2_version_t version, float vclip, int iterations, int vlength) + dvbt2_paprtr_cc::make(dvbt2_extended_carrier_t carriermode, dvbt2_fftsize_t fftsize, dvbt2_pilotpattern_t pilotpattern, dvb_guardinterval_t guardinterval, int numdatasyms, dvbt2_papr_t paprmode, dvbt2_version_t version, float vclip, int iterations, int vlength) { return gnuradio::get_initial_sptr (new dvbt2_paprtr_cc_impl(carriermode, fftsize, pilotpattern, guardinterval, numdatasyms, paprmode, version, vclip, iterations, vlength)); @@ -40,7 +40,7 @@ namespace gr { /* * The private constructor */ - dvbt2_paprtr_cc_impl::dvbt2_paprtr_cc_impl(dvbt2_extended_carrier_t carriermode, dvbt2_fftsize_t fftsize, dvbt2_pilotpattern_t pilotpattern, dvbt2_guardinterval_t guardinterval, int numdatasyms, dvbt2_papr_t paprmode, dvbt2_version_t version, float vclip, int iterations, int vlength) + dvbt2_paprtr_cc_impl::dvbt2_paprtr_cc_impl(dvbt2_extended_carrier_t carriermode, dvbt2_fftsize_t fftsize, dvbt2_pilotpattern_t pilotpattern, dvb_guardinterval_t guardinterval, int numdatasyms, dvbt2_papr_t paprmode, dvbt2_version_t version, float vclip, int iterations, int vlength) : gr::sync_block("dvbt2_paprtr_cc", gr::io_signature::make(1, 1, sizeof(gr_complex) * vlength), gr::io_signature::make(1, 1, sizeof(gr_complex) * vlength)) @@ -500,6 +500,8 @@ namespace gr { dy = 16; break; } + shift = 0; + papr_map = p2_papr_map; fft_size = fftsize; pilot_pattern = pilotpattern; carrier_mode = carriermode; diff --git a/gr-dtv/lib/dvbt2/dvbt2_paprtr_cc_impl.h b/gr-dtv/lib/dvbt2/dvbt2_paprtr_cc_impl.h index 96c669f8aa..aac5e48c3f 100644 --- a/gr-dtv/lib/dvbt2/dvbt2_paprtr_cc_impl.h +++ b/gr-dtv/lib/dvbt2/dvbt2_paprtr_cc_impl.h @@ -97,7 +97,7 @@ namespace gr { const static int tr_papr_map_32k[288]; public: - dvbt2_paprtr_cc_impl(dvbt2_extended_carrier_t carriermode, dvbt2_fftsize_t fftsize, dvbt2_pilotpattern_t pilotpattern, dvbt2_guardinterval_t guardinterval, int numdatasyms, dvbt2_papr_t paprmode, dvbt2_version_t version, float vclip, int iterations, int vlength); + dvbt2_paprtr_cc_impl(dvbt2_extended_carrier_t carriermode, dvbt2_fftsize_t fftsize, dvbt2_pilotpattern_t pilotpattern, dvb_guardinterval_t guardinterval, int numdatasyms, dvbt2_papr_t paprmode, dvbt2_version_t version, float vclip, int iterations, int vlength); ~dvbt2_paprtr_cc_impl(); int work(int noutput_items, diff --git a/gr-dtv/lib/dvbt2/dvbt2_pilotgenerator_cc_impl.cc b/gr-dtv/lib/dvbt2/dvbt2_pilotgenerator_cc_impl.cc index 05dacce62d..26c83492b9 100644 --- a/gr-dtv/lib/dvbt2/dvbt2_pilotgenerator_cc_impl.cc +++ b/gr-dtv/lib/dvbt2/dvbt2_pilotgenerator_cc_impl.cc @@ -30,7 +30,7 @@ namespace gr { namespace dtv { dvbt2_pilotgenerator_cc::sptr - dvbt2_pilotgenerator_cc::make(dvbt2_extended_carrier_t carriermode, dvbt2_fftsize_t fftsize, dvbt2_pilotpattern_t pilotpattern, dvbt2_guardinterval_t guardinterval, int numdatasyms, dvbt2_papr_t paprmode, dvbt2_version_t version, dvbt2_preamble_t preamble, dvbt2_misogroup_t misogroup, dvbt2_equalization_t equalization, dvbt2_bandwidth_t bandwidth, int vlength) + dvbt2_pilotgenerator_cc::make(dvbt2_extended_carrier_t carriermode, dvbt2_fftsize_t fftsize, dvbt2_pilotpattern_t pilotpattern, dvb_guardinterval_t guardinterval, int numdatasyms, dvbt2_papr_t paprmode, dvbt2_version_t version, dvbt2_preamble_t preamble, dvbt2_misogroup_t misogroup, dvbt2_equalization_t equalization, dvbt2_bandwidth_t bandwidth, int vlength) { return gnuradio::get_initial_sptr (new dvbt2_pilotgenerator_cc_impl(carriermode, fftsize, pilotpattern, guardinterval, numdatasyms, paprmode, version, preamble, misogroup, equalization, bandwidth, vlength)); @@ -39,7 +39,7 @@ namespace gr { /* * The private constructor */ - dvbt2_pilotgenerator_cc_impl::dvbt2_pilotgenerator_cc_impl(dvbt2_extended_carrier_t carriermode, dvbt2_fftsize_t fftsize, dvbt2_pilotpattern_t pilotpattern, dvbt2_guardinterval_t guardinterval, int numdatasyms, dvbt2_papr_t paprmode, dvbt2_version_t version, dvbt2_preamble_t preamble, dvbt2_misogroup_t misogroup, dvbt2_equalization_t equalization, dvbt2_bandwidth_t bandwidth, int vlength) + dvbt2_pilotgenerator_cc_impl::dvbt2_pilotgenerator_cc_impl(dvbt2_extended_carrier_t carriermode, dvbt2_fftsize_t fftsize, dvbt2_pilotpattern_t pilotpattern, dvb_guardinterval_t guardinterval, int numdatasyms, dvbt2_papr_t paprmode, dvbt2_version_t version, dvbt2_preamble_t preamble, dvbt2_misogroup_t misogroup, dvbt2_equalization_t equalization, dvbt2_bandwidth_t bandwidth, int vlength) : gr::block("dvbt2_pilotgenerator_cc", gr::io_signature::make(1, 1, sizeof(gr_complex)), gr::io_signature::make(1, 1, sizeof(gr_complex) * vlength)) diff --git a/gr-dtv/lib/dvbt2/dvbt2_pilotgenerator_cc_impl.h b/gr-dtv/lib/dvbt2/dvbt2_pilotgenerator_cc_impl.h index e4198721f3..f99d8a603f 100644 --- a/gr-dtv/lib/dvbt2/dvbt2_pilotgenerator_cc_impl.h +++ b/gr-dtv/lib/dvbt2/dvbt2_pilotgenerator_cc_impl.h @@ -155,7 +155,7 @@ namespace gr { const static int pp8_32k[6]; public: - dvbt2_pilotgenerator_cc_impl(dvbt2_extended_carrier_t carriermode, dvbt2_fftsize_t fftsize, dvbt2_pilotpattern_t pilotpattern, dvbt2_guardinterval_t guardinterval, int numdatasyms, dvbt2_papr_t paprmode, dvbt2_version_t version, dvbt2_preamble_t preamble, dvbt2_misogroup_t misogroup, dvbt2_equalization_t equalization, dvbt2_bandwidth_t bandwidth, int vlength); + dvbt2_pilotgenerator_cc_impl(dvbt2_extended_carrier_t carriermode, dvbt2_fftsize_t fftsize, dvbt2_pilotpattern_t pilotpattern, dvb_guardinterval_t guardinterval, int numdatasyms, dvbt2_papr_t paprmode, dvbt2_version_t version, dvbt2_preamble_t preamble, dvbt2_misogroup_t misogroup, dvbt2_equalization_t equalization, dvbt2_bandwidth_t bandwidth, int vlength); ~dvbt2_pilotgenerator_cc_impl(); void forecast (int noutput_items, gr_vector_int &ninput_items_required); diff --git a/gr-dtv/swig/dtv_swig.i b/gr-dtv/swig/dtv_swig.i index 42a7b0de09..094e8f0faf 100644 --- a/gr-dtv/swig/dtv_swig.i +++ b/gr-dtv/swig/dtv_swig.i @@ -44,6 +44,7 @@ #include "gnuradio/dtv/atsc_trellis_encoder.h" #include "gnuradio/dtv/atsc_viterbi_decoder.h" #include "gnuradio/dtv/dvb_config.h" +#include "gnuradio/dtv/dvbt_config.h" #include "gnuradio/dtv/dvbt2_config.h" #include "gnuradio/dtv/dvbs2_config.h" #include "gnuradio/dtv/dvb_bbheader_bb.h" @@ -62,6 +63,14 @@ #include "gnuradio/dtv/dvbs2_interleaver_bb.h" #include "gnuradio/dtv/dvbs2_modulator_bc.h" #include "gnuradio/dtv/dvbs2_physical_cc.h" +#include "gnuradio/dtv/dvbt_energy_dispersal.h" +#include "gnuradio/dtv/dvbt_reed_solomon_enc.h" +#include "gnuradio/dtv/dvbt_convolutional_interleaver.h" +#include "gnuradio/dtv/dvbt_inner_coder.h" +#include "gnuradio/dtv/dvbt_bit_inner_interleaver.h" +#include "gnuradio/dtv/dvbt_symbol_inner_interleaver.h" +#include "gnuradio/dtv/dvbt_map.h" +#include "gnuradio/dtv/dvbt_reference_signals.h" %} %include "gnuradio/dtv/atsc_deinterleaver.h" @@ -80,6 +89,7 @@ %include "gnuradio/dtv/atsc_trellis_encoder.h" %include "gnuradio/dtv/atsc_viterbi_decoder.h" %include "gnuradio/dtv/dvb_config.h" +%include "gnuradio/dtv/dvbt_config.h" %include "gnuradio/dtv/dvbt2_config.h" %include "gnuradio/dtv/dvbs2_config.h" %include "gnuradio/dtv/dvb_bbheader_bb.h" @@ -98,6 +108,14 @@ %include "gnuradio/dtv/dvbs2_interleaver_bb.h" %include "gnuradio/dtv/dvbs2_modulator_bc.h" %include "gnuradio/dtv/dvbs2_physical_cc.h" +%include "gnuradio/dtv/dvbt_energy_dispersal.h" +%include "gnuradio/dtv/dvbt_reed_solomon_enc.h" +%include "gnuradio/dtv/dvbt_convolutional_interleaver.h" +%include "gnuradio/dtv/dvbt_inner_coder.h" +%include "gnuradio/dtv/dvbt_bit_inner_interleaver.h" +%include "gnuradio/dtv/dvbt_symbol_inner_interleaver.h" +%include "gnuradio/dtv/dvbt_map.h" +%include "gnuradio/dtv/dvbt_reference_signals.h" GR_SWIG_BLOCK_MAGIC2(dtv, atsc_deinterleaver); GR_SWIG_BLOCK_MAGIC2(dtv, atsc_depad); @@ -130,3 +148,11 @@ GR_SWIG_BLOCK_MAGIC2(dtv, dvbt2_miso_cc); GR_SWIG_BLOCK_MAGIC2(dtv, dvbs2_interleaver_bb); GR_SWIG_BLOCK_MAGIC2(dtv, dvbs2_modulator_bc); GR_SWIG_BLOCK_MAGIC2(dtv, dvbs2_physical_cc); +GR_SWIG_BLOCK_MAGIC2(dtv, dvbt_energy_dispersal); +GR_SWIG_BLOCK_MAGIC2(dtv, dvbt_reed_solomon_enc); +GR_SWIG_BLOCK_MAGIC2(dtv, dvbt_convolutional_interleaver); +GR_SWIG_BLOCK_MAGIC2(dtv, dvbt_inner_coder); +GR_SWIG_BLOCK_MAGIC2(dtv, dvbt_bit_inner_interleaver); +GR_SWIG_BLOCK_MAGIC2(dtv, dvbt_symbol_inner_interleaver); +GR_SWIG_BLOCK_MAGIC2(dtv, dvbt_map); +GR_SWIG_BLOCK_MAGIC2(dtv, dvbt_reference_signals); diff --git a/gr-fcd/grc/fcd_source_c.xml b/gr-fcd/grc/fcd_source_c.xml index b514c6126c..01ea26d81c 100644 --- a/gr-fcd/grc/fcd_source_c.xml +++ b/gr-fcd/grc/fcd_source_c.xml @@ -3,7 +3,7 @@ <name>Funcube Dongle Source</name> <key>fcd_source_c</key> <category>FCD</category> - <throttle>1</throttle> + <flags>throttle</flags> <import>from gnuradio import fcd</import> <make>fcd.source_c($device_name) #if $lna() != 20.0 diff --git a/gr-fec/lib/gf2mat.cc b/gr-fec/lib/gf2mat.cc index 87cb300890..accc2859f2 100644 --- a/gr-fec/lib/gf2mat.cc +++ b/gr-fec/lib/gf2mat.cc @@ -109,13 +109,13 @@ GF2Vec GF2Mat::get_col(int i) { void GF2Mat::add_cols(int i, int j) { for ( int row = 0; row < M; row++ ) { - H[row][i] = H[row][i] xor H[row][j]; + H[row][i] = H[row][i] ^ H[row][j]; } } void GF2Mat::add_rows(int i, int j) { for ( int col = 0; col < N; col++ ) { - H[i][col] = H[i][col] xor H[j][col]; + H[i][col] = H[i][col] ^ H[j][col]; } } diff --git a/gr-filter/examples/CMakeLists.txt b/gr-filter/examples/CMakeLists.txt index 48b59ef099..a6229f38f4 100644 --- a/gr-filter/examples/CMakeLists.txt +++ b/gr-filter/examples/CMakeLists.txt @@ -42,6 +42,7 @@ GR_PYTHON_INSTALL(PROGRAMS install( FILES + filter_taps.grc resampler_demo.grc DESTINATION ${GR_PKG_FILTER_EXAMPLES_DIR} COMPONENT "filter_python" diff --git a/gr-filter/examples/filter_taps.grc b/gr-filter/examples/filter_taps.grc new file mode 100644 index 0000000000..48d37b228a --- /dev/null +++ b/gr-filter/examples/filter_taps.grc @@ -0,0 +1,1299 @@ +<?xml version='1.0' encoding='ASCII'?> +<?grc format='1' created='3.7.7'?> +<flow_graph> + <timestamp>Wed Apr 8 11:00:48 2015</timestamp> + <block> + <key>options</key> + <param> + <key>id</key> + <value>filter_taps</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>title</key> + <value></value> + </param> + <param> + <key>author</key> + <value></value> + </param> + <param> + <key>description</key> + <value></value> + </param> + <param> + <key>window_size</key> + <value>1280, 1024</value> + </param> + <param> + <key>generate_options</key> + <value>qt_gui</value> + </param> + <param> + <key>category</key> + <value>Custom</value> + </param> + <param> + <key>run_options</key> + <value>prompt</value> + </param> + <param> + <key>run</key> + <value>True</value> + </param> + <param> + <key>max_nouts</key> + <value>0</value> + </param> + <param> + <key>realtime_scheduling</key> + <value></value> + </param> + <param> + <key>thread_safe_setters</key> + <value></value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(10, 10)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>sym_rate</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>samp_rate/sps</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(1080, 171)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>sps</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>2</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(1016, 171)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>bp_low</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>6000</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(120, 139)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>cutoff_high</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>14000</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(8, 211)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>samp_rate</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>32000</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(8, 83)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>transition</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>1000</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(8, 283)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>cutoff_low</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>2000</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(8, 147)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>bp_high</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>10000</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(120, 211)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>len_taps</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>len(lp_taps)</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(288, 35)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable_band_pass_filter_taps</key> + <param> + <key>id</key> + <value>bp_taps</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>taps_real</value> + </param> + <param> + <key>gain</key> + <value>1.0</value> + </param> + <param> + <key>samp_rate</key> + <value>samp_rate</value> + </param> + <param> + <key>low_cutoff_freq</key> + <value>bp_low</value> + </param> + <param> + <key>high_cutoff_freq</key> + <value>bp_high</value> + </param> + <param> + <key>width</key> + <value>transition</value> + </param> + <param> + <key>win</key> + <value>firdes.WIN_HAMMING</value> + </param> + <param> + <key>beta</key> + <value>6.76</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(696, 35)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable_high_pass_filter_taps</key> + <param> + <key>id</key> + <value>hp_taps</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>gain</key> + <value>1.0</value> + </param> + <param> + <key>samp_rate</key> + <value>samp_rate</value> + </param> + <param> + <key>cutoff_freq</key> + <value>cutoff_low</value> + </param> + <param> + <key>width</key> + <value>transition</value> + </param> + <param> + <key>win</key> + <value>firdes.WIN_HAMMING</value> + </param> + <param> + <key>beta</key> + <value>6.76</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(536, 35)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable_low_pass_filter_taps</key> + <param> + <key>id</key> + <value>lp_taps</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>gain</key> + <value>1.0</value> + </param> + <param> + <key>samp_rate</key> + <value>samp_rate</value> + </param> + <param> + <key>cutoff_freq</key> + <value>cutoff_high</value> + </param> + <param> + <key>width</key> + <value>transition</value> + </param> + <param> + <key>win</key> + <value>firdes.WIN_HAMMING</value> + </param> + <param> + <key>beta</key> + <value>6.76</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(376, 35)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable_band_reject_filter_taps</key> + <param> + <key>id</key> + <value>br_taps</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>gain</key> + <value>1.0</value> + </param> + <param> + <key>samp_rate</key> + <value>samp_rate</value> + </param> + <param> + <key>low_cutoff_freq</key> + <value>bp_low</value> + </param> + <param> + <key>high_cutoff_freq</key> + <value>bp_high</value> + </param> + <param> + <key>width</key> + <value>transition</value> + </param> + <param> + <key>win</key> + <value>firdes.WIN_HAMMING</value> + </param> + <param> + <key>beta</key> + <value>6.76</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(856, 35)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>fir_filter_xxx</key> + <param> + <key>id</key> + <value>lp_filter</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>fff</value> + </param> + <param> + <key>decim</key> + <value>1</value> + </param> + <param> + <key>taps</key> + <value>lp_taps</value> + </param> + <param> + <key>samp_delay</key> + <value>0</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value>Low-pass filter</value> + </param> + <param> + <key>_coordinate</key> + <value>(392, 203)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>fir_filter_xxx</key> + <param> + <key>id</key> + <value>hp_filter</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>fff</value> + </param> + <param> + <key>decim</key> + <value>1</value> + </param> + <param> + <key>taps</key> + <value>hp_taps</value> + </param> + <param> + <key>samp_delay</key> + <value>0</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value>High-pass filter</value> + </param> + <param> + <key>_coordinate</key> + <value>(392, 307)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>fir_filter_xxx</key> + <param> + <key>id</key> + <value>bp_filter</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>fff</value> + </param> + <param> + <key>decim</key> + <value>1</value> + </param> + <param> + <key>taps</key> + <value>bp_taps</value> + </param> + <param> + <key>samp_delay</key> + <value>0</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value>Band-pass filter</value> + </param> + <param> + <key>_coordinate</key> + <value>(392, 403)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>fir_filter_xxx</key> + <param> + <key>id</key> + <value>br_filter</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>fff</value> + </param> + <param> + <key>decim</key> + <value>1</value> + </param> + <param> + <key>taps</key> + <value>br_taps</value> + </param> + <param> + <key>samp_delay</key> + <value>0</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value>Band-reject filter</value> + </param> + <param> + <key>_coordinate</key> + <value>(392, 499)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable_rrc_filter_taps</key> + <param> + <key>id</key> + <value>rrc_taps</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>gain</key> + <value>1.0</value> + </param> + <param> + <key>samp_rate</key> + <value>samp_rate</value> + </param> + <param> + <key>sym_rate</key> + <value>sym_rate</value> + </param> + <param> + <key>alpha</key> + <value>0.35</value> + </param> + <param> + <key>ntaps</key> + <value>11*sps</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(1016, 35)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>analog_fastnoise_source_x</key> + <param> + <key>id</key> + <value>analog_fastnoise_source_x_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>float</value> + </param> + <param> + <key>noise_type</key> + <value>analog.GR_GAUSSIAN</value> + </param> + <param> + <key>amp</key> + <value>1</value> + </param> + <param> + <key>seed</key> + <value>0</value> + </param> + <param> + <key>samples</key> + <value>8192</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(176, 387)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>fir_filter_xxx</key> + <param> + <key>id</key> + <value>rrc_filter</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>fff</value> + </param> + <param> + <key>decim</key> + <value>1</value> + </param> + <param> + <key>taps</key> + <value>rrc_taps</value> + </param> + <param> + <key>samp_delay</key> + <value>0</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value>RRC filter</value> + </param> + <param> + <key>_coordinate</key> + <value>(392, 587)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>qtgui_freq_sink_x</key> + <param> + <key>id</key> + <value>qtgui_freq_sink_x_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>float</value> + </param> + <param> + <key>name</key> + <value>""</value> + </param> + <param> + <key>fftsize</key> + <value>4096</value> + </param> + <param> + <key>freqhalf</key> + <value>False</value> + </param> + <param> + <key>wintype</key> + <value>firdes.WIN_BLACKMAN_hARRIS</value> + </param> + <param> + <key>fc</key> + <value>0</value> + </param> + <param> + <key>bw</key> + <value>samp_rate</value> + </param> + <param> + <key>grid</key> + <value>True</value> + </param> + <param> + <key>autoscale</key> + <value>False</value> + </param> + <param> + <key>average</key> + <value>0.2</value> + </param> + <param> + <key>ymin</key> + <value>-140</value> + </param> + <param> + <key>ymax</key> + <value>10</value> + </param> + <param> + <key>nconnections</key> + <value>5</value> + </param> + <param> + <key>update_time</key> + <value>0.10</value> + </param> + <param> + <key>gui_hint</key> + <value></value> + </param> + <param> + <key>showports</key> + <value>True</value> + </param> + <param> + <key>tr_mode</key> + <value>qtgui.TRIG_MODE_FREE</value> + </param> + <param> + <key>tr_level</key> + <value>0.0</value> + </param> + <param> + <key>tr_chan</key> + <value>0</value> + </param> + <param> + <key>tr_tag</key> + <value>""</value> + </param> + <param> + <key>ctrlpanel</key> + <value>True</value> + </param> + <param> + <key>legend</key> + <value>True</value> + </param> + <param> + <key>label1</key> + <value>Low-pass</value> + </param> + <param> + <key>width1</key> + <value>1</value> + </param> + <param> + <key>color1</key> + <value>"blue"</value> + </param> + <param> + <key>alpha1</key> + <value>0.9</value> + </param> + <param> + <key>label2</key> + <value>High-pass</value> + </param> + <param> + <key>width2</key> + <value>1</value> + </param> + <param> + <key>color2</key> + <value>"red"</value> + </param> + <param> + <key>alpha2</key> + <value>0.9</value> + </param> + <param> + <key>label3</key> + <value>Band-pass</value> + </param> + <param> + <key>width3</key> + <value>1</value> + </param> + <param> + <key>color3</key> + <value>"green"</value> + </param> + <param> + <key>alpha3</key> + <value>0.9</value> + </param> + <param> + <key>label4</key> + <value>Band-reject</value> + </param> + <param> + <key>width4</key> + <value>1</value> + </param> + <param> + <key>color4</key> + <value>"cyan"</value> + </param> + <param> + <key>alpha4</key> + <value>0.9</value> + </param> + <param> + <key>label5</key> + <value>RRC</value> + </param> + <param> + <key>width5</key> + <value>1</value> + </param> + <param> + <key>color5</key> + <value>"magenta"</value> + </param> + <param> + <key>alpha5</key> + <value>0.9</value> + </param> + <param> + <key>label6</key> + <value></value> + </param> + <param> + <key>width6</key> + <value>1</value> + </param> + <param> + <key>color6</key> + <value>"magenta"</value> + </param> + <param> + <key>alpha6</key> + <value>1.0</value> + </param> + <param> + <key>label7</key> + <value></value> + </param> + <param> + <key>width7</key> + <value>1</value> + </param> + <param> + <key>color7</key> + <value>"yellow"</value> + </param> + <param> + <key>alpha7</key> + <value>1.0</value> + </param> + <param> + <key>label8</key> + <value></value> + </param> + <param> + <key>width8</key> + <value>1</value> + </param> + <param> + <key>color8</key> + <value>"dark red"</value> + </param> + <param> + <key>alpha8</key> + <value>1.0</value> + </param> + <param> + <key>label9</key> + <value></value> + </param> + <param> + <key>width9</key> + <value>1</value> + </param> + <param> + <key>color9</key> + <value>"dark green"</value> + </param> + <param> + <key>alpha9</key> + <value>1.0</value> + </param> + <param> + <key>label10</key> + <value></value> + </param> + <param> + <key>width10</key> + <value>1</value> + </param> + <param> + <key>color10</key> + <value>"dark blue"</value> + </param> + <param> + <key>alpha10</key> + <value>1.0</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(728, 416)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <connection> + <source_block_id>bp_filter</source_block_id> + <sink_block_id>qtgui_freq_sink_x_0</sink_block_id> + <source_key>0</source_key> + <sink_key>2</sink_key> + </connection> + <connection> + <source_block_id>analog_fastnoise_source_x_0</source_block_id> + <sink_block_id>bp_filter</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>hp_filter</source_block_id> + <sink_block_id>qtgui_freq_sink_x_0</sink_block_id> + <source_key>0</source_key> + <sink_key>1</sink_key> + </connection> + <connection> + <source_block_id>analog_fastnoise_source_x_0</source_block_id> + <sink_block_id>hp_filter</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>lp_filter</source_block_id> + <sink_block_id>qtgui_freq_sink_x_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>analog_fastnoise_source_x_0</source_block_id> + <sink_block_id>lp_filter</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>analog_fastnoise_source_x_0</source_block_id> + <sink_block_id>br_filter</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>br_filter</source_block_id> + <sink_block_id>qtgui_freq_sink_x_0</sink_block_id> + <source_key>0</source_key> + <sink_key>3</sink_key> + </connection> + <connection> + <source_block_id>rrc_filter</source_block_id> + <sink_block_id>qtgui_freq_sink_x_0</sink_block_id> + <source_key>0</source_key> + <sink_key>4</sink_key> + </connection> + <connection> + <source_block_id>analog_fastnoise_source_x_0</source_block_id> + <sink_block_id>rrc_filter</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> +</flow_graph> diff --git a/gr-filter/grc/CMakeLists.txt b/gr-filter/grc/CMakeLists.txt index 575f6675d6..b3bc2e1828 100644 --- a/gr-filter/grc/CMakeLists.txt +++ b/gr-filter/grc/CMakeLists.txt @@ -45,6 +45,11 @@ install(FILES filter_band_pass_filter.xml filter_band_reject_filter.xml filter_root_raised_cosine_filter.xml + variable_low_pass_filter_taps.xml + variable_high_pass_filter_taps.xml + variable_band_pass_filter_taps.xml + variable_band_reject_filter_taps.xml + variable_rrc_filter_taps.xml DESTINATION ${GRC_BLOCKS_DIR} COMPONENT "filter_python" ) diff --git a/gr-filter/grc/filter_block_tree.xml b/gr-filter/grc/filter_block_tree.xml index fbba9daf09..ea869a75bd 100644 --- a/gr-filter/grc/filter_block_tree.xml +++ b/gr-filter/grc/filter_block_tree.xml @@ -1,7 +1,7 @@ <?xml version="1.0"?> <!-- - Copyright 2012 Free Software Foundation, Inc. + Copyright 2012,2015 Free Software Foundation, Inc. This file is part of GNU Radio @@ -30,6 +30,12 @@ <name></name> <!-- Blank for Root Name --> <cat> <name>Filters</name> + <!-- FIR filter tap generators --> + <block>variable_low_pass_filter_taps</block> + <block>variable_high_pass_filter_taps</block> + <block>variable_band_pass_filter_taps</block> + <block>variable_band_reject_filter_taps</block> + <block>variable_rrc_filter_taps</block> <!-- FIR convenience filters --> <block>low_pass_filter</block> <block>high_pass_filter</block> diff --git a/gr-filter/grc/variable_band_pass_filter_taps.xml b/gr-filter/grc/variable_band_pass_filter_taps.xml new file mode 100644 index 0000000000..6cdfcc0373 --- /dev/null +++ b/gr-filter/grc/variable_band_pass_filter_taps.xml @@ -0,0 +1,97 @@ +<?xml version="1.0"?> +<!-- +####################################################### +# Convenience wrapper for calling firdes.band_pass(...) +# or firdes.complex_bandpass(...) +####################################################### + --> +<block> + <name>Band-pass Filter Taps</name> + <key>variable_band_pass_filter_taps</key> + <import>from gnuradio.filter import firdes</import> + <var_make> +self.$(id) = $(id) = firdes.$(type.fcn)($gain, $samp_rate, $low_cutoff_freq, $high_cutoff_freq, $width, $win, $beta) + </var_make> + <var_value>firdes.$(type.fcn)($gain, $samp_rate, $low_cutoff_freq, $high_cutoff_freq, $width, $win, $beta)</var_value> + <make></make> + + <param> + <name>Tap Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Real</name> + <key>taps_real</key> + <opt>fcn:band_pass</opt> + </option> + <option> + <name>Complex</name> + <key>taps_complex</key> + <opt>fcn:complex_band_pass</opt> + </option> + </param> + <param> + <name>Gain</name> + <key>gain</key> + <value>1.0</value> + <type>float</type> + </param> + <param> + <name>Sample Rate (Hz)</name> + <key>samp_rate</key> + <value>samp_rate</value> + <type>float</type> + </param> + <param> + <name>Low Cutoff Freq (Hz)</name> + <key>low_cutoff_freq</key> + <type>float</type> + </param> + <param> + <name>High Cutoff Freq (Hz)</name> + <key>high_cutoff_freq</key> + <type>float</type> + </param> + <param> + <name>Transition Width (Hz)</name> + <key>width</key> + <type>float</type> + </param> + <param> + <name>Window</name> + <key>win</key> + <value>firdes.WIN_HAMMING</value> + <type>int</type> + <option> + <name>Hamming</name> + <key>firdes.WIN_HAMMING</key> + </option> + <option> + <name>Hann</name> + <key>firdes.WIN_HANN</key> + </option> + <option> + <name>Blackman</name> + <key>firdes.WIN_BLACKMAN</key> + </option> + <option> + <name>Rectangular</name> + <key>firdes.WIN_RECTANGULAR</key> + </option> + <option> + <name>Kaiser</name> + <key>firdes.WIN_KAISER</key> + </option> + </param> + <param> + <name>Beta</name> + <key>beta</key> + <value>6.76</value> + <type>float</type> + </param> + <doc> + This is a convenience wrapper for calling firdes.band_pass() or firdes.complex_band_pass() + + The beta paramater only applies to the Kaiser window. + </doc> +</block> diff --git a/gr-filter/grc/variable_band_reject_filter_taps.xml b/gr-filter/grc/variable_band_reject_filter_taps.xml new file mode 100644 index 0000000000..fbf25886d3 --- /dev/null +++ b/gr-filter/grc/variable_band_reject_filter_taps.xml @@ -0,0 +1,81 @@ +<?xml version="1.0"?> +<!-- +######################################################### +# Convenience wrapper for calling firdes.band_reject(...) +######################################################### + --> +<block> + <name>Band-reject Filter Taps</name> + <key>variable_band_reject_filter_taps</key> + <import>from gnuradio.filter import firdes</import> + <var_make> +self.$(id) = $(id) = firdes.band_reject($gain, $samp_rate, $low_cutoff_freq, $high_cutoff_freq, $width, $win, $beta) + </var_make> + <var_value>firdes.band_reject($gain, $samp_rate, $low_cutoff_freq, $high_cutoff_freq, $width, $win, $beta)</var_value> + <make></make> + + <param> + <name>Gain</name> + <key>gain</key> + <value>1.0</value> + <type>float</type> + </param> + <param> + <name>Sample Rate (Hz)</name> + <key>samp_rate</key> + <value>samp_rate</value> + <type>float</type> + </param> + <param> + <name>Low Cutoff Freq (Hz)</name> + <key>low_cutoff_freq</key> + <type>float</type> + </param> + <param> + <name>High Cutoff Freq (Hz)</name> + <key>high_cutoff_freq</key> + <type>float</type> + </param> + <param> + <name>Transition Width (Hz)</name> + <key>width</key> + <type>float</type> + </param> + <param> + <name>Window</name> + <key>win</key> + <value>firdes.WIN_HAMMING</value> + <type>int</type> + <option> + <name>Hamming</name> + <key>firdes.WIN_HAMMING</key> + </option> + <option> + <name>Hann</name> + <key>firdes.WIN_HANN</key> + </option> + <option> + <name>Blackman</name> + <key>firdes.WIN_BLACKMAN</key> + </option> + <option> + <name>Rectangular</name> + <key>firdes.WIN_RECTANGULAR</key> + </option> + <option> + <name>Kaiser</name> + <key>firdes.WIN_KAISER</key> + </option> + </param> + <param> + <name>Beta</name> + <key>beta</key> + <value>6.76</value> + <type>float</type> + </param> + <doc> + This is a convenience wrapper for calling firdes.band_reject(). + + The beta paramater only applies to the Kaiser window. + </doc> +</block> diff --git a/gr-filter/grc/variable_high_pass_filter_taps.xml b/gr-filter/grc/variable_high_pass_filter_taps.xml new file mode 100644 index 0000000000..08768d808a --- /dev/null +++ b/gr-filter/grc/variable_high_pass_filter_taps.xml @@ -0,0 +1,75 @@ +<?xml version="1.0"?> +<!-- +###################################################### +## Convenience wrapper around call to fides.high_pass() +###################################################### + --> +<block> + <name>High-pass Filter Taps</name> + <key>variable_high_pass_filter_taps</key> + <import>from gnuradio.filter import firdes</import> + <var_make> +self.$(id) = $(id) = firdes.high_pass($gain, $samp_rate, $cutoff_freq, $width, $win, $beta) + </var_make> + <var_value>firdes.high_pass($gain, $samp_rate, $cutoff_freq, $width, $win, $beta)</var_value> + <make></make> + <param> + <name>Gain</name> + <key>gain</key> + <value>1.0</value> + <type>float</type> + </param> + <param> + <name>Sample Rate (Hz)</name> + <key>samp_rate</key> + <value>samp_rate</value> + <type>float</type> + </param> + <param> + <name>Cutoff Freq (Hz)</name> + <key>cutoff_freq</key> + <type>float</type> + </param> + <param> + <name>Transition Width (Hz)</name> + <key>width</key> + <type>float</type> + </param> + <param> + <name>Window</name> + <key>win</key> + <value>firdes.WIN_HAMMING</value> + <type>int</type> + <option> + <name>Hamming</name> + <key>firdes.WIN_HAMMING</key> + </option> + <option> + <name>Hann</name> + <key>firdes.WIN_HANN</key> + </option> + <option> + <name>Blackman</name> + <key>firdes.WIN_BLACKMAN</key> + </option> + <option> + <name>Rectangular</name> + <key>firdes.WIN_RECTANGULAR</key> + </option> + <option> + <name>Kaiser</name> + <key>firdes.WIN_KAISER</key> + </option> + </param> + <param> + <name>Beta</name> + <key>beta</key> + <value>6.76</value> + <type>float</type> + </param> + <doc> + This variable is a convenience wrapper around a call to firdes.high_pass(...). + + The beta paramater only applies to the Kaiser window. + </doc> +</block> diff --git a/gr-filter/grc/variable_low_pass_filter_taps.xml b/gr-filter/grc/variable_low_pass_filter_taps.xml new file mode 100644 index 0000000000..e3367b1ec5 --- /dev/null +++ b/gr-filter/grc/variable_low_pass_filter_taps.xml @@ -0,0 +1,75 @@ +<?xml version="1.0"?> +<!-- +###################################################### +## Convenience wrapper around call to fides.low_pass() +###################################################### + --> +<block> + <name>Low-pass Filter Taps</name> + <key>variable_low_pass_filter_taps</key> + <import>from gnuradio.filter import firdes</import> + <var_make> +self.$(id) = $(id) = firdes.low_pass($gain, $samp_rate, $cutoff_freq, $width, $win, $beta) + </var_make> + <var_value>firdes.low_pass($gain, $samp_rate, $cutoff_freq, $width, $win, $beta)</var_value> + <make></make> + <param> + <name>Gain</name> + <key>gain</key> + <value>1.0</value> + <type>float</type> + </param> + <param> + <name>Sample Rate (Hz)</name> + <key>samp_rate</key> + <value>samp_rate</value> + <type>float</type> + </param> + <param> + <name>Cutoff Freq (Hz)</name> + <key>cutoff_freq</key> + <type>float</type> + </param> + <param> + <name>Transition Width (Hz)</name> + <key>width</key> + <type>float</type> + </param> + <param> + <name>Window</name> + <key>win</key> + <value>firdes.WIN_HAMMING</value> + <type>int</type> + <option> + <name>Hamming</name> + <key>firdes.WIN_HAMMING</key> + </option> + <option> + <name>Hann</name> + <key>firdes.WIN_HANN</key> + </option> + <option> + <name>Blackman</name> + <key>firdes.WIN_BLACKMAN</key> + </option> + <option> + <name>Rectangular</name> + <key>firdes.WIN_RECTANGULAR</key> + </option> + <option> + <name>Kaiser</name> + <key>firdes.WIN_KAISER</key> + </option> + </param> + <param> + <name>Beta</name> + <key>beta</key> + <value>6.76</value> + <type>float</type> + </param> + <doc> + This variable is a convenience wrapper around a call to firdes.low_pass(...). + + The beta paramater only applies to the Kaiser window. + </doc> +</block> diff --git a/gr-filter/grc/variable_rrc_filter_taps.xml b/gr-filter/grc/variable_rrc_filter_taps.xml new file mode 100644 index 0000000000..2824ba75b2 --- /dev/null +++ b/gr-filter/grc/variable_rrc_filter_taps.xml @@ -0,0 +1,50 @@ +<?xml version="1.0"?> +<!-- +######################################################################## +## Convenience wrapper for calling firdes.root_raised_cosine_filter(...) +######################################################################## + --> +<block> + <name>RRC Filter Taps</name> + <key>variable_rrc_filter_taps</key> + <import>from gnuradio.filter import firdes</import> + <var_make> +self.$(id) = $(id) = firdes.root_raised_cosine($gain, $samp_rate, $sym_rate, $alpha, $ntaps) + </var_make> + <var_value>firdes.root_raised_cosine($gain, $samp_rate, $sym_rate, $alpha, $ntaps)</var_value> + <make></make> + + <param> + <name>Gain</name> + <key>gain</key> + <value>1.0</value> + <type>float</type> + </param> + <param> + <name>Sample Rate (Hz)</name> + <key>samp_rate</key> + <value>samp_rate</value> + <type>float</type> + </param> + <param> + <name>Symbol Rate (Hz)</name> + <key>sym_rate</key> + <value></value> + <type>float</type> + </param> + <param> + <name>Excess BW</name> + <key>alpha</key> + <value>0.35</value> + <type>float</type> + </param> + <param> + <name>Num Taps</name> + <key>ntaps</key> + <value>11*sps</value> + <type>int</type> + </param> + <doc> + This is a convenience wrapper for calling firdes.root_raised_cosine(...). + </doc> +</block> diff --git a/gr-qtgui/grc/qtgui_range.xml b/gr-qtgui/grc/qtgui_range.xml index 05f3ffce9f..71b614cc5e 100644 --- a/gr-qtgui/grc/qtgui_range.xml +++ b/gr-qtgui/grc/qtgui_range.xml @@ -6,105 +6,126 @@ ################################################### --> <block> - <name>QT GUI Range</name> - <key>variable_qtgui_range</key> - <import>from gnuradio.qtgui import Range, RangeWidget</import> - <var_make>self.$(id) = $(id) = $value</var_make> - <make>#set $win = 'self._%s_win'%$id + <name>QT GUI Range</name> + <key>variable_qtgui_range</key> + <import>from gnuradio.qtgui import Range, RangeWidget</import> + <var_make>self.$(id) = $(id) = $value</var_make> + <make>#set $win = 'self._%s_win'%$id #set $range = 'self._%s_range'%$id #if not $label() #set $label = '"%s"'%$id #end if $(range) = Range($start, $stop, $step, $value, $min_len) -$(win) = RangeWidget($range, self.set_$(id), $label, "$widget") +$(win) = RangeWidget($range, self.set_$(id), $label, "$widget", $rangeType) $(gui_hint()($win))</make> - <callback>self.set_$(id)($value)</callback> - <param> - <name>Label</name> - <key>label</key> - <value></value> - <type>string</type> - <hide>#if $label() then 'none' else 'part'#</hide> - </param> - <param> - <name>Default Value</name> - <key>value</key> - <value>50</value> - <type>real</type> - </param> - <param> - <name>Start</name> - <key>start</key> - <value>0</value> - <type>real</type> - </param> - <param> - <name>Stop</name> - <key>stop</key> - <value>100</value> - <type>real</type> - </param> - <param> - <name>Step</name> - <key>step</key> - <value>1</value> - <type>real</type> - </param> - <param> - <name>Widget</name> - <key>widget</key> - <value>counter_slider</value> - <type>enum</type> - <hide>part</hide> - <option><name>Counter + Slider</name><key>counter_slider</key></option> - <option><name>Counter</name><key>counter</key></option> - <option><name>Slider</name><key>slider</key></option> - <option><name>Knob</name><key>dial</key></option> - </param> - <param> - <name>Orientation</name> - <key>orient</key> - <value>Qt.Horizontal</value> - <type>enum</type> - <hide>#if $widget() == "slider" then 'part' else 'all'#</hide> - <option> - <name>Horizontal</name> - <key>Qt.Horizontal</key> - <opt>scalepos:BottomScale</opt> - <opt>minfcn:setMinimumWidth</opt> - </option> - <option> - <name>Vertical</name> - <key>Qt.Vertical</key> - <opt>scalepos:LeftScale</opt> - <opt>minfcn:setMinimumHeight</opt> - </option> - </param> - <param> - <name>Minimum Length</name> - <key>min_len</key> - <value>200</value> - <type>int</type> - <hide>part</hide> - </param> -<!-- from min_len <hide>#if $widget().split('_')[0] in ("slider", "counter") then 'part' else 'all'#</hide>--> - <param> - <name>GUI Hint</name> - <key>gui_hint</key> - <value></value> - <type>gui_hint</type> - <hide>part</hide> - </param> - <check>$start <= $value <= $stop</check> - <check>$start < $stop</check> - <doc> -This block creates a variable with a slider. \ -Leave the label blank to use the variable id as the label. \ -The value must be a real number. \ -The value must be between the start and the stop. + <callback>self.set_$(id)($value)</callback> -The GUI hint can be used to position the widget within the application. \ -The hint is of the form [tab_id@tab_index]: [row, col, row_span, col_span]. \ -Both the tab specification and the grid position are optional. - </doc> + <param> + <name>Label</name> + <key>label</key> + <value></value> + <type>string</type> + <hide>#if $label() then 'none' else 'part'#</hide> + </param> + + <param> + <name>Type</name> + <key>rangeType</key> + <value>"float"</value> + <type>enum</type> + <hide>part</hide> + <option><name>Float</name><key>float</key><opt>type:float</opt></option> + <option><name>Int</name><key>int</key><opt>type:int</opt></option> + </param> + + <param> + <name>Default Value</name> + <key>value</key> + <value>50</value> + <type>$rangeType.type</type> + </param> + + <param> + <name>Start</name> + <key>start</key> + <value>0</value> + <type>$rangeType.type</type> + </param> + + <param> + <name>Stop</name> + <key>stop</key> + <value>100</value> + <type>$rangeType.type</type> + </param> + + <param> + <name>Step</name> + <key>step</key> + <value>1</value> + <type>$rangeType.type</type> + </param> + + <param> + <name>Widget</name> + <key>widget</key> + <value>counter_slider</value> + <type>enum</type> + <hide>part</hide> + <option><name>Counter + Slider</name><key>counter_slider</key></option> + <option><name>Counter</name><key>counter</key></option> + <option><name>Slider</name><key>slider</key></option> + <option><name>Knob</name><key>dial</key></option> + </param> + + <param> + <name>Orientation</name> + <key>orient</key> + <value>Qt.Horizontal</value> + <type>enum</type> + <hide>#if $widget() == "slider" then 'part' else 'all'#</hide> + <option> + <name>Horizontal</name> + <key>Qt.Horizontal</key> + <opt>scalepos:BottomScale</opt> + <opt>minfcn:setMinimumWidth</opt> + </option> + <option> + <name>Vertical</name> + <key>Qt.Vertical</key> + <opt>scalepos:LeftScale</opt> + <opt>minfcn:setMinimumHeight</opt> + </option> + </param> + + <param> + <name>Minimum Length</name> + <key>min_len</key> + <value>200</value> + <type>int</type> + <hide>part</hide> + </param> + <!-- from min_len <hide>#if $widget().split('_')[0] in ("slider", "counter") then 'part' else 'all'#</hide>--> + + <param> + <name>GUI Hint</name> + <key>gui_hint</key> + <value></value> + <type>gui_hint</type> + <hide>part</hide> + </param> + + <check>$start <= $value <= $stop</check> + <check>$start < $stop</check> + + <doc> + This block creates a variable with a slider. \ + Leave the label blank to use the variable id as the label. \ + The value must be a real number. \ + The value must be between the start and the stop. + + The GUI hint can be used to position the widget within the application. \ + The hint is of the form [tab_id@tab_index]: [row, col, row_span, col_span]. \ + Both the tab specification and the grid position are optional. + </doc> </block> diff --git a/gr-qtgui/lib/vector_sink_f_impl.cc b/gr-qtgui/lib/vector_sink_f_impl.cc index 0644071ebc..ba139b97f4 100644 --- a/gr-qtgui/lib/vector_sink_f_impl.cc +++ b/gr-qtgui/lib/vector_sink_f_impl.cc @@ -157,7 +157,7 @@ namespace gr { d_main_gui->setVecSize(d_vlen); set_x_axis(x_start, x_step); - if(not name.empty()) + if(! name.empty()) set_title(name); set_x_axis_label(x_axis_label); set_y_axis_label(y_axis_label); @@ -203,7 +203,7 @@ namespace gr { void vector_sink_f_impl::set_vec_average(const float avg) { - if (avg < 0 or avg > 1.0) { + if (avg < 0 || avg > 1.0) { GR_LOG_ALERT(d_logger, "Invalid average value received in set_vec_average(), must be within [0, 1]."); return; } diff --git a/gr-qtgui/python/qtgui/range.py b/gr-qtgui/python/qtgui/range.py index 168e6662c3..3eafc9002e 100755 --- a/gr-qtgui/python/qtgui/range.py +++ b/gr-qtgui/python/qtgui/range.py @@ -64,13 +64,16 @@ class Range(object): class RangeWidget(QtGui.QWidget): - def __init__(self, ranges, slot, label, style): + def __init__(self, ranges, slot, label, style, rangeType=float): """ Creates the QT Range widget """ QtGui.QWidget.__init__(self) self.range = ranges self.style = style + # rangeType tells the block how to return the value as a standard + self.rangeType = rangeType + # Top-block function to call when any value changes # Some widgets call this directly when their value changes. # Others have intermediate functions to map the value into the right range. @@ -81,24 +84,26 @@ class RangeWidget(QtGui.QWidget): layout.addWidget(label) if style == "dial": - self.d_widget = self.Dial(self, self.range, self.notifyChanged) + self.d_widget = self.Dial(self, self.range, self.notifyChanged, rangeType) elif style == "slider": - self.d_widget = self.Slider(self, self.range, self.notifyChanged) + self.d_widget = self.Slider(self, self.range, self.notifyChanged, rangeType) elif style == "counter": # The counter widget can be directly wired to the notifyChanged slot - self.d_widget = self.Counter(self, self.range, self.notifyChanged) + self.d_widget = self.Counter(self, self.range, self.notifyChanged, rangeType) else: # The CounterSlider needs its own internal handlers before calling notifyChanged - self.d_widget = self.CounterSlider(self, self.range, self.notifyChanged) + self.d_widget = self.CounterSlider(self, self.range, self.notifyChanged, rangeType) layout.addWidget(self.d_widget) self.setLayout(layout) class Dial(QtGui.QDial): """ Creates the range using a dial """ - def __init__(self, parent, ranges, slot): + def __init__(self, parent, ranges, slot, rangeType=float): QtGui.QDial.__init__(self, parent) + self.rangeType = rangeType + # Setup the dial self.setRange(0, ranges.nsteps-1) self.setSingleStep(1) @@ -116,13 +121,15 @@ class RangeWidget(QtGui.QWidget): def changed(self, value): """ Handles maping the value to the right range before calling the slot. """ val = self.range.map_range(value) - self.notifyChanged(val) + self.notifyChanged(self.rangeType(val)) class Slider(QtGui.QSlider): """ Creates the range using a slider """ - def __init__(self, parent, ranges, slot): + def __init__(self, parent, ranges, slot, rangeType=float): QtGui.QSlider.__init__(self, QtCore.Qt.Horizontal, parent) + self.rangeType = rangeType + # Setup the slider #self.setFocusPolicy(QtCore.Qt.NoFocus) self.setRange(0, ranges.nsteps - 1) @@ -149,7 +156,7 @@ class RangeWidget(QtGui.QWidget): def changed(self, value): """ Handle the valueChanged signal and map the value into the correct range """ val = self.range.map_range(value) - self.notifyChanged(val) + self.notifyChanged(self.rangeType(val)) def mousePressEvent(self, event): if((event.button() == QtCore.Qt.LeftButton)): @@ -168,9 +175,11 @@ class RangeWidget(QtGui.QWidget): class Counter(QtGui.QDoubleSpinBox): """ Creates the range using a counter """ - def __init__(self, parent, ranges, slot): + def __init__(self, parent, ranges, slot, rangeType=float): QtGui.QDoubleSpinBox.__init__(self, parent) + self.rangeType = rangeType + # Setup the counter self.setRange(ranges.min, ranges.max) self.setValue(ranges.default) @@ -179,18 +188,25 @@ class RangeWidget(QtGui.QWidget): self.setDecimals(ranges.precision) # The counter already handles floats and can be connected directly. - self.valueChanged.connect(slot) + self.valueChanged.connect(self.changed) + self.notifyChanged = slot + + def changed(self, value): + """ Handle the valueChanged signal by converting to the right type """ + self.notifyChanged(self.rangeType(value)) class CounterSlider(QtGui.QWidget): """ Creates the range using a counter and slider """ - def __init__(self, parent, ranges, slot): + def __init__(self, parent, ranges, slot, rangeType=float): QtGui.QWidget.__init__(self, parent) + self.rangeType = rangeType + # Slot to call in the parent self.notifyChanged = slot - self.slider = RangeWidget.Slider(parent, ranges, self.sliderChanged) - self.counter = RangeWidget.Counter(parent, ranges, self.counterChanged) + self.slider = RangeWidget.Slider(parent, ranges, self.sliderChanged, rangeType) + self.counter = RangeWidget.Counter(parent, ranges, self.counterChanged, rangeType) # Need another horizontal layout to wrap the other widgets. layout = Qt.QHBoxLayout() @@ -207,8 +223,8 @@ class RangeWidget(QtGui.QWidget): # If the counter was changed, ignore any of these events if not self.ignoreSlider: # Value is already float. Just set the counter - self.counter.setValue(value) - self.notifyChanged(value) + self.counter.setValue(self.rangeType(value)) + self.notifyChanged(self.rangeType(value)) self.ignoreSlider = False def counterChanged(self, value): @@ -223,4 +239,21 @@ class RangeWidget(QtGui.QWidget): self.ignoreSlider = True self.slider.setValue(new) - self.notifyChanged(value) + self.notifyChanged(self.rangeType(value)) + + +if __name__ == "__main__": + from PyQt4 import Qt + import sys + + def valueChanged(frequency): + print("Value updated - " + str(frequency)) + + app = Qt.QApplication(sys.argv) + widget = RangeWidget(Range(0, 100, 10, 1, 100), valueChanged, "Test", "counter_slider", int) + + widget.show() + widget.setWindowTitle("Test Qt Range") + app.exec_() + + widget = None diff --git a/gr-uhd/doc/uhd.dox b/gr-uhd/doc/uhd.dox index da6d9d45f5..27a1475566 100644 --- a/gr-uhd/doc/uhd.dox +++ b/gr-uhd/doc/uhd.dox @@ -12,15 +12,10 @@ as: from gnuradio import uhd \endcode -The relevant blocks are listed in the \ref uhd_blk group. - -A quick listing of the details can be found in Python after importing -by using: - -\code - help(uhd) -\endcode - +The relevant blocks are listed in the \ref uhd_blk group. The most important +components are the gr::uhd::usrp_source and gr::uhd::usrp_sink blocks, which +act as receivers/transmitters. Both are derived from gr::uhd::usrp_block, which +defines many of the shared functions between those blocks. \section uhd_external_docs External Documentation @@ -36,48 +31,92 @@ http://files.ettus.com/manual/annotated.html \section uhd_command_syntax Command Syntax The UHD sink and source can be controlled by a message port. These message ports -take commands, which are PMTs formatted as such: +take commands, which are PMTs formatted as described in \ref msg_passing_commands. + +There is a legacy format, which will be deprecated in the future, where commands may +be tuples, formatted as: (command, value, [channel]) -A command PMT is either a pair or a tuple. If it's a tuple, it must have either 2 or 3 elements. -Any other type of PMT will throw an error. +See older versions of this manual for documentation on this deprecated command format. -The `command` part is a string, which defines the command. `value` is a PMT whose format depends -on the command issued. Finally, `channel` is an integer PMT value that specifies which channel -this command shall be specified on. If this value is omitted, then it either applies this command -to all channels or channel zero, depending on which command is used. +In general, every command consists of one or more key/value pairs (either stored as a +PMT pair, or a dictionary). A full list of keys is listed below. Example: \code{.cpp} -pmt::pmt_t command = pmt::cons( // We make a pair, but pmt::make_tuple() is also valid! - pmt::mp("freq"), // Use the 'freq' command, which sets the frequency +pmt::pmt_t command = pmt::cons( // Make a pair + pmt::mp("freq"), // Key is 'freq' => sets the frequency pmt::mp(1.1e9) // Set the frequency to 1.1 GHz ); +// Now pass 'command' into the USRP block's command port \endcode This PMT would set the frequency to 1.1 GHz on all channels. We make use of the pmt::mp() function which automatically sets the PMT types. Assume we only want to set the frequency on channel 1 -(i.e. the second channel). In this case, we must construct a tuple: +(i.e. the second channel). In this case, we must construct a dictionary: \code{.cpp} -pmt::pmt_t command = pmt::make_tuple( - pmt::mp("freq"), // Use the 'freq' command, which sets the frequency - pmt::mp(1.1e9) // Set the frequency to 1.1 GHz - pmt::mp(1) // Select channel 1 -); +pmt::pmt_t command = pmt::make_dict(); +pmt::dict_add(command, pmt::mp("freq"), pmt::mp(1.1e9)); // Specify frequency +pmt::dict_add(command, pmt::mp("chan"), pmt::mp(1)); // Specify channel +// Now pass 'command' into the USRP block's command port \endcode +This command structure becomes more intuitive when thinking of sending the command PMT +as a function call, where the key/value pairs are argument names and values, respectively. +In the above example, the behaviour is the same as if calling +\code{.python} +usrp_source.set_center_freq(freq=1.1e9, chan=1) +\endcode +The main difference is that we can add more properties to the same +command PMT, e.g. as such: +\code{.cpp} +// 'command' is the same PMT as in the previous example +pmt::dict_add(command, pmt::mp("gain"), pmt::mp(23.0)); // Specify gain +pmt::dict_add(command, pmt::mp("antenna"), pmt::mp("TX/RX")); // Switch antenna +// Now pass 'command' into the USRP block's command port +\endcode +When the USRP block interprets this command PMT, all properties will be +set. + + +\subsection uhd_command_syntax_cmds Common command keys + +The following command keys are understood by both UHD Source and Sink: + +Command name | Value Type | Description +-------------|--------------|------------------------------------------------------------- +`chan` | int | Specifies a channel. If this is not given, either all channels are chosen, or channel 0, depending on the action. A value of -1 forces 'all channels', where possible. +`gain` | double | Sets the Tx or Rx gain (in dB). Defaults to all channels. +`freq` | double | Sets the Tx or Rx frequency. Defaults to all channels. If specified without `lo_offset`, it will set the LO offset to zero. +`lo_offset` | double | Sets an LO offset. Defaults to all channels. Note this does not affect the effective center frequency. +`tune` | tune_request | Like freq, but sets a full tune request (i.e. center frequency and DSP offset). Defaults to all channels. +`lo_freq` | double | For fully manual tuning: Set the LO frequency (RF frequency). Conflicts with `freq`, `lo_offset`, and `tune`. +`dsp_freq` | double | For fully manual tuning: Set the DSP frequency (CORDIC frequency). Conflicts with `freq`, `lo_offset`, and `tune`. +`rate` | double | See usrp_block::set_samp_rate(). *Always* affects all channels. +`bandwidth` | double | See usrp_block::set_bandwidth(). Defaults to all channels. +`time` | timestamp | Sets a command time. See usrp_block::set_command_time(). A value of PMT_NIL will clear the command time. +`mboard` | int | Specify mboard index, where applicable. +`antenna` | string | See usrp_block::set_antenna(). Defaults to all channels. + +Special types: + +- tune_request: Like a uhd::tune_request_t, but always uses POLICY_AUTO. This is a pair, composed of (target_frequency, lo_offset) +- timestamp: A pair composed of (long full_secs, double frac_secs). Similar to uhd::time_spec_t -\subsection uhd_command_syntax_cmds Common commands +\b Note: Not all commands are affected by `time`. See the UHD manual for details on timed commands. -The following commands are understood by both UHD Source and Sink: +\subsection uhd_command_syntax_multi_vs_single Dictionaries vs pairs -Command name | Value Type | Description --------------|------------|------------------------------------------------------------- -`freq` | double | Sets the Tx or Rx frequency. Defaults to all channels. -`lo_offset` | double | Sets an LO offset. Defaults to all channels. -`gain` | double | Sets the Tx or Rx gain (in dB). Defaults to all channels. +Given the choices, it may be unclear if it's preferable to send multiple commands +to the USRP block with a single key/value pair each, or send a single dict with +all the values. +In general, the dictionary should be preferred. It has some distinct advantages: +- If it carries a timestamp, this timestamp is valid for all key/value pairs it + may be applied to. +- All settings will be applied at once. With multiple messages, other blocks might + be sending interfering messages while the messages are being processed. \section uhd_configuring Configuring a UHD object diff --git a/gr-uhd/examples/grc/uhd_msg_tune.grc b/gr-uhd/examples/grc/uhd_msg_tune.grc index 89022278be..cedb743b40 100644 --- a/gr-uhd/examples/grc/uhd_msg_tune.grc +++ b/gr-uhd/examples/grc/uhd_msg_tune.grc @@ -1,39 +1,56 @@ <?xml version='1.0' encoding='ASCII'?> +<?grc format='1' created='3.7.8'?> <flow_graph> <timestamp>Tue Jul 8 12:08:19 2014</timestamp> <block> <key>options</key> <param> - <key>id</key> - <value>uhd_tune_msg</value> + <key>author</key> + <value></value> </param> <param> - <key>_enabled</key> - <value>True</value> + <key>alias</key> + <value></value> </param> <param> - <key>title</key> - <value>UHD Message Tuner</value> + <key>category</key> + <value>Custom</value> </param> <param> - <key>author</key> + <key>comment</key> <value></value> </param> <param> <key>description</key> - <value>Tune a UHD source from a QT sink via messages.</value> + <value>Tune a UHD source from a QT sink via messages (double-click a frequency to tune)</value> </param> <param> - <key>window_size</key> - <value>1280, 1024</value> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>_coordinate</key> + <value>(8, 3)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> </param> <param> <key>generate_options</key> <value>qt_gui</value> </param> <param> - <key>category</key> - <value>Custom</value> + <key>id</key> + <value>uhd_tune_msg</value> + </param> + <param> + <key>max_nouts</key> + <value>0</value> + </param> + <param> + <key>realtime_scheduling</key> + <value></value> </param> <param> <key>run_options</key> @@ -44,447 +61,708 @@ <value>True</value> </param> <param> - <key>max_nouts</key> - <value>0</value> + <key>thread_safe_setters</key> + <value></value> </param> <param> - <key>realtime_scheduling</key> - <value></value> + <key>title</key> + <value>UHD Message Tuner</value> </param> <param> - <key>alias</key> + <key>window_size</key> + <value>1280, 1024</value> + </param> + </block> + <block> + <key>variable_qtgui_chooser</key> + <param> + <key>comment</key> <value></value> </param> <param> + <key>value</key> + <value>TX/RX</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> <key>_coordinate</key> - <value>(-1, -2)</value> + <value>(8, 307)</value> + </param> + <param> + <key>gui_hint</key> + <value></value> </param> <param> <key>_rotation</key> <value>0</value> </param> + <param> + <key>id</key> + <value>ant_msg</value> + </param> + <param> + <key>label0</key> + <value></value> + </param> + <param> + <key>label1</key> + <value></value> + </param> + <param> + <key>label2</key> + <value></value> + </param> + <param> + <key>label3</key> + <value></value> + </param> + <param> + <key>label4</key> + <value></value> + </param> + <param> + <key>label</key> + <value>Antenna</value> + </param> + <param> + <key>labels</key> + <value>[]</value> + </param> + <param> + <key>num_opts</key> + <value>2</value> + </param> + <param> + <key>option0</key> + <value>TX/RX</value> + </param> + <param> + <key>option1</key> + <value>RX2</value> + </param> + <param> + <key>option2</key> + <value>2</value> + </param> + <param> + <key>option3</key> + <value>3</value> + </param> + <param> + <key>option4</key> + <value>4</value> + </param> + <param> + <key>options</key> + <value>[0, 1, 2]</value> + </param> + <param> + <key>orient</key> + <value>Qt.QVBoxLayout</value> + </param> + <param> + <key>type</key> + <value>string</value> + </param> + <param> + <key>widget</key> + <value>combo_box</value> + </param> </block> <block> <key>variable</key> <param> - <key>id</key> - <value>initial_fc</value> + <key>comment</key> + <value></value> </param> <param> <key>_enabled</key> <value>True</value> </param> <param> + <key>_coordinate</key> + <value>(232, 115)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>cmd_msg</value> + </param> + <param> <key>value</key> - <value>100e6</value> + <value>pmt.to_pmt({'antenna': ant_msg, 'gain': gain_msg, 'chan': 0, 'freq': freq_msg, 'lo_offset': lo_msg})</value> </param> + </block> + <block> + <key>variable_qtgui_entry</key> <param> - <key>alias</key> + <key>comment</key> <value></value> </param> <param> + <key>value</key> + <value>initial_fc</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> <key>_coordinate</key> - <value>(-2, 172)</value> + <value>(144, 227)</value> + </param> + <param> + <key>gui_hint</key> + <value>0,1,1,1</value> </param> <param> <key>_rotation</key> <value>0</value> </param> + <param> + <key>id</key> + <value>freq_msg</value> + </param> + <param> + <key>label</key> + <value>Frequency</value> + </param> + <param> + <key>type</key> + <value>real</value> + </param> </block> <block> <key>variable</key> <param> - <key>id</key> - <value>samp_rate</value> + <key>comment</key> + <value></value> </param> <param> <key>_enabled</key> <value>True</value> </param> <param> + <key>_coordinate</key> + <value>(104, 99)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>gain</value> + </param> + <param> <key>value</key> - <value>2e6</value> + <value>0.8</value> </param> + </block> + <block> + <key>variable_qtgui_entry</key> <param> - <key>alias</key> + <key>comment</key> <value></value> </param> <param> + <key>value</key> + <value>gain</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> <key>_coordinate</key> - <value>(1, 102)</value> + <value>(8, 227)</value> + </param> + <param> + <key>gui_hint</key> + <value>0,0,1,1</value> </param> <param> <key>_rotation</key> <value>0</value> </param> + <param> + <key>id</key> + <value>gain_msg</value> + </param> + <param> + <key>label</key> + <value>Gain</value> + </param> + <param> + <key>type</key> + <value>real</value> + </param> </block> <block> - <key>variable_qtgui_range</key> + <key>variable</key> <param> - <key>id</key> - <value>gain</value> + <key>comment</key> + <value></value> </param> <param> <key>_enabled</key> <value>True</value> </param> <param> - <key>label</key> - <value></value> + <key>_coordinate</key> + <value>(8, 163)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>initial_fc</value> </param> <param> <key>value</key> - <value>20</value> + <value>100e6</value> </param> + </block> + <block> + <key>variable_qtgui_entry</key> <param> - <key>start</key> + <key>comment</key> + <value></value> + </param> + <param> + <key>value</key> <value>0</value> </param> <param> - <key>stop</key> - <value>60</value> + <key>_enabled</key> + <value>True</value> </param> <param> - <key>step</key> - <value>1</value> + <key>_coordinate</key> + <value>(144, 307)</value> </param> <param> - <key>widget</key> - <value>counter_slider</value> + <key>gui_hint</key> + <value>1,1,1,1</value> </param> <param> - <key>orient</key> - <value>Qt.Horizontal</value> + <key>_rotation</key> + <value>0</value> </param> <param> - <key>min_len</key> - <value>200</value> + <key>id</key> + <value>lo_msg</value> </param> <param> - <key>gui_hint</key> - <value></value> + <key>label</key> + <value>LO Offset</value> </param> <param> - <key>alias</key> + <key>type</key> + <value>real</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>comment</key> <value></value> </param> <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> <key>_coordinate</key> - <value>(103, 99)</value> + <value>(8, 99)</value> </param> <param> <key>_rotation</key> <value>0</value> </param> + <param> + <key>id</key> + <value>samp_rate</value> + </param> + <param> + <key>value</key> + <value>2e6</value> + </param> </block> <block> - <key>uhd_usrp_source</key> + <key>blocks_message_strobe</key> <param> - <key>id</key> - <value>uhd_usrp_source_0</value> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> </param> <param> <key>_enabled</key> <value>True</value> </param> <param> - <key>type</key> - <value>fc32</value> + <key>_coordinate</key> + <value>(216, 43)</value> </param> <param> - <key>otw</key> - <value></value> + <key>_rotation</key> + <value>0</value> </param> <param> - <key>stream_args</key> - <value></value> + <key>id</key> + <value>blocks_message_strobe_0</value> </param> <param> - <key>stream_chans</key> - <value>[]</value> + <key>maxoutbuf</key> + <value>0</value> </param> <param> - <key>dev_addr</key> - <value>""</value> + <key>msg</key> + <value>cmd_msg</value> </param> <param> - <key>dev_args</key> - <value>""</value> + <key>minoutbuf</key> + <value>0</value> </param> <param> - <key>sync</key> - <value></value> + <key>period</key> + <value>2000</value> </param> + </block> + <block> + <key>qtgui_freq_sink_x</key> <param> - <key>clock_rate</key> - <value>0.0</value> + <key>autoscale</key> + <value>False</value> </param> <param> - <key>num_mboards</key> - <value>1</value> + <key>average</key> + <value>0.1</value> </param> <param> - <key>clock_source0</key> - <value></value> + <key>bw</key> + <value>samp_rate</value> </param> <param> - <key>time_source0</key> + <key>alias</key> <value></value> </param> <param> - <key>sd_spec0</key> - <value></value> + <key>fc</key> + <value>initial_fc</value> </param> <param> - <key>clock_source1</key> + <key>comment</key> <value></value> </param> <param> - <key>time_source1</key> - <value></value> + <key>ctrlpanel</key> + <value>False</value> </param> <param> - <key>sd_spec1</key> + <key>affinity</key> <value></value> </param> <param> - <key>clock_source2</key> - <value></value> + <key>_enabled</key> + <value>True</value> </param> <param> - <key>time_source2</key> - <value></value> + <key>fftsize</key> + <value>1024</value> </param> <param> - <key>sd_spec2</key> - <value></value> + <key>_coordinate</key> + <value>(472, 155)</value> </param> <param> - <key>clock_source3</key> + <key>gui_hint</key> <value></value> </param> <param> - <key>time_source3</key> - <value></value> + <key>_rotation</key> + <value>180</value> </param> <param> - <key>sd_spec3</key> - <value></value> + <key>grid</key> + <value>True</value> </param> <param> - <key>clock_source4</key> - <value></value> + <key>id</key> + <value>qtgui_freq_sink_x_0</value> </param> <param> - <key>time_source4</key> - <value></value> + <key>legend</key> + <value>False</value> </param> <param> - <key>sd_spec4</key> - <value></value> + <key>alpha1</key> + <value>1.0</value> </param> <param> - <key>clock_source5</key> - <value></value> + <key>color1</key> + <value>"blue"</value> </param> <param> - <key>time_source5</key> + <key>label1</key> <value></value> </param> <param> - <key>sd_spec5</key> - <value></value> + <key>width1</key> + <value>1</value> </param> <param> - <key>clock_source6</key> - <value></value> + <key>alpha10</key> + <value>1.0</value> </param> <param> - <key>time_source6</key> - <value></value> + <key>color10</key> + <value>"dark blue"</value> </param> <param> - <key>sd_spec6</key> + <key>label10</key> <value></value> </param> <param> - <key>clock_source7</key> - <value></value> + <key>width10</key> + <value>1</value> </param> <param> - <key>time_source7</key> - <value></value> + <key>alpha2</key> + <value>1.0</value> </param> <param> - <key>sd_spec7</key> + <key>color2</key> + <value>"red"</value> + </param> + <param> + <key>label2</key> <value></value> </param> <param> - <key>nchan</key> + <key>width2</key> <value>1</value> </param> <param> - <key>samp_rate</key> - <value>samp_rate</value> + <key>alpha3</key> + <value>1.0</value> </param> <param> - <key>center_freq0</key> - <value>initial_fc</value> + <key>color3</key> + <value>"green"</value> </param> <param> - <key>gain0</key> - <value>gain</value> + <key>label3</key> + <value></value> </param> <param> - <key>ant0</key> + <key>width3</key> + <value>1</value> + </param> + <param> + <key>alpha4</key> + <value>1.0</value> + </param> + <param> + <key>color4</key> + <value>"black"</value> + </param> + <param> + <key>label4</key> <value></value> </param> <param> - <key>bw0</key> - <value>0</value> + <key>width4</key> + <value>1</value> </param> <param> - <key>center_freq1</key> - <value>0</value> + <key>alpha5</key> + <value>1.0</value> </param> <param> - <key>gain1</key> - <value>0</value> + <key>color5</key> + <value>"cyan"</value> </param> <param> - <key>ant1</key> + <key>label5</key> <value></value> </param> <param> - <key>bw1</key> - <value>0</value> + <key>width5</key> + <value>1</value> </param> <param> - <key>center_freq2</key> - <value>0</value> + <key>alpha6</key> + <value>1.0</value> </param> <param> - <key>gain2</key> - <value>0</value> + <key>color6</key> + <value>"magenta"</value> </param> <param> - <key>ant2</key> + <key>label6</key> <value></value> </param> <param> - <key>bw2</key> - <value>0</value> + <key>width6</key> + <value>1</value> </param> <param> - <key>center_freq3</key> - <value>0</value> + <key>alpha7</key> + <value>1.0</value> </param> <param> - <key>gain3</key> - <value>0</value> + <key>color7</key> + <value>"yellow"</value> </param> <param> - <key>ant3</key> + <key>label7</key> <value></value> </param> <param> - <key>bw3</key> - <value>0</value> + <key>width7</key> + <value>1</value> </param> <param> - <key>center_freq4</key> - <value>0</value> + <key>alpha8</key> + <value>1.0</value> </param> <param> - <key>gain4</key> - <value>0</value> + <key>color8</key> + <value>"dark red"</value> </param> <param> - <key>ant4</key> + <key>label8</key> <value></value> </param> <param> - <key>bw4</key> - <value>0</value> + <key>width8</key> + <value>1</value> </param> <param> - <key>center_freq5</key> - <value>0</value> + <key>alpha9</key> + <value>1.0</value> </param> <param> - <key>gain5</key> - <value>0</value> + <key>color9</key> + <value>"dark green"</value> </param> <param> - <key>ant5</key> + <key>label9</key> <value></value> </param> <param> - <key>bw5</key> - <value>0</value> + <key>width9</key> + <value>1</value> </param> <param> - <key>center_freq6</key> + <key>maxoutbuf</key> <value>0</value> </param> <param> - <key>gain6</key> + <key>minoutbuf</key> <value>0</value> </param> <param> - <key>ant6</key> + <key>name</key> <value></value> </param> <param> - <key>bw6</key> - <value>0</value> + <key>nconnections</key> + <value>1</value> </param> <param> - <key>center_freq7</key> - <value>0</value> + <key>showports</key> + <value>False</value> </param> <param> - <key>gain7</key> + <key>freqhalf</key> + <value>True</value> + </param> + <param> + <key>tr_chan</key> <value>0</value> </param> <param> - <key>ant7</key> - <value></value> + <key>tr_level</key> + <value>0.0</value> </param> <param> - <key>bw7</key> - <value>0</value> + <key>tr_mode</key> + <value>qtgui.TRIG_MODE_FREE</value> </param> <param> - <key>center_freq8</key> - <value>0</value> + <key>tr_tag</key> + <value>""</value> </param> <param> - <key>gain8</key> - <value>0</value> + <key>type</key> + <value>complex</value> </param> <param> - <key>ant8</key> + <key>update_time</key> + <value>0.10</value> + </param> + <param> + <key>wintype</key> + <value>firdes.WIN_BLACKMAN_hARRIS</value> + </param> + <param> + <key>ymax</key> + <value>-40</value> + </param> + <param> + <key>ymin</key> + <value>-120</value> + </param> + </block> + <block> + <key>uhd_usrp_source</key> + <param> + <key>alias</key> <value></value> </param> <param> - <key>bw8</key> - <value>0</value> + <key>ant0</key> + <value></value> </param> <param> - <key>center_freq9</key> + <key>bw0</key> <value>0</value> </param> <param> - <key>gain9</key> - <value>0</value> + <key>center_freq0</key> + <value>initial_fc</value> </param> <param> - <key>ant9</key> + <key>norm_gain0</key> + <value>True</value> + </param> + <param> + <key>gain0</key> + <value>gain</value> + </param> + <param> + <key>ant10</key> <value></value> </param> <param> - <key>bw9</key> + <key>bw10</key> <value>0</value> </param> <param> @@ -492,15 +770,19 @@ <value>0</value> </param> <param> + <key>norm_gain10</key> + <value>False</value> + </param> + <param> <key>gain10</key> <value>0</value> </param> <param> - <key>ant10</key> + <key>ant11</key> <value></value> </param> <param> - <key>bw10</key> + <key>bw11</key> <value>0</value> </param> <param> @@ -508,15 +790,19 @@ <value>0</value> </param> <param> + <key>norm_gain11</key> + <value>False</value> + </param> + <param> <key>gain11</key> <value>0</value> </param> <param> - <key>ant11</key> + <key>ant12</key> <value></value> </param> <param> - <key>bw11</key> + <key>bw12</key> <value>0</value> </param> <param> @@ -524,15 +810,19 @@ <value>0</value> </param> <param> + <key>norm_gain12</key> + <value>False</value> + </param> + <param> <key>gain12</key> <value>0</value> </param> <param> - <key>ant12</key> + <key>ant13</key> <value></value> </param> <param> - <key>bw12</key> + <key>bw13</key> <value>0</value> </param> <param> @@ -540,15 +830,19 @@ <value>0</value> </param> <param> + <key>norm_gain13</key> + <value>False</value> + </param> + <param> <key>gain13</key> <value>0</value> </param> <param> - <key>ant13</key> + <key>ant14</key> <value></value> </param> <param> - <key>bw13</key> + <key>bw14</key> <value>0</value> </param> <param> @@ -556,15 +850,19 @@ <value>0</value> </param> <param> + <key>norm_gain14</key> + <value>False</value> + </param> + <param> <key>gain14</key> <value>0</value> </param> <param> - <key>ant14</key> + <key>ant15</key> <value></value> </param> <param> - <key>bw14</key> + <key>bw15</key> <value>0</value> </param> <param> @@ -572,15 +870,19 @@ <value>0</value> </param> <param> + <key>norm_gain15</key> + <value>False</value> + </param> + <param> <key>gain15</key> <value>0</value> </param> <param> - <key>ant15</key> + <key>ant16</key> <value></value> </param> <param> - <key>bw15</key> + <key>bw16</key> <value>0</value> </param> <param> @@ -588,15 +890,19 @@ <value>0</value> </param> <param> + <key>norm_gain16</key> + <value>False</value> + </param> + <param> <key>gain16</key> <value>0</value> </param> <param> - <key>ant16</key> + <key>ant17</key> <value></value> </param> <param> - <key>bw16</key> + <key>bw17</key> <value>0</value> </param> <param> @@ -604,15 +910,19 @@ <value>0</value> </param> <param> + <key>norm_gain17</key> + <value>False</value> + </param> + <param> <key>gain17</key> <value>0</value> </param> <param> - <key>ant17</key> + <key>ant18</key> <value></value> </param> <param> - <key>bw17</key> + <key>bw18</key> <value>0</value> </param> <param> @@ -620,15 +930,19 @@ <value>0</value> </param> <param> + <key>norm_gain18</key> + <value>False</value> + </param> + <param> <key>gain18</key> <value>0</value> </param> <param> - <key>ant18</key> + <key>ant19</key> <value></value> </param> <param> - <key>bw18</key> + <key>bw19</key> <value>0</value> </param> <param> @@ -636,23 +950,31 @@ <value>0</value> </param> <param> + <key>norm_gain19</key> + <value>False</value> + </param> + <param> <key>gain19</key> <value>0</value> </param> <param> - <key>ant19</key> + <key>ant1</key> <value></value> </param> <param> - <key>bw19</key> + <key>bw1</key> <value>0</value> </param> <param> - <key>center_freq20</key> + <key>center_freq1</key> <value>0</value> </param> <param> - <key>gain20</key> + <key>norm_gain1</key> + <value>False</value> + </param> + <param> + <key>gain1</key> <value>0</value> </param> <param> @@ -664,11 +986,15 @@ <value>0</value> </param> <param> - <key>center_freq21</key> + <key>center_freq20</key> <value>0</value> </param> <param> - <key>gain21</key> + <key>norm_gain20</key> + <value>False</value> + </param> + <param> + <key>gain20</key> <value>0</value> </param> <param> @@ -680,11 +1006,15 @@ <value>0</value> </param> <param> - <key>center_freq22</key> + <key>center_freq21</key> <value>0</value> </param> <param> - <key>gain22</key> + <key>norm_gain21</key> + <value>False</value> + </param> + <param> + <key>gain21</key> <value>0</value> </param> <param> @@ -696,11 +1026,15 @@ <value>0</value> </param> <param> - <key>center_freq23</key> + <key>center_freq22</key> <value>0</value> </param> <param> - <key>gain23</key> + <key>norm_gain22</key> + <value>False</value> + </param> + <param> + <key>gain22</key> <value>0</value> </param> <param> @@ -712,11 +1046,15 @@ <value>0</value> </param> <param> - <key>center_freq24</key> + <key>center_freq23</key> <value>0</value> </param> <param> - <key>gain24</key> + <key>norm_gain23</key> + <value>False</value> + </param> + <param> + <key>gain23</key> <value>0</value> </param> <param> @@ -728,11 +1066,15 @@ <value>0</value> </param> <param> - <key>center_freq25</key> + <key>center_freq24</key> <value>0</value> </param> <param> - <key>gain25</key> + <key>norm_gain24</key> + <value>False</value> + </param> + <param> + <key>gain24</key> <value>0</value> </param> <param> @@ -744,11 +1086,15 @@ <value>0</value> </param> <param> - <key>center_freq26</key> + <key>center_freq25</key> <value>0</value> </param> <param> - <key>gain26</key> + <key>norm_gain25</key> + <value>False</value> + </param> + <param> + <key>gain25</key> <value>0</value> </param> <param> @@ -760,11 +1106,15 @@ <value>0</value> </param> <param> - <key>center_freq27</key> + <key>center_freq26</key> <value>0</value> </param> <param> - <key>gain27</key> + <key>norm_gain26</key> + <value>False</value> + </param> + <param> + <key>gain26</key> <value>0</value> </param> <param> @@ -776,11 +1126,15 @@ <value>0</value> </param> <param> - <key>center_freq28</key> + <key>center_freq27</key> <value>0</value> </param> <param> - <key>gain28</key> + <key>norm_gain27</key> + <value>False</value> + </param> + <param> + <key>gain27</key> <value>0</value> </param> <param> @@ -792,11 +1146,15 @@ <value>0</value> </param> <param> - <key>center_freq29</key> + <key>center_freq28</key> <value>0</value> </param> <param> - <key>gain29</key> + <key>norm_gain28</key> + <value>False</value> + </param> + <param> + <key>gain28</key> <value>0</value> </param> <param> @@ -808,11 +1166,35 @@ <value>0</value> </param> <param> - <key>center_freq30</key> + <key>center_freq29</key> <value>0</value> </param> <param> - <key>gain30</key> + <key>norm_gain29</key> + <value>False</value> + </param> + <param> + <key>gain29</key> + <value>0</value> + </param> + <param> + <key>ant2</key> + <value></value> + </param> + <param> + <key>bw2</key> + <value>0</value> + </param> + <param> + <key>center_freq2</key> + <value>0</value> + </param> + <param> + <key>norm_gain2</key> + <value>False</value> + </param> + <param> + <key>gain2</key> <value>0</value> </param> <param> @@ -824,11 +1206,15 @@ <value>0</value> </param> <param> - <key>center_freq31</key> + <key>center_freq30</key> <value>0</value> </param> <param> - <key>gain31</key> + <key>norm_gain30</key> + <value>False</value> + </param> + <param> + <key>gain30</key> <value>0</value> </param> <param> @@ -840,258 +1226,291 @@ <value>0</value> </param> <param> - <key>alias</key> - <value></value> + <key>center_freq31</key> + <value>0</value> </param> <param> - <key>affinity</key> + <key>norm_gain31</key> + <value>False</value> + </param> + <param> + <key>gain31</key> + <value>0</value> + </param> + <param> + <key>ant3</key> <value></value> </param> <param> - <key>minoutbuf</key> + <key>bw3</key> <value>0</value> </param> <param> - <key>maxoutbuf</key> + <key>center_freq3</key> <value>0</value> </param> <param> - <key>_coordinate</key> - <value>(336, 8)</value> + <key>norm_gain3</key> + <value>False</value> </param> <param> - <key>_rotation</key> + <key>gain3</key> <value>0</value> </param> - </block> - <block> - <key>qtgui_freq_sink_x</key> <param> - <key>id</key> - <value>qtgui_freq_sink_x_0</value> + <key>ant4</key> + <value></value> </param> <param> - <key>_enabled</key> - <value>True</value> + <key>bw4</key> + <value>0</value> </param> <param> - <key>type</key> - <value>complex</value> + <key>center_freq4</key> + <value>0</value> </param> <param> - <key>name</key> - <value>QT GUI Plot</value> + <key>norm_gain4</key> + <value>False</value> </param> <param> - <key>fftsize</key> - <value>1024</value> + <key>gain4</key> + <value>0</value> </param> <param> - <key>wintype</key> - <value>firdes.WIN_BLACKMAN_hARRIS</value> + <key>ant5</key> + <value></value> </param> <param> - <key>fc</key> - <value>initial_fc</value> + <key>bw5</key> + <value>0</value> </param> <param> - <key>bw</key> - <value>samp_rate</value> + <key>center_freq5</key> + <value>0</value> </param> <param> - <key>autoscale</key> + <key>norm_gain5</key> <value>False</value> </param> <param> - <key>average</key> - <value>1.0</value> + <key>gain5</key> + <value>0</value> </param> <param> - <key>ymin</key> - <value>-140</value> + <key>ant6</key> + <value></value> </param> <param> - <key>ymax</key> - <value>10</value> + <key>bw6</key> + <value>0</value> </param> <param> - <key>nconnections</key> - <value>1</value> + <key>center_freq6</key> + <value>0</value> </param> <param> - <key>update_time</key> - <value>0.10</value> + <key>norm_gain6</key> + <value>False</value> </param> <param> - <key>gui_hint</key> - <value></value> + <key>gain6</key> + <value>0</value> </param> <param> - <key>label1</key> + <key>ant7</key> <value></value> </param> <param> - <key>width1</key> - <value>1</value> + <key>bw7</key> + <value>0</value> </param> <param> - <key>color1</key> - <value>"blue"</value> + <key>center_freq7</key> + <value>0</value> </param> <param> - <key>alpha1</key> - <value>1.0</value> + <key>norm_gain7</key> + <value>False</value> </param> <param> - <key>label2</key> + <key>gain7</key> + <value>0</value> + </param> + <param> + <key>ant8</key> <value></value> </param> <param> - <key>width2</key> - <value>1</value> + <key>bw8</key> + <value>0</value> </param> <param> - <key>color2</key> - <value>"red"</value> + <key>center_freq8</key> + <value>0</value> </param> <param> - <key>alpha2</key> - <value>1.0</value> + <key>norm_gain8</key> + <value>False</value> </param> <param> - <key>label3</key> + <key>gain8</key> + <value>0</value> + </param> + <param> + <key>ant9</key> <value></value> </param> <param> - <key>width3</key> - <value>1</value> + <key>bw9</key> + <value>0</value> </param> <param> - <key>color3</key> - <value>"green"</value> + <key>center_freq9</key> + <value>0</value> </param> <param> - <key>alpha3</key> - <value>1.0</value> + <key>norm_gain9</key> + <value>False</value> </param> <param> - <key>label4</key> + <key>gain9</key> + <value>0</value> + </param> + <param> + <key>clock_rate</key> + <value>0.0</value> + </param> + <param> + <key>comment</key> <value></value> </param> <param> - <key>width4</key> - <value>1</value> + <key>affinity</key> + <value></value> </param> <param> - <key>color4</key> - <value>"black"</value> + <key>dev_addr</key> + <value>""</value> </param> <param> - <key>alpha4</key> - <value>1.0</value> + <key>dev_args</key> + <value>""</value> </param> <param> - <key>label5</key> - <value></value> + <key>_enabled</key> + <value>True</value> </param> <param> - <key>width5</key> - <value>1</value> + <key>_coordinate</key> + <value>(488, 27)</value> </param> <param> - <key>color5</key> - <value>"cyan"</value> + <key>_rotation</key> + <value>0</value> </param> <param> - <key>alpha5</key> - <value>1.0</value> + <key>id</key> + <value>uhd_usrp_source_0</value> </param> <param> - <key>label6</key> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>clock_source0</key> <value></value> </param> <param> - <key>width6</key> - <value>1</value> + <key>sd_spec0</key> + <value></value> </param> <param> - <key>color6</key> - <value>"magenta"</value> + <key>time_source0</key> + <value></value> </param> <param> - <key>alpha6</key> - <value>1.0</value> + <key>clock_source1</key> + <value></value> </param> <param> - <key>label7</key> + <key>sd_spec1</key> <value></value> </param> <param> - <key>width7</key> - <value>1</value> + <key>time_source1</key> + <value></value> </param> <param> - <key>color7</key> - <value>"yellow"</value> + <key>clock_source2</key> + <value></value> </param> <param> - <key>alpha7</key> - <value>1.0</value> + <key>sd_spec2</key> + <value></value> </param> <param> - <key>label8</key> + <key>time_source2</key> <value></value> </param> <param> - <key>width8</key> - <value>1</value> + <key>clock_source3</key> + <value></value> </param> <param> - <key>color8</key> - <value>"dark red"</value> + <key>sd_spec3</key> + <value></value> </param> <param> - <key>alpha8</key> - <value>1.0</value> + <key>time_source3</key> + <value></value> </param> <param> - <key>label9</key> + <key>clock_source4</key> <value></value> </param> <param> - <key>width9</key> - <value>1</value> + <key>sd_spec4</key> + <value></value> </param> <param> - <key>color9</key> - <value>"dark green"</value> + <key>time_source4</key> + <value></value> </param> <param> - <key>alpha9</key> - <value>1.0</value> + <key>clock_source5</key> + <value></value> </param> <param> - <key>label10</key> + <key>sd_spec5</key> <value></value> </param> <param> - <key>width10</key> - <value>1</value> + <key>time_source5</key> + <value></value> </param> <param> - <key>color10</key> - <value>"dark blue"</value> + <key>clock_source6</key> + <value></value> </param> <param> - <key>alpha10</key> - <value>1.0</value> + <key>sd_spec6</key> + <value></value> </param> <param> - <key>alias</key> + <key>time_source6</key> <value></value> </param> <param> - <key>affinity</key> + <key>clock_source7</key> + <value></value> + </param> + <param> + <key>sd_spec7</key> + <value></value> + </param> + <param> + <key>time_source7</key> <value></value> </param> <param> @@ -1099,23 +1518,49 @@ <value>0</value> </param> <param> - <key>maxoutbuf</key> - <value>0</value> + <key>nchan</key> + <value>1</value> </param> <param> - <key>_coordinate</key> - <value>(330, 104)</value> + <key>num_mboards</key> + <value>1</value> </param> <param> - <key>_rotation</key> - <value>180</value> + <key>type</key> + <value>fc32</value> + </param> + <param> + <key>samp_rate</key> + <value>samp_rate</value> + </param> + <param> + <key>stream_args</key> + <value></value> + </param> + <param> + <key>stream_chans</key> + <value>[]</value> + </param> + <param> + <key>sync</key> + <value></value> + </param> + <param> + <key>otw</key> + <value></value> </param> </block> <connection> - <source_block_id>uhd_usrp_source_0</source_block_id> + <source_block_id>blocks_message_strobe_0</source_block_id> + <sink_block_id>uhd_usrp_source_0</sink_block_id> + <source_key>strobe</source_key> + <sink_key>command</sink_key> + </connection> + <connection> + <source_block_id>qtgui_freq_sink_x_0</source_block_id> <sink_block_id>qtgui_freq_sink_x_0</sink_block_id> - <source_key>0</source_key> - <sink_key>0</sink_key> + <source_key>freq</source_key> + <sink_key>freq</sink_key> </connection> <connection> <source_block_id>qtgui_freq_sink_x_0</source_block_id> @@ -1124,9 +1569,9 @@ <sink_key>command</sink_key> </connection> <connection> - <source_block_id>qtgui_freq_sink_x_0</source_block_id> + <source_block_id>uhd_usrp_source_0</source_block_id> <sink_block_id>qtgui_freq_sink_x_0</sink_block_id> - <source_key>freq</source_key> - <sink_key>freq</sink_key> + <source_key>0</source_key> + <sink_key>0</sink_key> </connection> </flow_graph> diff --git a/gr-uhd/examples/python/freq_hopping.py b/gr-uhd/examples/python/freq_hopping.py index 5da5efa241..ce33a92a51 100755 --- a/gr-uhd/examples/python/freq_hopping.py +++ b/gr-uhd/examples/python/freq_hopping.py @@ -24,7 +24,6 @@ TXs a waveform (either from a file, or a sinusoid) in a frequency-hopping manner. """ -import time import numpy import argparse import pmt @@ -35,7 +34,7 @@ from gnuradio import uhd def setup_parser(): """ Setup the parser for the frequency hopper. """ parser = argparse.ArgumentParser( - description="Transmit a signal in a frequency-hopping manner, using tx_freq tags." + description="Transmit a signal in a frequency-hopping manner, using tx_freq tags." ) parser.add_argument('-i', '--input-file', type=file, default=None, help="File with samples to transmit. If left out, will transmit a sinusoid.") @@ -54,7 +53,9 @@ def setup_parser(): parser.add_argument("-t", "--hop-time", type=float, default=1000, help="Time between hops in milliseconds. This must be larger than or equal to the burst duration as set by --samp-per-burst") parser.add_argument("-f", "--freq", type=float, default=2.45e9, - help="Base frequency. This is the lowest frequency at which the USRP will Tx.") + help="Base frequency. This is the middle channel frequency at which the USRP will Tx.") + parser.add_argument("--dsp", action='store_true', + help="DSP tuning only.") parser.add_argument("-d", "--freq-delta", type=float, default=1e6, help="Channel spacing.") parser.add_argument("-c", "--num-channels", type=int, default=5, @@ -64,7 +65,7 @@ def setup_parser(): parser.add_argument("-p", "--post-tuning", action='count', help="Tune after transmitting. Default is to tune immediately before transmitting.") parser.add_argument("-v", "--verbose", action='count', - help="Print more information.") + help="Print more information. The morer the printier.") return parser @@ -73,7 +74,7 @@ class FrequencyHopperSrc(gr.hier_block2): def __init__( self, n_bursts, n_channels, - freq_delta, base_freq, + freq_delta, base_freq, dsp_tuning, burst_length, base_time, hop_time, post_tuning=False, tx_gain=0, @@ -85,8 +86,10 @@ class FrequencyHopperSrc(gr.hier_block2): gr.io_signature(1, 1, gr.sizeof_gr_complex), ) n_samples_total = n_bursts * burst_length - self.hop_sequence = numpy.arange(base_freq, base_freq + n_channels * freq_delta, freq_delta) + lowest_frequency = base_freq - numpy.floor(n_channels/2) * freq_delta + self.hop_sequence = [lowest_frequency + n * freq_delta for n in xrange(n_channels)] numpy.random.shuffle(self.hop_sequence) + # Repeat that: self.hop_sequence = [self.hop_sequence[x % n_channels] for x in xrange(n_bursts)] if verbose: print "Hop Frequencies | Hop Pattern" @@ -103,20 +106,19 @@ class FrequencyHopperSrc(gr.hier_block2): gain_tag = gr.tag_t() gain_tag.offset = 0 gain_tag.key = pmt.string_to_symbol('tx_command') - gain_tag.value = pmt.cons( - pmt.intern("gain"), - # These are both valid: - #pmt.from_double(tx_gain) - pmt.cons(pmt.to_pmt(0), pmt.to_pmt(tx_gain)) - ) + gain_tag.value = pmt.to_pmt({'gain': tx_gain}) tag_list = [gain_tag,] - for i in xrange(n_bursts): + for i in xrange(len(self.hop_sequence)): tune_tag = gr.tag_t() tune_tag.offset = i * burst_length - if i > 0 and post_tuning: + if i > 0 and post_tuning and not dsp_tuning: # TODO dsp_tuning should also be able to do post_tuning tune_tag.offset -= 1 # Move it to last sample of previous burst - tune_tag.key = pmt.string_to_symbol('tx_freq') - tune_tag.value = pmt.to_pmt(self.hop_sequence[i]) + if dsp_tuning: + tune_tag.key = pmt.string_to_symbol('tx_command') + tune_tag.value = pmt.to_pmt({'lo_freq': base_freq, 'dsp_freq': base_freq - self.hop_sequence[i]}) + else: + tune_tag.key = pmt.string_to_symbol('tx_freq') + tune_tag.value = pmt.to_pmt(self.hop_sequence[i]) tag_list.append(tune_tag) length_tag = gr.tag_t() length_tag.offset = i * burst_length @@ -164,7 +166,7 @@ class FlowGraph(gr.top_block): raise SystemExit, 1 hopper_block = FrequencyHopperSrc( options.num_bursts, options.num_channels, - options.freq_delta, options.freq, + options.freq_delta, options.freq, options.dsp, options.samp_per_burst, 1.0, options.hop_time / 1000., options.post_tuning, options.gain, @@ -202,7 +204,7 @@ def main(): args = setup_parser().parse_args() if (1.0 * args.samp_per_burst / args.rate) > args.hop_time * 1e-3: print "Burst duration must be smaller than hop time." - raise SystemExit, 1 + exit(1) if args.verbose: print_hopper_stats(args) top_block = FlowGraph(args) diff --git a/gr-uhd/examples/python/usrp_spectrum_sense.py b/gr-uhd/examples/python/usrp_spectrum_sense.py index ba45a2e80e..b1ea6b44d8 100755 --- a/gr-uhd/examples/python/usrp_spectrum_sense.py +++ b/gr-uhd/examples/python/usrp_spectrum_sense.py @@ -33,6 +33,7 @@ import math import struct import threading from datetime import datetime +import time sys.stderr.write("Warning: this may have issues on some machines+Python version combinations to seg fault due to the callback in bin_statitics.\n\n") @@ -271,6 +272,8 @@ def main_loop(tb): bin_start = int(tb.fft_size * ((1 - 0.75) / 2)) bin_stop = int(tb.fft_size - bin_start) + timestamp = 0 + centerfreq = 0 while 1: # Get the next message sent from the C++ code (blocking call). @@ -282,6 +285,15 @@ def main_loop(tb): # m.raw_data is a string that contains the binary floats. # You could write this as binary to a file. + # Scanning rate + if timestamp == 0: + timestamp = time.time() + centerfreq = m.center_freq + if m.center_freq < centerfreq: + sys.stderr.write("scanned %.1fMHz in %.1fs\n" % ((centerfreq - m.center_freq)/1.0e6, time.time() - timestamp)) + timestamp = time.time() + centerfreq = m.center_freq + for i_bin in range(bin_start, bin_stop): center_freq = m.center_freq diff --git a/gr-uhd/grc/gen_uhd_usrp_blocks.py b/gr-uhd/grc/gen_uhd_usrp_blocks.py index fda1b9dfd7..72f1b50135 100644 --- a/gr-uhd/grc/gen_uhd_usrp_blocks.py +++ b/gr-uhd/grc/gen_uhd_usrp_blocks.py @@ -23,7 +23,7 @@ MAIN_TMPL = """\ <block> <name>UHD: USRP $sourk.title()</name> <key>uhd_usrp_$(sourk)</key> - <throttle>1</throttle> + <flags>throttle</flags> <import>from gnuradio import uhd</import> <import>import time</import> <make>uhd.usrp_$(sourk)( diff --git a/gr-uhd/include/gnuradio/uhd/CMakeLists.txt b/gr-uhd/include/gnuradio/uhd/CMakeLists.txt index 71c17b89cd..b1f3345d78 100644 --- a/gr-uhd/include/gnuradio/uhd/CMakeLists.txt +++ b/gr-uhd/include/gnuradio/uhd/CMakeLists.txt @@ -22,6 +22,7 @@ ######################################################################## install(FILES api.h + usrp_block.h usrp_source.h usrp_sink.h amsg_source.h diff --git a/gr-uhd/include/gnuradio/uhd/usrp_block.h b/gr-uhd/include/gnuradio/uhd/usrp_block.h new file mode 100644 index 0000000000..d57e1d24cb --- /dev/null +++ b/gr-uhd/include/gnuradio/uhd/usrp_block.h @@ -0,0 +1,564 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 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_UHD_USRP_BLOCK_H +#define INCLUDED_GR_UHD_USRP_BLOCK_H + +#include <gnuradio/uhd/api.h> +#include <gnuradio/sync_block.h> +#include <uhd/usrp/multi_usrp.hpp> + +namespace gr { + namespace uhd { + + /*! Base class for USRP blocks. + * \ingroup uhd_blk + * + * Note that many of the functions defined here differ between + * Rx and Tx configurations. As an example, set_center_freq() + * will set the Rx frequency for a usrp_source object, and the + * Tx frequency on a usrp_sink object. + */ + class GR_UHD_API usrp_block : public gr::sync_block + { + protected: + usrp_block() {}; // For virtual sub-classing + usrp_block(const std::string &name, + gr::io_signature::sptr input_signature, + gr::io_signature::sptr output_signature); + public: + + /*! + * Set the frontend specification. + * + * \param spec the subdev spec markup string + * \param mboard the motherboard index 0 to M-1 + */ + virtual void set_subdev_spec(const std::string &spec, size_t mboard = 0) = 0; + + /*! + * Get the frontend specification. + * + * \param mboard the motherboard index 0 to M-1 + * \return the frontend specification in use + */ + virtual std::string get_subdev_spec(size_t mboard = 0) = 0; + + /*! + * Set the sample rate for this connection to the USRP. + * + * \param rate a new rate in Sps + */ + virtual void set_samp_rate(double rate) = 0; + + /*! + * Get the sample rate for this connection to the USRP. + * This is the actual sample rate and may differ from the rate set. + * + * \return the actual rate in Sps + */ + virtual double get_samp_rate(void) = 0; + + /*! + * Get the possible sample rates for this connection. + * + * \return a range of rates in Sps + */ + virtual ::uhd::meta_range_t get_samp_rates(void) = 0; + + /*! + * Tune the selected channel to the desired center frequency. + * + * \param tune_request the tune request instructions + * \param chan the channel index 0 to N-1 + * \return a tune result with the actual frequencies + */ + virtual ::uhd::tune_result_t set_center_freq( + const ::uhd::tune_request_t tune_request, + size_t chan = 0 + ) = 0; + + /*! + * Tune the the selected channel to the desired center frequency. + * + * This is a wrapper around set_center_freq() so that in this case, + * the user can pass a single frequency in the call instead of + * having to generate a tune_request_t object. + * + * \param freq the desired frequency in Hz + * \param chan the channel index 0 to N-1 + * \return a tune result with the actual frequencies + */ + ::uhd::tune_result_t set_center_freq(double freq, size_t chan = 0) + { + return set_center_freq(::uhd::tune_request_t(freq), chan); + } + + /*! + * Get the center frequency. + * + * \param chan the channel index 0 to N-1 + * \return the frequency in Hz + */ + virtual double get_center_freq(size_t chan = 0) = 0; + + /*! + * Get the tunable frequency range. + * + * \param chan the channel index 0 to N-1 + * \return the frequency range in Hz + */ + virtual ::uhd::freq_range_t get_freq_range(size_t chan = 0) = 0; + + /*! + * Set the gain for the selected channel. + * + * \param gain the gain in dB + * \param chan the channel index 0 to N-1 + */ + virtual void set_gain(double gain, size_t chan = 0) = 0; + + /*! + * Set the named gain on the dboard. + * + * \param gain the gain in dB + * \param name the name of the gain stage + * \param chan the channel index 0 to N-1 + */ + virtual void set_gain(double gain, + const std::string &name, + size_t chan = 0) = 0; + + /*! + * Set the normalized gain. + * + * The normalized gain is always in [0, 1], regardless of the device. + * 0 corresponds to minimum gain (usually 0 dB, but make sure to read the device + * notes in the UHD manual) and 1 corresponds to maximum gain. + * This will work for any UHD device. Use get_gain() to see which dB value + * the normalized gain value corresponds to. + * + * Note that it is not possible to specify a gain name for this function. + * + * \throws A runtime_error if \p norm_gain is not within the valid range. + * + * \param norm_gain the gain in fractions of the gain range (must be 0 <= norm_gain <= 1) + * \param chan the channel index 0 to N-1 + */ + virtual void set_normalized_gain(double norm_gain, size_t chan = 0) = 0; + + /*! + * Get the actual dboard gain setting. + * + * \param chan the channel index 0 to N-1 + * \return the actual gain in dB + */ + virtual double get_gain(size_t chan = 0) = 0; + + /*! + * Get the actual dboard gain setting of named stage. + * + * \param name the name of the gain stage + * \param chan the channel index 0 to N-1 + * \return the actual gain in dB + */ + virtual double get_gain(const std::string &name, + size_t chan = 0) = 0; + + /*! + * Returns the normalized gain. + * + * The normalized gain is always in [0, 1], regardless of the device. + * See also set_normalized_gain(). + * + * Note that it is not possible to specify a gain name for + * this function, the result is over the entire gain chain. + * + * \param chan the channel index 0 to N-1 + */ + virtual double get_normalized_gain(size_t chan = 0) = 0; + + /*! + * Get the actual dboard gain setting of named stage. + * + * \param chan the channel index 0 to N-1 + * \return the actual gain in dB + */ + virtual std::vector<std::string> get_gain_names(size_t chan = 0) = 0; + + /*! + * Get the settable gain range. + * + * \param chan the channel index 0 to N-1 + * \return the gain range in dB + */ + virtual ::uhd::gain_range_t get_gain_range(size_t chan = 0) = 0; + + /*! + * Get the settable gain range. + * + * \param name the name of the gain stage + * \param chan the channel index 0 to N-1 + * \return the gain range in dB + */ + virtual ::uhd::gain_range_t get_gain_range(const std::string &name, + size_t chan = 0) = 0; + + /*! + * Set the antenna to use for a given channel. + * + * \param ant the antenna string + * \param chan the channel index 0 to N-1 + */ + virtual void set_antenna(const std::string &ant, + size_t chan = 0) = 0; + + /*! + * Get the antenna in use. + * + * \param chan the channel index 0 to N-1 + * \return the antenna string + */ + virtual std::string get_antenna(size_t chan = 0) = 0; + + /*! + * Get a list of possible antennas on a given channel. + * + * \param chan the channel index 0 to N-1 + * \return a vector of antenna strings + */ + virtual std::vector<std::string> get_antennas(size_t chan = 0) = 0; + + /*! + * Set the bandpass filter on the RF frontend. + * + * \param bandwidth the filter bandwidth in Hz + * \param chan the channel index 0 to N-1 + */ + virtual void set_bandwidth(double bandwidth, size_t chan = 0) = 0; + + /*! + * Get the bandpass filter setting on the RF frontend. + * + * \param chan the channel index 0 to N-1 + * \return bandwidth of the filter in Hz + */ + virtual double get_bandwidth(size_t chan = 0) = 0; + + /*! + * Get the bandpass filter range of the RF frontend. + * + * \param chan the channel index 0 to N-1 + * \return the range of the filter bandwidth in Hz + */ + virtual ::uhd::freq_range_t get_bandwidth_range(size_t chan = 0) = 0; + + /*! + * Get an RF frontend sensor value. + * \param name the name of the sensor + * \param chan the channel index 0 to N-1 + * \return a sensor value object + */ + virtual ::uhd::sensor_value_t get_sensor(const std::string &name, + size_t chan = 0) = 0; + + /*! + * Get a list of possible RF frontend sensor names. + * \param chan the channel index 0 to N-1 + * \return a vector of sensor names + */ + virtual std::vector<std::string> get_sensor_names(size_t chan = 0) = 0; + + //! DEPRECATED use get_sensor + ::uhd::sensor_value_t get_dboard_sensor(const std::string &name, + size_t chan = 0) + { + return this->get_sensor(name, chan); + } + + //! DEPRECATED use get_sensor_names + std::vector<std::string> get_dboard_sensor_names(size_t chan = 0) + { + return this->get_sensor_names(chan); + } + + /*! + * Get a motherboard sensor value. + * + * \param name the name of the sensor + * \param mboard the motherboard index 0 to M-1 + * \return a sensor value object + */ + virtual ::uhd::sensor_value_t get_mboard_sensor(const std::string &name, + size_t mboard = 0) = 0; + + /*! + * Get a list of possible motherboard sensor names. + * + * \param mboard the motherboard index 0 to M-1 + * \return a vector of sensor names + */ + virtual std::vector<std::string> get_mboard_sensor_names(size_t mboard = 0) = 0; + + /*! + * Get the currently set time source. + * + * \param mboard which motherboard to get the config + * \return the string representing the time source + */ + virtual std::string get_time_source(const size_t mboard) = 0; + + /*! + * Get a list of possible time sources. + * + * \param mboard which motherboard to get the list + * \return a vector of strings for possible settings + */ + virtual std::vector<std::string> get_time_sources(const size_t mboard) = 0; + + /*! + * Set the clock source for the usrp device. + * + * This sets the source for a 10 MHz reference clock. + * Typical options for source: internal, external, MIMO. + * + * \param source a string representing the clock source + * \param mboard which motherboard to set the config + */ + virtual void set_clock_source(const std::string &source, + const size_t mboard = 0) = 0; + + /*! + * Get the currently set clock source. + * + * \param mboard which motherboard to get the config + * \return the string representing the clock source + */ + virtual std::string get_clock_source(const size_t mboard) = 0; + + /*! + * Get a list of possible clock sources. + * + * \param mboard which motherboard to get the list + * \return a vector of strings for possible settings + */ + virtual std::vector<std::string> get_clock_sources(const size_t mboard) = 0; + + /*! + * Get the master clock rate. + * + * \param mboard the motherboard index 0 to M-1 + * \return the clock rate in Hz + */ + virtual double get_clock_rate(size_t mboard = 0) = 0; + + /*! + * Set the master clock rate. + * + * \param rate the new rate in Hz + * \param mboard the motherboard index 0 to M-1 + */ + virtual void set_clock_rate(double rate, size_t mboard = 0) = 0; + + /*! + * Get the current time registers. + * + * \param mboard the motherboard index 0 to M-1 + * \return the current usrp time + */ + virtual ::uhd::time_spec_t get_time_now(size_t mboard = 0) = 0; + + /*! + * Get the time when the last pps pulse occured. + * \param mboard the motherboard index 0 to M-1 + * \return the current usrp time + */ + virtual ::uhd::time_spec_t get_time_last_pps(size_t mboard = 0) = 0; + + /*! + * Sets the time registers immediately. + * \param time_spec the new time + * \param mboard the motherboard index 0 to M-1 + */ + virtual void set_time_now(const ::uhd::time_spec_t &time_spec, size_t mboard = 0) = 0; + + /*! + * Set the time registers at the next pps. + * \param time_spec the new time + */ + virtual void set_time_next_pps(const ::uhd::time_spec_t &time_spec) = 0; + + /*! + * Sync the time registers with an unknown pps edge. + * \param time_spec the new time + */ + virtual void set_time_unknown_pps(const ::uhd::time_spec_t &time_spec) = 0; + + /*! + * Set the time at which the control commands will take effect. + * + * A timed command will back-pressure all subsequent timed commands, + * assuming that the subsequent commands occur within the time-window. + * If the time spec is late, the command will be activated upon arrival. + * + * \param time_spec the time at which the next command will activate + * \param mboard which motherboard to set the config + */ + virtual void set_command_time(const ::uhd::time_spec_t &time_spec, + size_t mboard = 0) = 0; + + /*! + * Clear the command time so future commands are sent ASAP. + * + * \param mboard which motherboard to set the config + */ + virtual void clear_command_time(size_t mboard = 0) = 0; + + /*! + * Get access to the underlying uhd dboard iface object. + * + * \return the dboard_iface object + */ + virtual ::uhd::usrp::dboard_iface::sptr get_dboard_iface(size_t chan = 0) = 0; + + /*! + * Get access to the underlying uhd device object. + * + * NOTE: This function is only available in C++. + * \return the multi usrp device object + */ + virtual ::uhd::usrp::multi_usrp::sptr get_device(void) = 0; + + /*! + * Perform write on the user configuration register bus. These + * only exist if the user has implemented custom setting + * registers in the device FPGA. + * + * \param addr 8-bit register address + * \param data 32-bit register value + * \param mboard which motherboard to set the user register + */ + virtual void set_user_register(const uint8_t addr, + const uint32_t data, + size_t mboard = 0) = 0; + + /*! + * Set the clock configuration. + * + * DEPRECATED for set_time/clock_source. + * \param clock_config the new configuration + * \param mboard the motherboard index 0 to M-1 + */ + virtual void set_clock_config(const ::uhd::clock_config_t &clock_config, + size_t mboard = 0) = 0; + + /*! + * Set the time source for the USRP device. + * + * This sets the method of time synchronization, + * typically a pulse per second or an encoded time. + * Typical options for source: external, MIMO. + * \param source a string representing the time source + * \param mboard which motherboard to set the config + */ + virtual void set_time_source(const std::string &source, + const size_t mboard = 0) = 0; + + /*! + * Update the stream args for this device. + * + * This update will only take effect after a restart of the + * streaming, or before streaming and after construction. + * This will also delete the current streamer. + * Note you cannot change the I/O signature of this block using + * this function, or it will throw. + * + * It is possible to leave the 'channels' fields of \p stream_args + * unset. In this case, the previous channels field is used. + * + * \param stream_args New stream args. + * \throws std::runtime_error if new settings are invalid. + */ + virtual void set_stream_args(const ::uhd::stream_args_t &stream_args) = 0; + + /******************************************************************* + * GPIO methods + ******************************************************************/ + /*! + * Enumerate GPIO banks on the current device. + * \param mboard the motherboard index 0 to M-1 + * \return a list of string for each bank name + */ + virtual std::vector<std::string> get_gpio_banks(const size_t mboard) = 0; + + /*! + * Set a GPIO attribute on a particular GPIO bank. + * Possible attribute names: + * - CTRL - 1 for ATR mode 0 for GPIO mode + * - DDR - 1 for output 0 for input + * - OUT - GPIO output level (not ATR mode) + * - ATR_0X - ATR idle state + * - ATR_RX - ATR receive only state + * - ATR_TX - ATR transmit only state + * - ATR_XX - ATR full duplex state + * \param bank the name of a GPIO bank + * \param attr the name of a GPIO attribute + * \param value the new value for this GPIO bank + * \param mask the bit mask to effect which pins are changed + * \param mboard the motherboard index 0 to M-1 + */ + virtual void set_gpio_attr( + const std::string &bank, + const std::string &attr, + const boost::uint32_t value, + const boost::uint32_t mask = 0xffffffff, + const size_t mboard = 0 + ) = 0; + + /*! + * Get a GPIO attribute on a particular GPIO bank. + * Possible attribute names: + * - CTRL - 1 for ATR mode 0 for GPIO mode + * - DDR - 1 for output 0 for input + * - OUT - GPIO output level (not ATR mode) + * - ATR_0X - ATR idle state + * - ATR_RX - ATR receive only state + * - ATR_TX - ATR transmit only state + * - ATR_XX - ATR full duplex state + * - READBACK - readback input GPIOs + * \param bank the name of a GPIO bank + * \param attr the name of a GPIO attribute + * \param mboard the motherboard index 0 to M-1 + * \return the value set for this attribute + */ + virtual boost::uint32_t get_gpio_attr( + const std::string &bank, + const std::string &attr, + const size_t mboard = 0 + ) = 0; + + }; + + } /* namespace uhd */ +} /* namespace gr */ + +#endif /* INCLUDED_GR_UHD_USRP_BLOCK_H */ diff --git a/gr-uhd/include/gnuradio/uhd/usrp_sink.h b/gr-uhd/include/gnuradio/uhd/usrp_sink.h index dd1bd6a73a..4ccb83f595 100644 --- a/gr-uhd/include/gnuradio/uhd/usrp_sink.h +++ b/gr-uhd/include/gnuradio/uhd/usrp_sink.h @@ -23,9 +23,7 @@ #ifndef INCLUDED_GR_UHD_USRP_SINK_H #define INCLUDED_GR_UHD_USRP_SINK_H -#include <gnuradio/uhd/api.h> -#include <gnuradio/sync_block.h> -#include <uhd/usrp/multi_usrp.hpp> +#include <gnuradio/uhd/usrp_block.h> // TODO In 3.8, UHD 3.4 will be required and we can remove all these ifdefs #ifndef INCLUDED_UHD_STREAM_HPP @@ -54,7 +52,72 @@ namespace gr { class uhd_usrp_sink; - class GR_UHD_API usrp_sink : virtual public sync_block + /*! USRP Sink -- Radio Transmitter + * \ingroup uhd_blk + * + * + * The USRP sink block reads a stream and transmits the samples. + * The sink block also provides API calls for transmitter settings. + * See also gr::uhd::usrp_block for more public API calls. + * + * \section uhd_tx_tagging TX Stream tagging + * + * The following tag keys will be consumed by the work function: + * - pmt::string_to_symbol("tx_sob") + * - pmt::string_to_symbol("tx_eob") + * - pmt::string_to_symbol("tx_time") + * - pmt::string_to_symbol("tx_freq") + * - pmt::string_to_symbol("tx_command") + * - pmt::string_to_symbol(tsb_tag_name) + * + * Any other tag will be ignored. + * + * \section uhd_tx_burstys Bursty Transmission + * + * There are multiple ways to do bursty transmission without triggering + * underruns: + * - Using SOB/EOB tags + * - Using tagged streams (See \ref page_tagged_stream_blocks) + * + * The sob and eob (start and end of burst) tag values are pmt booleans. + * When present, burst tags should be set to true (pmt::PMT_T). + * + * If `tsb_tag_name` is not an empty string, all "tx_sob" and "tx_eob" + * tags will be ignored, and the input is assumed to a tagged stream. + * + * If sob/eob tags or length tags are used, this block understands that + * the data is bursty, and will configure the USRP to make sure there's + * no underruns after transmitting the final sample of a burst. + * + * \section uhd_tx_time Timestamps + * + * The timestamp tag value is a PMT tuple of the following: + * (uint64 seconds, double fractional seconds). + * + * The tx_freq tag has to be a double or a pair of form (channel, frequency), + * with frequency being a double and channel being an integer. + * This tag will trigger a tune command to the USRP + * to the given frequency, if possible. Note that oscillators need some time + * to stabilize after this! Don't expect clean data to be sent immediately after this command. + * If channel is omitted, and only a double is given, it will set this frequency to all + * channels. + * + * The command tag can carry a PMT command. See the following section. + * + * \section uhd_tx_commands Command interface + * + * There are two ways of passing commands to this block: + * 1. tx_command tag. The command is attached to a sample, and will executed + * before the sample is transmitted, and after the previous sample. + * 2. The 'command' message port. The command is executed asynchronously, + * as soon as possible. + * + * In both cases, the payload of the command is a PMT command, as described + * in Section \ref uhd_command_syntax. + * + * For a more general description of the gr-uhd components, see \ref page_uhd. + */ + class GR_UHD_API usrp_sink : virtual public usrp_block { public: // gr::uhd::usrp_sink::sptr @@ -68,64 +131,10 @@ namespace gr { * gr::uhd::usrp_sink::make(const ::uhd::device_addr_t, const ::uhd::stream_args_t, const std::string). */ static sptr make(const ::uhd::device_addr_t &device_addr, - const ::uhd::io_type_t &io_type, - size_t num_channels); + const ::uhd::io_type_t &io_type, + size_t num_channels); /*! - * \brief Make a new USRP sink block (usually a radio transmitter). - * - * The USRP sink block reads a stream and transmits the samples. - * The sink block also provides API calls for transmitter settings. - * - * \section uhd_tx_tagging TX Stream tagging - * - * The following tag keys will be consumed by the work function: - * - pmt::string_to_symbol("tx_sob") - * - pmt::string_to_symbol("tx_eob") - * - pmt::string_to_symbol("tx_time") - * - pmt::string_to_symbol("tx_freq") - * - pmt::string_to_symbol("tx_command") - * - pmt::string_to_symbol(tsb_tag_name) - * - * Any other tag will be ignored. - * - * The sob and eob (start and end of burst) tag values are pmt booleans. - * When present, burst tags should be set to true (pmt::PMT_T). - * - * If `tsb_tag_name` is not an empty string, all "tx_sob" and "tx_eob" - * tags will be ignored, and the input is assumed to a tagged stream, - * as described in \ref page_tagged_stream_blocks. - * - * If sob/eob tags or length tags are used, this block understands that - * the data is bursty, and will configure the USRP to make sure there's - * no underruns after transmitting the final sample of a burst. - * - * The timestamp tag value is a PMT tuple of the following: - * (uint64 seconds, double fractional seconds). - * - * The tx_freq tag has to be a double or a pair of form (channel, frequency), - * with frequency being a double and channel being an integer. - * This tag will trigger a tune command to the USRP - * to the given frequency, if possible. Note that oscillators need some time - * to stabilize after this! Don't expect clean data to be sent immediately after this command. - * If channel is omitted, and only a double is given, it will set this frequency to all - * channels. - * - * The command tag can carry a PMT command. See the following section. - * - * \section uhd_tx_commands Command interface - * - * There are two ways of passing commands to this block: - * 1. tx_command tag. The command is attached to a sample, and will executed - * before the sample is transmitted, and after the previous sample. - * 2. The 'command' message port. The command is executed asynchronously, - * as soon as possible. - * - * In both cases, the payload of the command is a PMT command, as described - * in Section \ref uhd_command_syntax. - * - * For a more general description of the gr-uhd components, see \ref page_uhd. - * * \param device_addr the address to identify the hardware * \param stream_args the IO format and channel specification * \param tsb_tag_name the name of the tag identifying tagged stream length @@ -158,205 +167,6 @@ namespace gr { virtual ::uhd::dict<std::string, std::string> get_usrp_info(size_t chan = 0) = 0; /*! - * Set the frontend specification. - * \param spec the subdev spec markup string - * \param mboard the motherboard index 0 to M-1 - */ - virtual void set_subdev_spec(const std::string &spec, size_t mboard = 0) = 0; - - /*! - * Get the TX frontend specification. - * \param mboard the motherboard index 0 to M-1 - * \return the frontend specification in use - */ - virtual std::string get_subdev_spec (size_t mboard = 0) = 0; - - /*! - * Set the sample rate for the usrp device. - * \param rate a new rate in Sps - */ - virtual void set_samp_rate(double rate) = 0; - - /*! - * Get the sample rate for the usrp device. - * This is the actual sample rate and may differ from the rate set. - * \return the actual rate in Sps - */ - virtual double get_samp_rate(void) = 0; - - /*! - * Get the possible sample rates for the usrp device. - * \return a range of rates in Sps - */ - virtual ::uhd::meta_range_t get_samp_rates(void) = 0; - - /*! - * Tune the usrp device to the desired center frequency. - * \param tune_request the tune request instructions - * \param chan the channel index 0 to N-1 - * \return a tune result with the actual frequencies - */ - virtual ::uhd::tune_result_t set_center_freq - (const ::uhd::tune_request_t tune_request, size_t chan = 0) = 0; - - /*! - * Tune the usrp device to the desired center frequency. - * This is a wrapper around set center freq so that in this case, - * the user can pass a single frequency in the call through swig. - * \param freq the desired frequency in Hz - * \param chan the channel index 0 to N-1 - * \return a tune result with the actual frequencies - */ - ::uhd::tune_result_t set_center_freq(double freq, size_t chan = 0) - { - return set_center_freq(::uhd::tune_request_t(freq), chan); - } - - /*! - * Get the center frequency. - * \param chan the channel index 0 to N-1 - * \return the frequency in Hz - */ - virtual double get_center_freq(size_t chan = 0) = 0; - - /*! - * Get the tunable frequency range. - * \param chan the channel index 0 to N-1 - * \return the frequency range in Hz - */ - virtual ::uhd::freq_range_t get_freq_range(size_t chan = 0) = 0; - - /*! - * Set the gain for the dboard. - * \param gain the gain in dB - * \param chan the channel index 0 to N-1 - */ - virtual void set_gain(double gain, size_t chan = 0) = 0; - - /*! - * Set the named gain on the dboard. - * \param gain the gain in dB - * \param name the name of the gain stage - * \param chan the channel index 0 to N-1 - */ - virtual void set_gain(double gain, - const std::string &name, - size_t chan = 0) = 0; - - /*! - * Set the normalized gain. - * - * The normalized gain is always in [0, 1], regardless of the device. - * 0 corresponds to minimum gain (usually 0 dB, but make sure to read the device - * notes in the UHD manual) and 1 corresponds to maximum gain. - * This will work for any UHD device. Use get_gain() to see which dB value - * the normalized gain value corresponds to. - * - * Note that it is not possible to specify a gain name for this function. - * - * \throws A runtime_error if \p norm_gain is not within the valid range. - * - * \param norm_gain the gain in fractions of the gain range (must be 0 <= norm_gain <= 1) - * \param chan the channel index 0 to N-1 - */ - virtual void set_normalized_gain(double norm_gain, size_t chan = 0) = 0; - - /*! - * Get the actual dboard gain setting. - * \param chan the channel index 0 to N-1 - * \return the actual gain in dB - */ - virtual double get_gain(size_t chan = 0) = 0; - - /*! - * Get the actual dboard gain setting of named stage. - * \param name the name of the gain stage - * \param chan the channel index 0 to N-1 - * \return the actual gain in dB - */ - virtual double get_gain(const std::string &name, - size_t chan = 0) = 0; - - /*! - * Returns the normalized gain. - * - * The normalized gain is always in [0, 1], regardless of the device. - * See also set_normalized_gain(). - * - * Note that it is not possible to specify a gain name for this function, - * the result is over the entire gain chain. - * - * \param chan the channel index 0 to N-1 - */ - virtual double get_normalized_gain(size_t chan = 0) = 0; - - /*! - * Get the actual dboard gain setting of named stage. - * \param chan the channel index 0 to N-1 - * \return the actual gain in dB - */ - virtual std::vector<std::string> get_gain_names(size_t chan = 0) = 0; - - /*! - * Get the settable gain range. - * \param chan the channel index 0 to N-1 - * \return the gain range in dB - */ - virtual ::uhd::gain_range_t get_gain_range(size_t chan = 0) = 0; - - /*! - * Get the settable gain range. - * \param name the name of the gain stage - * \param chan the channel index 0 to N-1 - * \return the gain range in dB - */ - virtual ::uhd::gain_range_t get_gain_range(const std::string &name, - size_t chan = 0) = 0; - - /*! - * Set the antenna to use. - * \param ant the antenna string - * \param chan the channel index 0 to N-1 - */ - virtual void set_antenna(const std::string &ant, - size_t chan = 0) = 0; - - /*! - * Get the antenna in use. - * \param chan the channel index 0 to N-1 - * \return the antenna string - */ - virtual std::string get_antenna(size_t chan = 0) = 0; - - /*! - * Get a list of possible antennas. - * \param chan the channel index 0 to N-1 - * \return a vector of antenna strings - */ - virtual std::vector<std::string> get_antennas(size_t chan = 0) = 0; - - /*! - * Set the bandpass filter on the RF frontend. - * \param bandwidth the filter bandwidth in Hz - * \param chan the channel index 0 to N-1 - */ - virtual void set_bandwidth(double bandwidth, size_t chan = 0) = 0; - - /*! - * Get the bandpass filter setting on the RF frontend. - * \param chan the channel index 0 to N-1 - * \return bandwidth of the filter in Hz - */ - virtual double get_bandwidth(size_t chan = 0) = 0; - - /*! - * Get the bandpass filter range of the RF frontend. - * \param chan the channel index 0 to N-1 - * \return the range of the filter bandwidth in Hz - */ - virtual ::uhd::freq_range_t get_bandwidth_range(size_t chan = 0) = 0; - - /*! * Set a constant DC offset value. * The value is complex to control both I and Q. * \param offset the dc offset (1.0 is full-scale) @@ -375,218 +185,6 @@ namespace gr { virtual void set_iq_balance(const std::complex<double> &correction, size_t chan = 0) = 0; - /*! - * Get an RF frontend sensor value. - * \param name the name of the sensor - * \param chan the channel index 0 to N-1 - * \return a sensor value object - */ - virtual ::uhd::sensor_value_t get_sensor(const std::string &name, - size_t chan = 0) = 0; - - /*! - * Get a list of possible RF frontend sensor names. - * \param chan the channel index 0 to N-1 - * \return a vector of sensor names - */ - virtual std::vector<std::string> get_sensor_names(size_t chan = 0) = 0; - - //! DEPRECATED use get_sensor - ::uhd::sensor_value_t get_dboard_sensor(const std::string &name, - size_t chan = 0) - { - return this->get_sensor(name, chan); - } - - //! DEPRECATED use get_sensor_names - std::vector<std::string> get_dboard_sensor_names(size_t chan = 0) - { - return this->get_sensor_names(chan); - } - - /*! - * Get a motherboard sensor value. - * \param name the name of the sensor - * \param mboard the motherboard index 0 to M-1 - * \return a sensor value object - */ - virtual ::uhd::sensor_value_t get_mboard_sensor(const std::string &name, - size_t mboard = 0) = 0; - - /*! - * Get a list of possible motherboard sensor names. - * \param mboard the motherboard index 0 to M-1 - * \return a vector of sensor names - */ - virtual std::vector<std::string> get_mboard_sensor_names(size_t mboard = 0) = 0; - - /*! - * Set the clock configuration. - * DEPRECATED for set_time/clock_source. - * \param clock_config the new configuration - * \param mboard the motherboard index 0 to M-1 - */ - virtual void set_clock_config(const ::uhd::clock_config_t &clock_config, - size_t mboard = 0) = 0; - - /*! - * Set the time source for the usrp device. - * This sets the method of time synchronization, - * typically a pulse per second or an encoded time. - * Typical options for source: external, MIMO. - * \param source a string representing the time source - * \param mboard which motherboard to set the config - */ - virtual void set_time_source(const std::string &source, - const size_t mboard = 0) = 0; - - /*! - * Get the currently set time source. - * \param mboard which motherboard to get the config - * \return the string representing the time source - */ - virtual std::string get_time_source(const size_t mboard) = 0; - - /*! - * Get a list of possible time sources. - * \param mboard which motherboard to get the list - * \return a vector of strings for possible settings - */ - virtual std::vector<std::string> get_time_sources(const size_t mboard) = 0; - - /*! - * Set the clock source for the usrp device. - * This sets the source for a 10 Mhz reference clock. - * Typical options for source: internal, external, MIMO. - * \param source a string representing the clock source - * \param mboard which motherboard to set the config - */ - virtual void set_clock_source(const std::string &source, - const size_t mboard = 0) = 0; - - /*! - * Get the currently set clock source. - * \param mboard which motherboard to get the config - * \return the string representing the clock source - */ - virtual std::string get_clock_source(const size_t mboard) = 0; - - /*! - * Get a list of possible clock sources. - * \param mboard which motherboard to get the list - * \return a vector of strings for possible settings - */ - virtual std::vector<std::string> get_clock_sources(const size_t mboard) = 0; - - /*! - * Get the master clock rate. - * \param mboard the motherboard index 0 to M-1 - * \return the clock rate in Hz - */ - virtual double get_clock_rate(size_t mboard = 0) = 0; - - /*! - * Set the master clock rate. - * \param rate the new rate in Hz - * \param mboard the motherboard index 0 to M-1 - */ - virtual void set_clock_rate(double rate, size_t mboard = 0) = 0; - - /*! - * Get the current time registers. - * \param mboard the motherboard index 0 to M-1 - * \return the current usrp time - */ - virtual ::uhd::time_spec_t get_time_now(size_t mboard = 0) = 0; - - /*! - * Get the time when the last pps pulse occured. - * \param mboard the motherboard index 0 to M-1 - * \return the current usrp time - */ - virtual ::uhd::time_spec_t get_time_last_pps(size_t mboard = 0) = 0; - - /*! - * Sets the time registers immediately. - * \param time_spec the new time - * \param mboard the motherboard index 0 to M-1 - */ - virtual void set_time_now(const ::uhd::time_spec_t &time_spec, size_t mboard = 0) = 0; - - /*! - * Set the time registers at the next pps. - * \param time_spec the new time - */ - virtual void set_time_next_pps(const ::uhd::time_spec_t &time_spec) = 0; - - /*! - * Sync the time registers with an unknown pps edge. - * \param time_spec the new time - */ - virtual void set_time_unknown_pps(const ::uhd::time_spec_t &time_spec) = 0; - - /*! - * Set the time at which the control commands will take effect. - * - * A timed command will back-pressure all subsequent timed commands, - * assuming that the subsequent commands occur within the time-window. - * If the time spec is late, the command will be activated upon arrival. - * - * \param time_spec the time at which the next command will activate - * \param mboard which motherboard to set the config - */ - virtual void set_command_time(const ::uhd::time_spec_t &time_spec, - size_t mboard = 0) = 0; - - /*! - * Clear the command time so future commands are sent ASAP. - * - * \param mboard which motherboard to set the config - */ - virtual void clear_command_time(size_t mboard = 0) = 0; - - /*! - * Get access to the underlying uhd dboard iface object. - * \return the dboard_iface object - */ - virtual ::uhd::usrp::dboard_iface::sptr get_dboard_iface(size_t chan = 0) = 0; - - /*! - * Get access to the underlying uhd device object. - * - * NOTE: This function is only available in C++. - * \return the multi usrp device object - */ - virtual ::uhd::usrp::multi_usrp::sptr get_device(void) = 0; - - /*! - * Perform write on the user configuration register bus. These - * only exist if the user has implemented custom setting - * registers in the device FPGA. - * \param addr 8-bit register address - * \param data 32-bit register value - * \param mboard which motherboard to set the user register - */ - virtual void set_user_register(const uint8_t addr, - const uint32_t data, - size_t mboard = 0) = 0; - - /*! - * Update the stream args for this device. - * - * This update will only take effect after a restart of the - * streaming, or before streaming and after construction. - * This will also delete the current streamer. - * Note you cannot change the I/O signature of this block using - * this function, or it will throw. - * - * It is possible to leave the 'channels' fields of \p stream_args - * unset. In this case, the previous channels field is used. - * - * \param stream_args New stream args. - * \throws std::runtime_error if new settings are invalid. - */ - virtual void set_stream_args(const ::uhd::stream_args_t &stream_args) = 0; }; } /* namespace uhd */ diff --git a/gr-uhd/include/gnuradio/uhd/usrp_source.h b/gr-uhd/include/gnuradio/uhd/usrp_source.h index 7da39683d1..19b3feb61f 100644 --- a/gr-uhd/include/gnuradio/uhd/usrp_source.h +++ b/gr-uhd/include/gnuradio/uhd/usrp_source.h @@ -23,11 +23,9 @@ #ifndef INCLUDED_GR_UHD_USRP_SOURCE_H #define INCLUDED_GR_UHD_USRP_SOURCE_H -#include <gnuradio/uhd/api.h> -#include <gnuradio/sync_block.h> -#include <uhd/usrp/multi_usrp.hpp> +#include <gnuradio/uhd/usrp_block.h> -// TODO In 3.8, UHD 3.4 will be required and we can remove all these ifdefs +// TODO In 3.8, UHD 3.6 will be required and we can remove all these ifdefs #ifndef INCLUDED_UHD_STREAM_HPP namespace uhd { struct GR_UHD_API stream_args_t @@ -54,7 +52,31 @@ namespace gr { class uhd_usrp_source; - class GR_UHD_API usrp_source : virtual public sync_block + /*! USRP Source -- Radio Receiver + * \ingroup uhd_blk + * + * The USRP source block receives samples and writes to a stream. + * The source block also provides API calls for receiver settings. + * See also gr::uhd::usrp_block for more public API calls. + * + * RX Stream tagging: + * + * The following tag keys will be produced by the work function: + * - pmt::string_to_symbol("rx_time") + * + * The timestamp tag value is a pmt tuple of the following: + * (uint64 seconds, and double fractional seconds). + * A timestamp tag is produced at start() and after overflows. + * + * \section uhd_rx_command_iface Command interface + * + * This block has a message port, which consumes UHD PMT commands. + * For a description of the command syntax, see Section \ref uhd_command_syntax. + * + * For a more general description of the gr-uhd components, see \ref page_uhd. + * + */ + class GR_UHD_API usrp_source : virtual public usrp_block { public: // gr::uhd::usrp_source::sptr @@ -72,27 +94,6 @@ namespace gr { size_t num_channels); /*! - * \brief Make a new USRP source block (usually a radio receiver). - * - * The USRP source block receives samples and writes to a stream. - * The source block also provides API calls for receiver settings. - * - * RX Stream tagging: - * - * The following tag keys will be produced by the work function: - * - pmt::string_to_symbol("rx_time") - * - * The timestamp tag value is a pmt tuple of the following: - * (uint64 seconds, and double fractional seconds). - * A timestamp tag is produced at start() and after overflows. - * - * \section uhd_rx_command_iface Command interface - * - * This block has a message port, which consumes UHD PMT commands. - * For a description of the command syntax, see Section \ref uhd_command_syntax. - * - * For a more general description of the gr-uhd components, see \ref page_uhd. - * * \param device_addr the address to identify the hardware * \param stream_args the IO format and channel specification * \return a new USRP source block object @@ -137,205 +138,6 @@ namespace gr { virtual ::uhd::dict<std::string, std::string> get_usrp_info(size_t chan = 0) = 0; /*! - * Set the frontend specification. - * \param spec the subdev spec markup string - * \param mboard the motherboard index 0 to M-1 - */ - virtual void set_subdev_spec(const std::string &spec, size_t mboard = 0) = 0; - - /*! - * Get the RX frontend specification. - * \param mboard the motherboard index 0 to M-1 - * \return the frontend specification in use - */ - virtual std::string get_subdev_spec(size_t mboard = 0) = 0; - - /*! - * Set the sample rate for the usrp device. - * \param rate a new rate in Sps - */ - virtual void set_samp_rate(double rate) = 0; - - /*! - * Get the sample rate for the usrp device. - * This is the actual sample rate and may differ from the rate set. - * \return the actual rate in Sps - */ - virtual double get_samp_rate(void) = 0; - - /*! - * Get the possible sample rates for the usrp device. - * \return a range of rates in Sps - */ - virtual ::uhd::meta_range_t get_samp_rates(void) = 0; - - /*! - * Tune the usrp device to the desired center frequency. - * \param tune_request the tune request instructions - * \param chan the channel index 0 to N-1 - * \return a tune result with the actual frequencies - */ - virtual ::uhd::tune_result_t set_center_freq - (const ::uhd::tune_request_t tune_request, size_t chan = 0) = 0; - - /*! - * Tune the usrp device to the desired center frequency. - * This is a wrapper around set center freq so that in this case, - * the user can pass a single frequency in the call through swig. - * \param freq the desired frequency in Hz - * \param chan the channel index 0 to N-1 - * \return a tune result with the actual frequencies - */ - ::uhd::tune_result_t set_center_freq(double freq, size_t chan = 0) - { - return set_center_freq(::uhd::tune_request_t(freq), chan); - } - - /*! - * Get the center frequency. - * \param chan the channel index 0 to N-1 - * \return the frequency in Hz - */ - virtual double get_center_freq(size_t chan = 0) = 0; - - /*! - * Get the tunable frequency range. - * \param chan the channel index 0 to N-1 - * \return the frequency range in Hz - */ - virtual ::uhd::freq_range_t get_freq_range(size_t chan = 0) = 0; - - /*! - * Set the gain for the dboard. - * \param gain the gain in dB - * \param chan the channel index 0 to N-1 - */ - virtual void set_gain(double gain, size_t chan = 0) = 0; - - /*! - * Set the named gain on the dboard. - * \param gain the gain in dB - * \param name the name of the gain stage - * \param chan the channel index 0 to N-1 - */ - virtual void set_gain(double gain, - const std::string &name, - size_t chan = 0) = 0; - - /*! - * Set the normalized gain. - * - * The normalized gain is always in [0, 1], regardless of the device. - * 0 corresponds to minimum gain (usually 0 dB, but make sure to read the device - * notes in the UHD manual) and 1 corresponds to maximum gain. - * This will work for any UHD device. Use get_gain() to see which dB value - * the normalized gain value corresponds to. - * - * Note that it is not possible to specify a gain name for this function. - * - * \throws A runtime_error if \p norm_gain is not within the valid range. - * - * \param norm_gain the gain in fractions of the gain range (must be 0 <= norm_gain <= 1) - * \param chan the channel index 0 to N-1 - */ - virtual void set_normalized_gain(double norm_gain, size_t chan = 0) = 0; - - /*! - * Get the actual dboard gain setting. - * \param chan the channel index 0 to N-1 - * \return the actual gain in dB - */ - virtual double get_gain(size_t chan = 0) = 0; - - /*! - * Get the actual dboard gain setting of named stage. - * \param name the name of the gain stage - * \param chan the channel index 0 to N-1 - * \return the actual gain in dB - */ - virtual double get_gain(const std::string &name, - size_t chan = 0) = 0; - - /*! - * Returns the normalized gain. - * - * The normalized gain is always in [0, 1], regardless of the device. - * See also set_normalized_gain(). - * - * Note that it is not possible to specify a gain name for this function, - * the result is over the entire gain chain. - * - * \param chan the channel index 0 to N-1 - */ - virtual double get_normalized_gain(size_t chan = 0) = 0; - - /*! - * Get the actual dboard gain setting of named stage. - * \param chan the channel index 0 to N-1 - * \return the actual gain in dB - */ - virtual std::vector<std::string> get_gain_names(size_t chan = 0) = 0; - - /*! - * Get the settable gain range. - * \param chan the channel index 0 to N-1 - * \return the gain range in dB - */ - virtual ::uhd::gain_range_t get_gain_range(size_t chan = 0) = 0; - - /*! - * Get the settable gain range. - * \param name the name of the gain stage - * \param chan the channel index 0 to N-1 - * \return the gain range in dB - */ - virtual ::uhd::gain_range_t get_gain_range(const std::string &name, - size_t chan = 0) = 0; - - /*! - * Set the antenna to use. - * \param ant the antenna string - * \param chan the channel index 0 to N-1 - */ - virtual void set_antenna(const std::string &ant, - size_t chan = 0) = 0; - - /*! - * Get the antenna in use. - * \param chan the channel index 0 to N-1 - * \return the antenna string - */ - virtual std::string get_antenna(size_t chan = 0) = 0; - - /*! - * Get a list of possible antennas. - * \param chan the channel index 0 to N-1 - * \return a vector of antenna strings - */ - virtual std::vector<std::string> get_antennas(size_t chan = 0) = 0; - - /*! - * Set the bandpass filter on the RF frontend. - * \param bandwidth the filter bandwidth in Hz - * \param chan the channel index 0 to N-1 - */ - virtual void set_bandwidth(double bandwidth, size_t chan = 0) = 0; - - /*! - * Get the bandpass filter setting on the RF frontend. - * \param chan the channel index 0 to N-1 - * \return bandwidth of the filter in Hz - */ - virtual double get_bandwidth(size_t chan = 0) = 0; - - /*! - * Get the bandpass filter range of the RF frontend. - * \param chan the channel index 0 to N-1 - * \return the range of the filter bandwidth in Hz - */ - virtual ::uhd::freq_range_t get_bandwidth_range(size_t chan = 0) = 0; - - /*! * Enable/disable the automatic DC offset correction. * The automatic correction subtracts out the long-run average. * @@ -377,221 +179,6 @@ namespace gr { size_t chan = 0) = 0; /*! - * Get a RF frontend sensor value. - * \param name the name of the sensor - * \param chan the channel index 0 to N-1 - * \return a sensor value object - */ - virtual ::uhd::sensor_value_t get_sensor(const std::string &name, - size_t chan = 0) = 0; - - /*! - * Get a list of possible RF frontend sensor names. - * \param chan the channel index 0 to N-1 - * \return a vector of sensor names - */ - virtual std::vector<std::string> get_sensor_names(size_t chan = 0) = 0; - - //! DEPRECATED use get_sensor - ::uhd::sensor_value_t get_dboard_sensor(const std::string &name, - size_t chan = 0) - { - return this->get_sensor(name, chan); - } - - //! DEPRECATED use get_sensor_names - std::vector<std::string> get_dboard_sensor_names(size_t chan = 0) - { - return this->get_sensor_names(chan); - } - - /*! - * Get a motherboard sensor value. - * \param name the name of the sensor - * \param mboard the motherboard index 0 to M-1 - * \return a sensor value object - */ - virtual ::uhd::sensor_value_t get_mboard_sensor(const std::string &name, - size_t mboard = 0) = 0; - - /*! - * Get a list of possible motherboard sensor names. - * \param mboard the motherboard index 0 to M-1 - * \return a vector of sensor names - */ - virtual std::vector<std::string> get_mboard_sensor_names(size_t mboard = 0) = 0; - - /*! - * Set the clock configuration. - * DEPRECATED for set_time/clock_source. - * \param clock_config the new configuration - * \param mboard the motherboard index 0 to M-1 - */ - virtual void set_clock_config(const ::uhd::clock_config_t &clock_config, - size_t mboard = 0) = 0; - - /*! - * Set the time source for the usrp device. - * This sets the method of time synchronization, - * typically a pulse per second or an encoded time. - * Typical options for source: external, MIMO. - * \param source a string representing the time source - * \param mboard which motherboard to set the config - */ - virtual void set_time_source(const std::string &source, - const size_t mboard = 0) = 0; - - /*! - * Get the currently set time source. - * \param mboard which motherboard to get the config - * \return the string representing the time source - */ - virtual std::string get_time_source(const size_t mboard) = 0; - - /*! - * Get a list of possible time sources. - * \param mboard which motherboard to get the list - * \return a vector of strings for possible settings - */ - virtual std::vector<std::string> get_time_sources(const size_t mboard) = 0; - - /*! - * Set the clock source for the usrp device. - * This sets the source for a 10 Mhz reference clock. - * Typical options for source: internal, external, MIMO. - * \param source a string representing the clock source - * \param mboard which motherboard to set the config - */ - virtual void set_clock_source(const std::string &source, - const size_t mboard = 0) = 0; - - /*! - * Get the currently set clock source. - * \param mboard which motherboard to get the config - * \return the string representing the clock source - */ - virtual std::string get_clock_source(const size_t mboard) = 0; - - /*! - * Get a list of possible clock sources. - * \param mboard which motherboard to get the list - * \return a vector of strings for possible settings - */ - virtual std::vector<std::string> get_clock_sources(const size_t mboard) = 0; - - /*! - * Get the master clock rate. - * \param mboard the motherboard index 0 to M-1 - * \return the clock rate in Hz - */ - virtual double get_clock_rate(size_t mboard = 0) = 0; - - /*! - * Set the master clock rate. - * \param rate the new rate in Hz - * \param mboard the motherboard index 0 to M-1 - */ - virtual void set_clock_rate(double rate, size_t mboard = 0) = 0; - - /*! - * Get the current time registers. - * \param mboard the motherboard index 0 to M-1 - * \return the current usrp time - */ - virtual ::uhd::time_spec_t get_time_now(size_t mboard = 0) = 0; - - /*! - * Get the time when the last pps pulse occured. - * \param mboard the motherboard index 0 to M-1 - * \return the current usrp time - */ - virtual ::uhd::time_spec_t get_time_last_pps(size_t mboard = 0) = 0; - - /*! - * Sets the time registers immediately. - * \param time_spec the new time - * \param mboard the motherboard index 0 to M-1 - */ - virtual void set_time_now(const ::uhd::time_spec_t &time_spec, - size_t mboard = 0) = 0; - - /*! - * Set the time registers at the next pps. - * \param time_spec the new time - */ - virtual void set_time_next_pps(const ::uhd::time_spec_t &time_spec) = 0; - - /*! - * Sync the time registers with an unknown pps edge. - * \param time_spec the new time - */ - virtual void set_time_unknown_pps(const ::uhd::time_spec_t &time_spec) = 0; - - /*! - * Set the time at which the control commands will take effect. - * - * A timed command will back-pressure all subsequent timed - * commands, assuming that the subsequent commands occur within - * the time-window. If the time spec is late, the command will - * be activated upon arrival. - * - * \param time_spec the time at which the next command will activate - * \param mboard which motherboard to set the config - */ - virtual void set_command_time(const ::uhd::time_spec_t &time_spec, - size_t mboard = 0) = 0; - - /*! - * Clear the command time so future commands are sent ASAP. - * - * \param mboard which motherboard to set the config - */ - virtual void clear_command_time(size_t mboard = 0) = 0; - - /*! - * Get access to the underlying uhd dboard iface object. - * \return the dboard_iface object - */ - virtual ::uhd::usrp::dboard_iface::sptr get_dboard_iface(size_t chan = 0) = 0; - - /*! - * Get access to the underlying uhd device object. - * - * NOTE: This function is only available in C++. - * \return the multi usrp device object - */ - virtual ::uhd::usrp::multi_usrp::sptr get_device(void) = 0; - - /*! - * Perform write on the user configuration register bus. These - * only exist if the user has implemented custom setting - * registers in the device FPGA. - * \param addr 8-bit register address - * \param data 32-bit register value - * \param mboard which motherboard to set the user register - */ - virtual void set_user_register(const uint8_t addr, - const uint32_t data, - size_t mboard = 0) = 0; - - /*! - * Update the stream args for this device. - * - * This update will only take effect after a restart of the - * streaming, or before streaming and after construction. - * This will also delete the current streamer. - * Note you cannot change the I/O signature of this block using - * this function, or it will throw. - * - * It is possible to leave the 'channels' fields of \p stream_args - * unset. In this case, the previous channels field is used. - * - * \param stream_args New stream args. - * \throws std::runtime_error if new settings are invalid. - */ - virtual void set_stream_args(const ::uhd::stream_args_t &stream_args) = 0; - - /*! * Convenience function for finite data acquisition. * This is not to be used with the scheduler; rather, * one can request samples from the USRP in python. diff --git a/gr-uhd/lib/CMakeLists.txt b/gr-uhd/lib/CMakeLists.txt index b3ead137af..531bd40b09 100644 --- a/gr-uhd/lib/CMakeLists.txt +++ b/gr-uhd/lib/CMakeLists.txt @@ -46,6 +46,7 @@ link_directories(${LOG4CPP_LIBRARY_DIRS}) # Setup library ######################################################################## list(APPEND gr_uhd_sources + usrp_block_impl.cc usrp_source_impl.cc usrp_sink_impl.cc amsg_source_impl.cc diff --git a/gr-uhd/lib/usrp_block_impl.cc b/gr-uhd/lib/usrp_block_impl.cc new file mode 100644 index 0000000000..1977b89a3a --- /dev/null +++ b/gr-uhd/lib/usrp_block_impl.cc @@ -0,0 +1,696 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 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. + */ + +#include "usrp_block_impl.h" +#include <boost/make_shared.hpp> + +using namespace gr::uhd; + +const double usrp_block_impl::LOCK_TIMEOUT = 1.5; + +const pmt::pmt_t CMD_CHAN_KEY = pmt::mp("chan"); +const pmt::pmt_t CMD_GAIN_KEY = pmt::mp("gain"); +const pmt::pmt_t CMD_FREQ_KEY = pmt::mp("freq"); +const pmt::pmt_t CMD_LO_OFFSET_KEY = pmt::mp("lo_offset"); +const pmt::pmt_t CMD_TUNE_KEY = pmt::mp("tune"); +const pmt::pmt_t CMD_LO_FREQ_KEY = pmt::mp("lo_freq"); +const pmt::pmt_t CMD_DSP_FREQ_KEY = pmt::mp("dsp_freq"); +const pmt::pmt_t CMD_RATE_KEY = pmt::mp("rate"); +const pmt::pmt_t CMD_BANDWIDTH_KEY = pmt::mp("bandwidth"); +const pmt::pmt_t CMD_TIME_KEY = pmt::mp("time"); +const pmt::pmt_t CMD_MBOARD_KEY = pmt::mp("mboard"); +const pmt::pmt_t CMD_ANTENNA_KEY = pmt::mp("antenna"); + + +/********************************************************************** + * Structors + *********************************************************************/ +usrp_block::usrp_block( + const std::string &name, + gr::io_signature::sptr input_signature, + gr::io_signature::sptr output_signature +) : sync_block(name, input_signature, output_signature) +{ + // nop +} + +usrp_block_impl::usrp_block_impl( + const ::uhd::device_addr_t &device_addr, + const ::uhd::stream_args_t &stream_args, + const std::string &ts_tag_name +) : _stream_args(stream_args), + _nchan(stream_args.channels.size()), + _stream_now(_nchan == 1 and ts_tag_name.empty()), + _start_time_set(false), + _curr_tune_req(stream_args.channels.size(), ::uhd::tune_request_t()), + _chans_to_tune(stream_args.channels.size()) +{ + // TODO remove this when we update UHD + if(stream_args.cpu_format == "fc32") + _type = boost::make_shared< ::uhd::io_type_t >(::uhd::io_type_t::COMPLEX_FLOAT32); + if(stream_args.cpu_format == "sc16") + _type = boost::make_shared< ::uhd::io_type_t >(::uhd::io_type_t::COMPLEX_INT16); + _dev = ::uhd::usrp::multi_usrp::make(device_addr); + + _check_mboard_sensors_locked(); + + // Set up message ports: + message_port_register_in(pmt::mp("command")); + set_msg_handler( + pmt::mp("command"), + boost::bind(&usrp_block_impl::msg_handler_command, this, _1) + ); + +// cuz we lazy: +#define REGISTER_CMD_HANDLER(key, _handler) register_msg_cmd_handler(key, boost::bind(&usrp_block_impl::_handler, this, _1, _2, _3)) + // Register default command handlers: + REGISTER_CMD_HANDLER(CMD_FREQ_KEY, _cmd_handler_freq); + REGISTER_CMD_HANDLER(CMD_GAIN_KEY, _cmd_handler_gain); + REGISTER_CMD_HANDLER(CMD_LO_OFFSET_KEY, _cmd_handler_looffset); + REGISTER_CMD_HANDLER(CMD_TUNE_KEY, _cmd_handler_tune); + REGISTER_CMD_HANDLER(CMD_LO_FREQ_KEY, _cmd_handler_lofreq); + REGISTER_CMD_HANDLER(CMD_DSP_FREQ_KEY, _cmd_handler_dspfreq); + REGISTER_CMD_HANDLER(CMD_RATE_KEY, _cmd_handler_rate); + REGISTER_CMD_HANDLER(CMD_BANDWIDTH_KEY, _cmd_handler_bw); + REGISTER_CMD_HANDLER(CMD_ANTENNA_KEY, _cmd_handler_antenna); +} + +usrp_block_impl::~usrp_block_impl() +{ + // nop +} + +/********************************************************************** + * Helpers + *********************************************************************/ +void usrp_block_impl::_update_stream_args(const ::uhd::stream_args_t &stream_args_) +{ + ::uhd::stream_args_t stream_args(stream_args_); + if (stream_args.channels.empty()) { + stream_args.channels = _stream_args.channels; + } + if (stream_args.cpu_format != _stream_args.cpu_format || + stream_args.channels.size() != _stream_args.channels.size()) { + throw std::runtime_error("Cannot change I/O signatures while updating stream args!"); + } + _stream_args = stream_args; +} + +bool usrp_block_impl::_wait_for_locked_sensor( + std::vector<std::string> sensor_names, + const std::string &sensor_name, + get_sensor_fn_t get_sensor_fn +){ + if (std::find(sensor_names.begin(), sensor_names.end(), sensor_name) == sensor_names.end()) + return true; + + boost::system_time start = boost::get_system_time(); + boost::system_time first_lock_time; + + while (true) { + if ((not first_lock_time.is_not_a_date_time()) and + (boost::get_system_time() > (first_lock_time + boost::posix_time::seconds(LOCK_TIMEOUT)))) { + break; + } + + if (get_sensor_fn(sensor_name).to_bool()) { + if (first_lock_time.is_not_a_date_time()) + first_lock_time = boost::get_system_time(); + } + else { + first_lock_time = boost::system_time(); //reset to 'not a date time' + + if (boost::get_system_time() > (start + boost::posix_time::seconds(LOCK_TIMEOUT))){ + return false; + } + } + + boost::this_thread::sleep(boost::posix_time::milliseconds(100)); + } + + return true; +} + +bool usrp_block_impl::_unpack_chan_command( + std::string &command, + pmt::pmt_t &cmd_val, + int &chan, + const pmt::pmt_t &cmd_pmt +) { + try { + chan = -1; // Default value + if (pmt::is_tuple(cmd_pmt) and (pmt::length(cmd_pmt) == 2 or pmt::length(cmd_pmt) == 3)) { + command = pmt::symbol_to_string(pmt::tuple_ref(cmd_pmt, 0)); + cmd_val = pmt::tuple_ref(cmd_pmt, 1); + if (pmt::length(cmd_pmt) == 3) { + chan = pmt::to_long(pmt::tuple_ref(cmd_pmt, 2)); + } + } + else if (pmt::is_pair(cmd_pmt)) { + command = pmt::symbol_to_string(pmt::car(cmd_pmt)); + cmd_val = pmt::cdr(cmd_pmt); + if (pmt::is_pair(cmd_val)) { + chan = pmt::to_long(pmt::car(cmd_val)); + cmd_val = pmt::cdr(cmd_val); + } + } + else { + return false; + } + } catch (pmt::wrong_type w) { + return false; + } + return true; +} + +bool usrp_block_impl::_check_mboard_sensors_locked() +{ + bool clocks_locked = true; + + // Check ref lock for all mboards + for (size_t mboard_index = 0; mboard_index < _dev->get_num_mboards(); mboard_index++) { + std::string sensor_name = "ref_locked"; + if (_dev->get_clock_source(mboard_index) == "internal") { + continue; + } + else if (_dev->get_clock_source(mboard_index) == "mimo") { + sensor_name = "mimo_locked"; + } + if (not _wait_for_locked_sensor( + get_mboard_sensor_names(mboard_index), + sensor_name, + boost::bind(&usrp_block_impl::get_mboard_sensor, this, _1, mboard_index) + )) { + GR_LOG_WARN(d_logger, boost::format("Sensor '%s' failed to lock within timeout on motherboard %d.") % sensor_name % mboard_index); + clocks_locked = false; + } + } + + return clocks_locked; +} + +void +usrp_block_impl::_set_center_freq_from_internals_allchans() +{ + while (_chans_to_tune.any()) { + // This resets() bits, so this loop should not run indefinitely + _set_center_freq_from_internals(_chans_to_tune.find_first()); + } +} + + +/********************************************************************** + * Public API calls + *********************************************************************/ +::uhd::sensor_value_t +usrp_block_impl::get_mboard_sensor(const std::string &name, + size_t mboard) +{ + return _dev->get_mboard_sensor(name, mboard); +} + +std::vector<std::string> +usrp_block_impl::get_mboard_sensor_names(size_t mboard) +{ + return _dev->get_mboard_sensor_names(mboard); +} + +void +usrp_block_impl::set_clock_config(const ::uhd::clock_config_t &clock_config, + size_t mboard) +{ + return _dev->set_clock_config(clock_config, mboard); +} + +void +usrp_block_impl::set_time_source(const std::string &source, + const size_t mboard) +{ +#ifdef UHD_USRP_MULTI_USRP_REF_SOURCES_API + return _dev->set_time_source(source, mboard); +#else + throw std::runtime_error("not implemented in this version"); +#endif +} + +std::string +usrp_block_impl::get_time_source(const size_t mboard) +{ +#ifdef UHD_USRP_MULTI_USRP_REF_SOURCES_API + return _dev->get_time_source(mboard); +#else + throw std::runtime_error("not implemented in this version"); +#endif +} + +std::vector<std::string> +usrp_block_impl::get_time_sources(const size_t mboard) +{ +#ifdef UHD_USRP_MULTI_USRP_REF_SOURCES_API + return _dev->get_time_sources(mboard); +#else + throw std::runtime_error("not implemented in this version"); +#endif +} + +void +usrp_block_impl::set_clock_source(const std::string &source, + const size_t mboard) +{ +#ifdef UHD_USRP_MULTI_USRP_REF_SOURCES_API + return _dev->set_clock_source(source, mboard); +#else + throw std::runtime_error("not implemented in this version"); +#endif +} + +std::string +usrp_block_impl::get_clock_source(const size_t mboard) +{ +#ifdef UHD_USRP_MULTI_USRP_REF_SOURCES_API + return _dev->get_clock_source(mboard); +#else + throw std::runtime_error("not implemented in this version"); +#endif +} + +std::vector<std::string> +usrp_block_impl::get_clock_sources(const size_t mboard) +{ +#ifdef UHD_USRP_MULTI_USRP_REF_SOURCES_API + return _dev->get_clock_sources(mboard); +#else + throw std::runtime_error("not implemented in this version"); +#endif +} + +double +usrp_block_impl::get_clock_rate(size_t mboard) +{ + return _dev->get_master_clock_rate(mboard); +} + +void +usrp_block_impl::set_clock_rate(double rate, size_t mboard) +{ + return _dev->set_master_clock_rate(rate, mboard); +} + +::uhd::time_spec_t +usrp_block_impl::get_time_now(size_t mboard) +{ + return _dev->get_time_now(mboard); +} + +::uhd::time_spec_t +usrp_block_impl::get_time_last_pps(size_t mboard) +{ + return _dev->get_time_last_pps(mboard); +} + +std::vector<std::string> +usrp_block_impl::get_gpio_banks(const size_t mboard) +{ +#ifdef UHD_USRP_MULTI_USRP_GPIO_API + return _dev->get_gpio_banks(mboard); +#else + throw std::runtime_error("not implemented in this version"); +#endif +} + +boost::uint32_t +usrp_block_impl::get_gpio_attr( + const std::string &bank, + const std::string &attr, + const size_t mboard +) { +#ifdef UHD_USRP_MULTI_USRP_GPIO_API + return _dev->get_gpio_attr(bank, attr, mboard); +#else + throw std::runtime_error("not implemented in this version"); +#endif +} + +void +usrp_block_impl::set_time_now(const ::uhd::time_spec_t &time_spec, + size_t mboard) +{ + return _dev->set_time_now(time_spec, mboard); +} + +void +usrp_block_impl::set_time_next_pps(const ::uhd::time_spec_t &time_spec) +{ + return _dev->set_time_next_pps(time_spec); +} + +void +usrp_block_impl::set_time_unknown_pps(const ::uhd::time_spec_t &time_spec) +{ + return _dev->set_time_unknown_pps(time_spec); +} + +void +usrp_block_impl::set_command_time(const ::uhd::time_spec_t &time_spec, + size_t mboard) +{ +#ifdef UHD_USRP_MULTI_USRP_COMMAND_TIME_API + return _dev->set_command_time(time_spec, mboard); +#else + throw std::runtime_error("not implemented in this version"); +#endif +} + +void +usrp_block_impl::clear_command_time(size_t mboard) +{ +#ifdef UHD_USRP_MULTI_USRP_COMMAND_TIME_API + return _dev->clear_command_time(mboard); +#else + throw std::runtime_error("not implemented in this version"); +#endif +} + +void +usrp_block_impl::set_user_register(const uint8_t addr, + const uint32_t data, + size_t mboard) +{ +#ifdef UHD_USRP_MULTI_USRP_USER_REGS_API + _dev->set_user_register(addr, data, mboard); +#else + throw std::runtime_error("not implemented in this version"); +#endif +} + +void +usrp_block_impl::set_gpio_attr( + const std::string &bank, + const std::string &attr, + const boost::uint32_t value, + const boost::uint32_t mask, + const size_t mboard +) { +#ifdef UHD_USRP_MULTI_USRP_GPIO_API + return _dev->set_gpio_attr(bank, attr, value, mask, mboard); +#else + throw std::runtime_error("not implemented in this version"); +#endif +} + +::uhd::usrp::multi_usrp::sptr +usrp_block_impl::get_device(void) +{ + return _dev; +} + +/********************************************************************** + * External Interfaces + *********************************************************************/ +void +usrp_block_impl::setup_rpc() +{ +#ifdef GR_CTRLPORT + add_rpc_variable( + rpcbasic_sptr(new rpcbasic_register_get<usrp_block, double>( + alias(), "samp_rate", + &usrp_block::get_samp_rate, + pmt::mp(100000.0f), pmt::mp(25000000.0f), pmt::mp(1000000.0f), + "sps", "Sample Rate", RPC_PRIVLVL_MIN, + DISPTIME | DISPOPTSTRIP)) + ); + + add_rpc_variable( + rpcbasic_sptr(new rpcbasic_register_set<usrp_block, double>( + alias(), "samp_rate", + &usrp_block::set_samp_rate, + pmt::mp(100000.0f), pmt::mp(25000000.0f), pmt::mp(1000000.0f), + "sps", "Sample Rate", + RPC_PRIVLVL_MIN, DISPNULL)) + ); +#endif /* GR_CTRLPORT */ +} + +void usrp_block_impl::msg_handler_command(pmt::pmt_t msg) +{ + // Legacy code back compat: If we receive a tuple, we convert + // it to a dict, and call the function again. Yep, this comes + // at a slight performance hit. Sometime in the future, we can + // hopefully remove this: + if (pmt::is_tuple(msg)) { + if (pmt::length(msg) != 2 && pmt::length(msg) != 3) { + GR_LOG_ALERT(d_logger, boost::format("Error while unpacking command PMT: %s") % msg); + return; + } + pmt::pmt_t new_msg = pmt::make_dict(); + new_msg = pmt::dict_add(new_msg, pmt::tuple_ref(msg, 0), pmt::tuple_ref(msg, 1)); + if (pmt::length(msg) == 3) { + new_msg = pmt::dict_add(new_msg, pmt::mp("chan"), pmt::tuple_ref(msg, 2)); + } + GR_LOG_WARN(d_debug_logger, boost::format("Using legacy message format (tuples): %s") % msg); + return msg_handler_command(new_msg); + } + // End of legacy backward compat code. + + // Turn pair into dict + if (!pmt::is_dict(msg)) { + GR_LOG_ERROR(d_logger, boost::format("Command message is neither dict nor pair: %s") % msg); + return; + } + + // OK, here comes the horrible part. Pairs pass is_dict(), but they're not dicts. Such dicks. + try { + // This will fail if msg is a pair: + pmt::pmt_t keys = pmt::dict_keys(msg); + } catch (const pmt::wrong_type &e) { + // So we fix it: + GR_LOG_DEBUG(d_debug_logger, boost::format("Converting pair to dict: %s") % msg); + msg = pmt::dict_add(pmt::make_dict(), pmt::car(msg), pmt::cdr(msg)); + } + + /*** Start the actual message processing *************************/ + /// 1) Check if there's a time stamp + if (pmt::dict_has_key(msg, CMD_TIME_KEY)) { + size_t mboard_index = pmt::to_long( + pmt::dict_ref( + msg, CMD_MBOARD_KEY, + pmt::from_long( ::uhd::usrp::multi_usrp::ALL_MBOARDS ) // Default to all mboards + ) + ); + pmt::pmt_t timespec_p = pmt::dict_ref(msg, CMD_TIME_KEY, pmt::PMT_NIL); + if (timespec_p == pmt::PMT_NIL) { + clear_command_time(mboard_index); + } else { + ::uhd::time_spec_t timespec( + time_t(pmt::to_uint64(pmt::car(timespec_p))), // Full secs + pmt::to_double(pmt::cdr(timespec_p)) // Frac secs + ); + GR_LOG_DEBUG(d_debug_logger, boost::format("Setting command time on mboard %d") % mboard_index); + set_command_time(timespec, mboard_index); + } + } + + /// 2) Read chan value + int chan = int(pmt::to_long( + pmt::dict_ref( + msg, CMD_CHAN_KEY, + pmt::from_long(-1) // Default to all chans + ) + )); + + /// 3) Loop through all the values + GR_LOG_DEBUG(d_debug_logger, boost::format("Processing command message %s") % msg); + pmt::pmt_t msg_items = pmt::dict_items(msg); + for (size_t i = 0; i < pmt::length(msg_items); i++) { + try { + dispatch_msg_cmd_handler( + pmt::car(pmt::nth(i, msg_items)), + pmt::cdr(pmt::nth(i, msg_items)), + chan, msg + ); + } catch (pmt::wrong_type &e) { + GR_LOG_ALERT(d_logger, boost::format("Invalid command value for key %s: %s") % pmt::car(pmt::nth(i, msg_items)) % pmt::cdr(pmt::nth(i, msg_items))); + break; + } + } + + /// 4) Check if we need to re-tune + _set_center_freq_from_internals_allchans(); +} + + +void usrp_block_impl::dispatch_msg_cmd_handler(const pmt::pmt_t &cmd, const pmt::pmt_t &val, int chan, pmt::pmt_t &msg) +{ + if (_msg_cmd_handlers.has_key(cmd)) { + _msg_cmd_handlers[cmd](val, chan, msg); + } +} + +void usrp_block_impl::register_msg_cmd_handler(const pmt::pmt_t &cmd, cmd_handler_t handler) +{ + _msg_cmd_handlers[cmd] = handler; +} + +void usrp_block_impl::_update_curr_tune_req(::uhd::tune_request_t &tune_req, int chan) +{ + if (chan == -1) { + for (size_t i = 0; i < _nchan; i++) { + _update_curr_tune_req(tune_req, int(i)); + } + return; + } + + if (tune_req.target_freq != _curr_tune_req[chan].target_freq || + tune_req.rf_freq_policy != _curr_tune_req[chan].rf_freq_policy || + tune_req.rf_freq != _curr_tune_req[chan].rf_freq || + tune_req.dsp_freq != _curr_tune_req[chan].dsp_freq || + tune_req.dsp_freq_policy != _curr_tune_req[chan].dsp_freq_policy + ) { + _curr_tune_req[chan] = tune_req; + _chans_to_tune.set(chan); + } +} + +// Default handlers: +void usrp_block_impl::_cmd_handler_freq(const pmt::pmt_t &freq_, int chan, const pmt::pmt_t &msg) +{ + double freq = pmt::to_double(freq_); + ::uhd::tune_request_t new_tune_reqest(freq); + if (pmt::dict_has_key(msg, CMD_LO_OFFSET_KEY)) { + double lo_offset = pmt::to_double(pmt::dict_ref(msg, CMD_LO_OFFSET_KEY, pmt::PMT_NIL)); + new_tune_reqest = ::uhd::tune_request_t(freq, lo_offset); + } + + _update_curr_tune_req(new_tune_reqest, chan); +} + +void usrp_block_impl::_cmd_handler_looffset(const pmt::pmt_t &lo_offset, int chan, const pmt::pmt_t &msg) +{ + if (pmt::dict_has_key(msg, CMD_FREQ_KEY)) { + // Then it's already taken care of + return; + } + + double lo_offs = pmt::to_double(lo_offset); + ::uhd::tune_request_t new_tune_request = _curr_tune_req[chan]; + new_tune_request.rf_freq = new_tune_request.target_freq + lo_offs; + new_tune_request.rf_freq_policy = ::uhd::tune_request_t::POLICY_MANUAL; + new_tune_request.dsp_freq_policy = ::uhd::tune_request_t::POLICY_AUTO; + + _update_curr_tune_req(new_tune_request, chan); +} + +void usrp_block_impl::_cmd_handler_gain(const pmt::pmt_t &gain_, int chan, const pmt::pmt_t &msg) +{ + double gain = pmt::to_double(gain_); + if (chan == -1) { + for (size_t i = 0; i < _nchan; i++) { + set_gain(gain, i); + } + return; + } + + set_gain(gain, chan); +} + +void usrp_block_impl::_cmd_handler_antenna(const pmt::pmt_t &ant, int chan, const pmt::pmt_t &msg) +{ + const std::string antenna(pmt::symbol_to_string(ant)); + if (chan == -1) { + for (size_t i = 0; i < _nchan; i++) { + set_antenna(antenna, i); + } + return; + } + + set_antenna(antenna, chan); +} + +void usrp_block_impl::_cmd_handler_rate(const pmt::pmt_t &rate_, int, const pmt::pmt_t &) +{ + const double rate = pmt::to_double(rate_); + set_samp_rate(rate); +} + +void usrp_block_impl::_cmd_handler_tune(const pmt::pmt_t &tune, int chan, const pmt::pmt_t &msg) +{ + double freq = pmt::to_double(pmt::car(tune)); + double lo_offset = pmt::to_double(pmt::cdr(tune)); + ::uhd::tune_request_t new_tune_reqest(freq, lo_offset); + _update_curr_tune_req(new_tune_reqest, chan); +} + +void usrp_block_impl::_cmd_handler_bw(const pmt::pmt_t &bw, int chan, const pmt::pmt_t &msg) +{ + double bandwidth = pmt::to_double(bw); + if (chan == -1) { + for (size_t i = 0; i < _nchan; i++) { + set_bandwidth(bandwidth, i); + } + return; + } + + set_bandwidth(bandwidth, chan); +} + +void usrp_block_impl::_cmd_handler_lofreq(const pmt::pmt_t &lofreq, int chan, const pmt::pmt_t &msg) +{ + if (chan == -1) { + for (size_t i = 0; i < _nchan; i++) { + _cmd_handler_lofreq(lofreq, int(i), msg); + } + return; + } + + ::uhd::tune_request_t new_tune_request = _curr_tune_req[chan]; + new_tune_request.rf_freq = pmt::to_double(lofreq); + if (pmt::dict_has_key(msg, CMD_DSP_FREQ_KEY)) { + new_tune_request.dsp_freq = pmt::to_double(pmt::dict_ref(msg, CMD_DSP_FREQ_KEY, pmt::PMT_NIL)); + } + new_tune_request.rf_freq_policy = ::uhd::tune_request_t::POLICY_MANUAL; + new_tune_request.dsp_freq_policy = ::uhd::tune_request_t::POLICY_MANUAL; + + _update_curr_tune_req(new_tune_request, chan); +} + +void usrp_block_impl::_cmd_handler_dspfreq(const pmt::pmt_t &dspfreq, int chan, const pmt::pmt_t &msg) +{ + if (pmt::dict_has_key(msg, CMD_LO_FREQ_KEY)) { + // Then it's already dealt with + return; + } + + if (chan == -1) { + for (size_t i = 0; i < _nchan; i++) { + _cmd_handler_dspfreq(dspfreq, int(i), msg); + } + return; + } + + ::uhd::tune_request_t new_tune_request = _curr_tune_req[chan]; + new_tune_request.dsp_freq = pmt::to_double(dspfreq); + new_tune_request.rf_freq_policy = ::uhd::tune_request_t::POLICY_MANUAL; + new_tune_request.dsp_freq_policy = ::uhd::tune_request_t::POLICY_MANUAL; + + _update_curr_tune_req(new_tune_request, chan); +} + diff --git a/gr-uhd/lib/usrp_block_impl.h b/gr-uhd/lib/usrp_block_impl.h new file mode 100644 index 0000000000..2158d542bc --- /dev/null +++ b/gr-uhd/lib/usrp_block_impl.h @@ -0,0 +1,241 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 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_UHD_BLOCK_IMPL_H +#define INCLUDED_GR_UHD_BLOCK_IMPL_H + +#include <gnuradio/uhd/usrp_block.h> +#include <pmt/pmt.h> +#include <uhd/usrp/multi_usrp.hpp> +#include <boost/dynamic_bitset.hpp> +#include <boost/bind.hpp> + +#define SET_CENTER_FREQ_FROM_INTERNALS(usrp_class, tune_method) \ + ::uhd::tune_result_t \ + usrp_class::_set_center_freq_from_internals(size_t chan) \ + { \ + _chans_to_tune.reset(chan); \ + return _dev->tune_method(_curr_tune_req[chan], _stream_args.channels[chan]); \ + } + +namespace gr { + namespace uhd { + + class usrp_block_impl : virtual public usrp_block + { + public: + typedef boost::function< ::uhd::sensor_value_t (const std::string&)> get_sensor_fn_t; + typedef boost::function<void(const pmt::pmt_t &, int, const pmt::pmt_t &)> cmd_handler_t; + + static const double LOCK_TIMEOUT; + + /********************************************************************** + * Public API calls (see usrp_block.h for docs) + **********************************************************************/ + // Getters + ::uhd::sensor_value_t get_mboard_sensor(const std::string &name, size_t mboard); + std::vector<std::string> get_mboard_sensor_names(size_t mboard); + std::string get_time_source(const size_t mboard); + std::vector<std::string> get_time_sources(const size_t mboard); + std::string get_clock_source(const size_t mboard); + std::vector<std::string> get_clock_sources(const size_t mboard); + double get_clock_rate(size_t mboard); + ::uhd::time_spec_t get_time_now(size_t mboard = 0); + ::uhd::time_spec_t get_time_last_pps(size_t mboard); + ::uhd::usrp::multi_usrp::sptr get_device(void); + std::vector<std::string> get_gpio_banks(const size_t mboard); + boost::uint32_t get_gpio_attr( + const std::string &bank, + const std::string &attr, + const size_t mboard = 0 + ); + + // Setters + void set_clock_config(const ::uhd::clock_config_t &clock_config, size_t mboard); + void set_time_source(const std::string &source, const size_t mboard); + void set_clock_source(const std::string &source, const size_t mboard); + void set_clock_rate(double rate, size_t mboard); + void set_time_now(const ::uhd::time_spec_t &time_spec, size_t mboard); + void set_time_next_pps(const ::uhd::time_spec_t &time_spec); + void set_time_unknown_pps(const ::uhd::time_spec_t &time_spec); + void set_command_time(const ::uhd::time_spec_t &time_spec, size_t mboard); + void set_user_register(const uint8_t addr, const uint32_t data, size_t mboard); + void clear_command_time(size_t mboard); + void set_gpio_attr( + const std::string &bank, + const std::string &attr, + const boost::uint32_t value, + const boost::uint32_t mask, + const size_t mboard + ); + + // RPC + void setup_rpc(); + + /********************************************************************** + * Structors + * ********************************************************************/ + virtual ~usrp_block_impl(); + protected: + /*! \brief Components common to USRP sink and source. + * + * \param device_addr Device address + options + * \param stream_args Stream args (cpu format, otw format...) + * \param ts_tag_name If this block produces or consumes stream tags, enter the corresponding tag name here + */ + usrp_block_impl( + const ::uhd::device_addr_t &device_addr, + const ::uhd::stream_args_t &stream_args, + const std::string &ts_tag_name + ); + + /********************************************************************** + * Command Interface + **********************************************************************/ + //! Receives commands and handles them + void msg_handler_command(pmt::pmt_t msg); + + //! For a given argument, call the associated handler, or if none exists, + // show a warning through the logging interface. + void dispatch_msg_cmd_handler(const pmt::pmt_t &cmd, const pmt::pmt_t &val, int chan, pmt::pmt_t &msg); + + //! Register a new handler for command key \p cmd + void register_msg_cmd_handler(const pmt::pmt_t &cmd, cmd_handler_t handler); + + + // Default handlers + void _cmd_handler_freq(const pmt::pmt_t &freq, int chan, const pmt::pmt_t &msg); + void _cmd_handler_looffset(const pmt::pmt_t &lo_offset, int chan, const pmt::pmt_t &msg); + void _cmd_handler_gain(const pmt::pmt_t &gain, int chan, const pmt::pmt_t &msg); + void _cmd_handler_antenna(const pmt::pmt_t &ant, int chan, const pmt::pmt_t &msg); + void _cmd_handler_rate(const pmt::pmt_t &rate, int chan, const pmt::pmt_t &msg); + void _cmd_handler_tune(const pmt::pmt_t &tune, int chan, const pmt::pmt_t &msg); + void _cmd_handler_bw(const pmt::pmt_t &bw, int chan, const pmt::pmt_t &msg); + void _cmd_handler_lofreq(const pmt::pmt_t &lofreq, int chan, const pmt::pmt_t &msg); + void _cmd_handler_dspfreq(const pmt::pmt_t &dspfreq, int chan, const pmt::pmt_t &msg); + + /********************************************************************** + * Helpers + **********************************************************************/ + bool _check_mboard_sensors_locked(); + + void _update_stream_args(const ::uhd::stream_args_t &stream_args_); + + // should be const, doesn't work though 'cause missing operator=() for tune_request_t + void _update_curr_tune_req(::uhd::tune_request_t &tune_req, int chan); + + /*! \brief Wait until a timeout or a sensor returns 'locked'. + * + * If a given sensor is not found, this still returns 'true', so we don't throw + * errors or warnings if a sensor wasn't implemented. + * + * \returns true if the sensor locked in time or doesn't exist + */ + bool _wait_for_locked_sensor( + std::vector<std::string> sensor_names, + const std::string &sensor_name, + get_sensor_fn_t get_sensor_fn + ); + + //! Helper function for msg_handler_command: + // - Extracts command and the command value from the command PMT + // - Returns true if the command PMT is well formed + // - If a channel is given, return that as well, otherwise set the channel to -1 + static bool _unpack_chan_command( + std::string &command, + pmt::pmt_t &cmd_val, + int &chan, + const pmt::pmt_t &cmd_pmt + ); + + //! Helper function for msg_handler_command: + // - Sets a value in vector_to_update to cmd_val, depending on chan + // - If chan is a positive integer, it will set vector_to_update[chan] + // - If chan is -1, it depends on minus_one_updates_all: + // - Either set vector_to_update[0] or + // - Set *all* entries in vector_to_update + // - Returns a dynamic_bitset, all indexes that where changed in + // vector_to_update are set to 1 + template <typename T> + static boost::dynamic_bitset<> _update_vector_from_cmd_val( + std::vector<T> &vector_to_update, + int chan, + const T cmd_val, + bool minus_one_updates_all = false + ) { + boost::dynamic_bitset<> vals_updated(vector_to_update.size()); + if (chan == -1) { + if (minus_one_updates_all) { + for (size_t i = 0; i < vector_to_update.size(); i++) { + if (vector_to_update[i] != cmd_val) { + vals_updated[i] = true; + vector_to_update[i] = cmd_val; + } + } + return vals_updated; + } + chan = 0; + } + if (vector_to_update[chan] != cmd_val) { + vector_to_update[chan] = cmd_val; + vals_updated[chan] = true; + } + + return vals_updated; + } + + //! Like set_center_freq(), but uses _curr_freq and _curr_lo_offset + virtual ::uhd::tune_result_t _set_center_freq_from_internals(size_t chan) = 0; + + //! Calls _set_center_freq_from_internals() on all channels + void _set_center_freq_from_internals_allchans(); + + /********************************************************************** + * Members + *********************************************************************/ + //! Shared pointer to the underlying multi_usrp object + ::uhd::usrp::multi_usrp::sptr _dev; + ::uhd::stream_args_t _stream_args; + boost::shared_ptr< ::uhd::io_type_t > _type; + //! Number of channels (i.e. number of in- or outputs) + size_t _nchan; + bool _stream_now; + ::uhd::time_spec_t _start_time; + bool _start_time_set; + + /****** Command interface related **********/ + //! Stores a list of commands for later execution + std::vector<pmt::pmt_t> _pending_cmds; + //! Shadows the last value we told the USRP to tune to for every channel + // (this is not necessarily the true value the USRP is currently tuned to!). + std::vector< ::uhd::tune_request_t > _curr_tune_req; + boost::dynamic_bitset<> _chans_to_tune; + + //! Stores the individual command handlers + ::uhd::dict<pmt::pmt_t, cmd_handler_t> _msg_cmd_handlers; + }; + + } /* namespace uhd */ +} /* namespace gr */ + +#endif /* INCLUDED_GR_UHD_BLOCK_IMPL_H */ + diff --git a/gr-uhd/lib/usrp_common.h b/gr-uhd/lib/usrp_common.h deleted file mode 100644 index 41f443922c..0000000000 --- a/gr-uhd/lib/usrp_common.h +++ /dev/null @@ -1,211 +0,0 @@ -/* -*- 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_UHD_USRP_COMMON_H -#define INCLUDED_GR_UHD_USRP_COMMON_H - -#include <pmt/pmt.h> -#include <boost/dynamic_bitset.hpp> -#include <boost/make_shared.hpp> -#include <boost/bind.hpp> -#include <boost/thread.hpp> -#include <uhd/usrp/multi_usrp.hpp> -#include <uhd/convert.hpp> -#include <iostream> - -namespace gr { - namespace uhd { - typedef boost::function< ::uhd::sensor_value_t (const std::string&)> get_sensor_fn_t; - - static const double LOCK_TIMEOUT = 1.5; // s - - //! Helper function for msg_handler_command: - // - Extracts command and the command value from the command PMT - // - Returns true if the command PMT is well formed - // - If a channel is given, return that as well, otherwise set the channel to -1 - static bool _unpack_chan_command( - std::string &command, - pmt::pmt_t &cmd_val, - int &chan, - const pmt::pmt_t &cmd_pmt - ) { - try { - chan = -1; // Default value - if (pmt::is_tuple(cmd_pmt) and (pmt::length(cmd_pmt) == 2 or pmt::length(cmd_pmt) == 3)) { - command = pmt::symbol_to_string(pmt::tuple_ref(cmd_pmt, 0)); - cmd_val = pmt::tuple_ref(cmd_pmt, 1); - if (pmt::length(cmd_pmt) == 3) { - chan = pmt::to_long(pmt::tuple_ref(cmd_pmt, 2)); - } - } - else if (pmt::is_pair(cmd_pmt)) { - command = pmt::symbol_to_string(pmt::car(cmd_pmt)); - cmd_val = pmt::cdr(cmd_pmt); - if (pmt::is_pair(cmd_val)) { - chan = pmt::to_long(pmt::car(cmd_val)); - cmd_val = pmt::cdr(cmd_val); - } - } - else { - return false; - } - } catch (pmt::wrong_type w) { - return false; - } - return true; - } - - //! Helper function for msg_handler_command: - // - Sets a value in vector_to_update to cmd_val, depending on chan - // - If chan is a positive integer, it will set vector_to_update[chan] - // - If chan is -1, it depends on minus_one_updates_all: - // - Either set vector_to_update[0] or - // - Set *all* entries in vector_to_update - // - Returns a dynamic_bitset, all indexes that where changed in - // vector_to_update are set to 1 - template <typename T> - static boost::dynamic_bitset<> _update_vector_from_cmd_val( - std::vector<T> &vector_to_update, - int chan, - const T cmd_val, - bool minus_one_updates_all = false - ) { - boost::dynamic_bitset<> vals_updated(vector_to_update.size()); - if (chan == -1) { - if (minus_one_updates_all) { - for (size_t i = 0; i < vector_to_update.size(); i++) { - if (vector_to_update[i] != cmd_val) { - vals_updated[i] = true; - vector_to_update[i] = cmd_val; - } - } - return vals_updated; - } - chan = 0; - } - if (vector_to_update[chan] != cmd_val) { - vector_to_update[chan] = cmd_val; - vals_updated[chan] = true; - } - - return vals_updated; - } - - - /*! \brief Components common to USRP sink and source. - * - * \param device_addr Device address + options - * \param stream_args Stream args (cpu format, otw format...) - * \param ts_tag_name If this block produces or consumes stream tags, enter the corresponding tag name here - */ - class usrp_common_impl - { - public: - usrp_common_impl( - const ::uhd::device_addr_t &device_addr, - const ::uhd::stream_args_t &stream_args, - const std::string &ts_tag_name - ) : - _stream_args(stream_args), - _nchan(stream_args.channels.size()), - _stream_now(_nchan == 1 and ts_tag_name.empty()), - _start_time_set(false) - { - if(stream_args.cpu_format == "fc32") - _type = boost::make_shared< ::uhd::io_type_t >(::uhd::io_type_t::COMPLEX_FLOAT32); - if(stream_args.cpu_format == "sc16") - _type = boost::make_shared< ::uhd::io_type_t >(::uhd::io_type_t::COMPLEX_INT16); - _dev = ::uhd::usrp::multi_usrp::make(device_addr); - }; - - ~usrp_common_impl() {}; - - protected: - /*! \brief Wait until a timeout or a sensor returns 'locked'. - * - * If a given sensor is not found, this still returns 'true', so we don't throw - * errors or warnings if a sensor wasn't implemented. - */ - bool _wait_for_locked_sensor( - std::vector<std::string> sensor_names, - const std::string &sensor_name, - get_sensor_fn_t get_sensor_fn - ){ - if (std::find(sensor_names.begin(), sensor_names.end(), sensor_name) == sensor_names.end()) - return true; - - boost::system_time start = boost::get_system_time(); - boost::system_time first_lock_time; - - while (true) { - if ((not first_lock_time.is_not_a_date_time()) and - (boost::get_system_time() > (first_lock_time + boost::posix_time::seconds(LOCK_TIMEOUT)))) { - break; - } - - if (get_sensor_fn(sensor_name).to_bool()) { - if (first_lock_time.is_not_a_date_time()) - first_lock_time = boost::get_system_time(); - } - else { - first_lock_time = boost::system_time(); //reset to 'not a date time' - - if (boost::get_system_time() > (start + boost::posix_time::seconds(LOCK_TIMEOUT))){ - return false; - } - } - - boost::this_thread::sleep(boost::posix_time::milliseconds(100)); - } - - return true; - } - - void _update_stream_args(const ::uhd::stream_args_t &stream_args_) - { - ::uhd::stream_args_t stream_args(stream_args_); - if (stream_args.channels.empty()) { - stream_args.channels = _stream_args.channels; - } - if (stream_args.cpu_format != _stream_args.cpu_format || - stream_args.channels.size() != _stream_args.channels.size()) { - throw std::runtime_error("Cannot change I/O signatures while updating stream args!"); - } - _stream_args = stream_args; - } - - //! Shared pointer to the underlying multi_usrp object - ::uhd::usrp::multi_usrp::sptr _dev; - ::uhd::stream_args_t _stream_args; - boost::shared_ptr< ::uhd::io_type_t > _type; - //! Number of channels (i.e. number of in- or outputs) - size_t _nchan; - bool _stream_now; - ::uhd::time_spec_t _start_time; - bool _start_time_set; - }; - - } /* namespace uhd */ -} /* namespace gr */ - -#endif /* INCLUDED_GR_UHD_USRP_COMMON_H */ - diff --git a/gr-uhd/lib/usrp_sink_impl.cc b/gr-uhd/lib/usrp_sink_impl.cc index 08896a8bb0..8f2d2ad4a3 100644 --- a/gr-uhd/lib/usrp_sink_impl.cc +++ b/gr-uhd/lib/usrp_sink_impl.cc @@ -64,53 +64,16 @@ namespace gr { usrp_sink_impl::usrp_sink_impl(const ::uhd::device_addr_t &device_addr, const ::uhd::stream_args_t &stream_args, const std::string &length_tag_name) - : sync_block("gr uhd usrp sink", + : usrp_block("gr uhd usrp sink", args_to_io_sig(stream_args), io_signature::make(0, 0, 0)), - usrp_common_impl(device_addr, stream_args, length_tag_name), + usrp_block_impl(device_addr, stream_args, length_tag_name), _length_tag_key(length_tag_name.empty() ? pmt::PMT_NIL : pmt::string_to_symbol(length_tag_name)), - _nitems_to_send(0), - _curr_freq(stream_args.channels.size(), 0.0), - _curr_lo_offset(stream_args.channels.size(), 0.0), - _curr_gain(stream_args.channels.size(), 0.0), - _chans_to_tune(stream_args.channels.size()) + _nitems_to_send(0) { - message_port_register_in(pmt::mp("command")); - set_msg_handler( - pmt::mp("command"), - boost::bind(&usrp_sink_impl::msg_handler_command, this, _1) - ); - - _check_sensors_locked(); + _sample_rate = get_samp_rate(); } - bool usrp_sink_impl::_check_sensors_locked() - { - bool clocks_locked = true; - - // Check ref lock for all mboards - for (size_t mboard_index = 0; mboard_index < _dev->get_num_mboards(); mboard_index++) { - std::string sensor_name = "ref_locked"; - if (_dev->get_clock_source(mboard_index) == "internal") { - continue; - } - else if (_dev->get_clock_source(mboard_index) == "mimo") { - sensor_name = "mimo_locked"; - } - if (not _wait_for_locked_sensor( - get_mboard_sensor_names(mboard_index), - sensor_name, - boost::bind(&usrp_sink_impl::get_mboard_sensor, this, _1, mboard_index) - )) { - GR_LOG_WARN(d_logger, boost::format("Sensor '%s' failed to lock within timeout on motherboard %d.") % sensor_name % mboard_index); - clocks_locked = false; - } - } - - return clocks_locked; - } - - usrp_sink_impl::~usrp_sink_impl() { } @@ -169,39 +132,12 @@ namespace gr { usrp_sink_impl::set_center_freq(const ::uhd::tune_request_t tune_request, size_t chan) { - _curr_freq[chan] = tune_request.target_freq; - if (tune_request.rf_freq_policy == ::uhd::tune_request_t::POLICY_MANUAL) { - _curr_lo_offset[chan] = tune_request.rf_freq - tune_request.target_freq; - } else { - _curr_lo_offset[chan] = 0.0; - } + _curr_tune_req[chan] = tune_request; chan = _stream_args.channels[chan]; return _dev->set_tx_freq(tune_request, chan); } - ::uhd::tune_result_t - usrp_sink_impl::_set_center_freq_from_internals(size_t chan) - { - _chans_to_tune[chan] = false; - if (_curr_lo_offset[chan] == 0.0) { - return _dev->set_tx_freq(_curr_freq[chan], _stream_args.channels[chan]); - } else { - return _dev->set_tx_freq( - ::uhd::tune_request_t(_curr_freq[chan], _curr_lo_offset[chan]), - _stream_args.channels[chan] - ); - } - } - - void - usrp_sink_impl::_set_center_freq_from_internals_allchans() - { - for (size_t chan = 0; chan < _nchan; chan++) { - if (_chans_to_tune[chan]) { - _set_center_freq_from_internals(chan); - } - } - } + SET_CENTER_FREQ_FROM_INTERNALS(usrp_sink_impl, set_tx_freq); double usrp_sink_impl::get_center_freq(size_t chan) @@ -220,7 +156,6 @@ namespace gr { void usrp_sink_impl::set_gain(double gain, size_t chan) { - _curr_gain[chan] = gain; chan = _stream_args.channels[chan]; return _dev->set_tx_gain(gain, chan); } @@ -230,7 +165,6 @@ namespace gr { const std::string &name, size_t chan) { - _curr_gain[chan] = gain; chan = _stream_args.channels[chan]; return _dev->set_tx_gain(gain, name, chan); } @@ -375,152 +309,6 @@ namespace gr { return _dev->get_tx_sensor_names(chan); } - ::uhd::sensor_value_t - usrp_sink_impl::get_mboard_sensor(const std::string &name, - size_t mboard) - { - return _dev->get_mboard_sensor(name, mboard); - } - - std::vector<std::string> - usrp_sink_impl::get_mboard_sensor_names(size_t mboard) - { - return _dev->get_mboard_sensor_names(mboard); - } - - void - usrp_sink_impl::set_clock_config(const ::uhd::clock_config_t &clock_config, - size_t mboard) - { - return _dev->set_clock_config(clock_config, mboard); - } - - void - usrp_sink_impl::set_time_source(const std::string &source, - const size_t mboard) - { -#ifdef UHD_USRP_MULTI_USRP_REF_SOURCES_API - return _dev->set_time_source(source, mboard); -#else - throw std::runtime_error("not implemented in this version"); -#endif - } - - std::string - usrp_sink_impl::get_time_source(const size_t mboard) - { -#ifdef UHD_USRP_MULTI_USRP_REF_SOURCES_API - return _dev->get_time_source(mboard); -#else - throw std::runtime_error("not implemented in this version"); -#endif - } - - std::vector<std::string> - usrp_sink_impl::get_time_sources(const size_t mboard) - { -#ifdef UHD_USRP_MULTI_USRP_REF_SOURCES_API - return _dev->get_time_sources(mboard); -#else - throw std::runtime_error("not implemented in this version"); -#endif - } - - void - usrp_sink_impl::set_clock_source(const std::string &source, - const size_t mboard) - { -#ifdef UHD_USRP_MULTI_USRP_REF_SOURCES_API - return _dev->set_clock_source(source, mboard); -#else - throw std::runtime_error("not implemented in this version"); -#endif - } - - std::string - usrp_sink_impl::get_clock_source(const size_t mboard) - { -#ifdef UHD_USRP_MULTI_USRP_REF_SOURCES_API - return _dev->get_clock_source(mboard); -#else - throw std::runtime_error("not implemented in this version"); -#endif - } - - std::vector<std::string> - usrp_sink_impl::get_clock_sources(const size_t mboard) - { -#ifdef UHD_USRP_MULTI_USRP_REF_SOURCES_API - return _dev->get_clock_sources(mboard); -#else - throw std::runtime_error("not implemented in this version"); -#endif - } - - double - usrp_sink_impl::get_clock_rate(size_t mboard) - { - return _dev->get_master_clock_rate(mboard); - } - - void - usrp_sink_impl::set_clock_rate(double rate, size_t mboard) - { - return _dev->set_master_clock_rate(rate, mboard); - } - - ::uhd::time_spec_t - usrp_sink_impl::get_time_now(size_t mboard) - { - return _dev->get_time_now(mboard); - } - - ::uhd::time_spec_t - usrp_sink_impl::get_time_last_pps(size_t mboard) - { - return _dev->get_time_last_pps(mboard); - } - - void - usrp_sink_impl::set_time_now(const ::uhd::time_spec_t &time_spec, - size_t mboard) - { - return _dev->set_time_now(time_spec, mboard); - } - - void - usrp_sink_impl::set_time_next_pps(const ::uhd::time_spec_t &time_spec) - { - return _dev->set_time_next_pps(time_spec); - } - - void - usrp_sink_impl::set_time_unknown_pps(const ::uhd::time_spec_t &time_spec) - { - return _dev->set_time_unknown_pps(time_spec); - } - - void - usrp_sink_impl::set_command_time(const ::uhd::time_spec_t &time_spec, - size_t mboard) - { -#ifdef UHD_USRP_MULTI_USRP_COMMAND_TIME_API - return _dev->set_command_time(time_spec, mboard); -#else - throw std::runtime_error("not implemented in this version"); -#endif - } - - void - usrp_sink_impl::clear_command_time(size_t mboard) - { -#ifdef UHD_USRP_MULTI_USRP_COMMAND_TIME_API - return _dev->clear_command_time(mboard); -#else - throw std::runtime_error("not implemented in this version"); -#endif - } - ::uhd::usrp::dboard_iface::sptr usrp_sink_impl::get_dboard_iface(size_t chan) { @@ -528,24 +316,6 @@ namespace gr { return _dev->get_tx_dboard_iface(chan); } - ::uhd::usrp::multi_usrp::sptr - usrp_sink_impl::get_device(void) - { - return _dev; - } - - void - usrp_sink_impl::set_user_register(const uint8_t addr, - const uint32_t data, - size_t mboard) - { -#ifdef UHD_USRP_MULTI_USRP_USER_REGS_API - _dev->set_user_register(addr, data, mboard); -#else - throw std::runtime_error("not implemented in this version"); -#endif - } - void usrp_sink_impl::set_stream_args(const ::uhd::stream_args_t &stream_args) { @@ -644,7 +414,7 @@ namespace gr { // Go through tag list until something indicates the end of a burst. bool found_time_tag = false; bool found_eob = false; - // For commands that are in the middle in the burst: + // For commands that are in the middle of the burst: std::vector<pmt::pmt_t> commands_in_burst; // Store the command uint64_t in_burst_cmd_offset = 0; // Store its position BOOST_FOREACH(const tag_t &my_tag, _tags) { @@ -660,7 +430,7 @@ namespace gr { * * This includes: * - tx_time - * - tx_command + * - tx_command TODO should also work end-of-burst * - tx_sob * - length tags * @@ -672,6 +442,7 @@ namespace gr { max_count = my_tag_count; break; } + // TODO set the command time from the sample time msg_handler_command(value); } @@ -727,12 +498,16 @@ namespace gr { else if (pmt::equal(key, FREQ_KEY) && my_tag_count == samp0_count) { // If it's on the first sample, immediately do the tune: GR_LOG_DEBUG(d_debug_logger, boost::format("Received tx_freq on start of burst.")); - msg_handler_command(pmt::cons(pmt::mp("freq"), value)); + pmt::pmt_t freq_cmd = pmt::make_dict(); + freq_cmd = pmt::dict_add(freq_cmd, pmt::mp("freq"), value); + msg_handler_command(freq_cmd); } else if(pmt::equal(key, FREQ_KEY)) { // If it's not on the first sample, queue this command and only tx until here: GR_LOG_DEBUG(d_debug_logger, boost::format("Received tx_freq mid-burst.")); - commands_in_burst.push_back(pmt::cons(pmt::mp("freq"), value)); + pmt::pmt_t freq_cmd = pmt::make_dict(); + freq_cmd = pmt::dict_add(freq_cmd, pmt::mp("freq"), value); + commands_in_burst.push_back(freq_cmd); max_count = my_tag_count + 1; in_burst_cmd_offset = my_tag_count; } @@ -763,7 +538,7 @@ namespace gr { // until before the tag, so it will be on the first sample of the next run. if (not commands_in_burst.empty()) { if (not found_eob) { - // If it's in the middle of a burst, only send() until before the tag + // ...then it's in the middle of a burst, only send() until before the tag max_count = in_burst_cmd_offset; } else if (in_burst_cmd_offset < max_count) { BOOST_FOREACH(const pmt::pmt_t &cmd_pmt, commands_in_burst) { @@ -843,69 +618,5 @@ namespace gr { return true; } - - /************** External interfaces (RPC + Message passing) ********************/ - void usrp_sink_impl::msg_handler_command(pmt::pmt_t msg) - { - std::string command; - pmt::pmt_t cmd_value; - int chan = -1; - if (not _unpack_chan_command(command, cmd_value, chan, msg)) { - GR_LOG_ALERT(d_logger, boost::format("Error while unpacking command PMT: %s") % msg); - return; - } - GR_LOG_DEBUG(d_debug_logger, boost::format("Received command: %s") % command); - try { - if (command == "freq") { - _chans_to_tune = _update_vector_from_cmd_val<double>( - _curr_freq, chan, pmt::to_double(cmd_value), true - ); - _set_center_freq_from_internals_allchans(); - } else if (command == "lo_offset") { - _chans_to_tune = _update_vector_from_cmd_val<double>( - _curr_lo_offset, chan, pmt::to_double(cmd_value), true - ); - _set_center_freq_from_internals_allchans(); - } else if (command == "gain") { - boost::dynamic_bitset<> chans_to_change = _update_vector_from_cmd_val<double>( - _curr_gain, chan, pmt::to_double(cmd_value), true - ); - if (chans_to_change.any()) { - for (size_t i = 0; i < chans_to_change.size(); i++) { - if (chans_to_change[i]) { - set_gain(_curr_gain[i], i); - } - } - } - } else { - GR_LOG_ALERT(d_logger, boost::format("Received unknown command: %s") % command); - } - } catch (pmt::wrong_type &e) { - GR_LOG_ALERT(d_logger, boost::format("Received command '%s' with invalid command value: %s") % command % cmd_value); - } - } - - void - usrp_sink_impl::setup_rpc() - { -#ifdef GR_CTRLPORT - add_rpc_variable( - rpcbasic_sptr(new rpcbasic_register_get<usrp_sink, double>( - alias(), "samp_rate", - &usrp_sink::get_samp_rate, - pmt::mp(100000.0f), pmt::mp(25000000.0f), pmt::mp(1000000.0f), - "sps", "TX Sample Rate", RPC_PRIVLVL_MIN, - DISPTIME | DISPOPTSTRIP))); - - add_rpc_variable( - rpcbasic_sptr(new rpcbasic_register_set<usrp_sink, double>( - alias(), "samp_rate", - &usrp_sink::set_samp_rate, - pmt::mp(100000.0f), pmt::mp(25000000.0f), pmt::mp(1000000.0f), - "sps", "TX Sample Rate", - RPC_PRIVLVL_MIN, DISPNULL))); -#endif /* GR_CTRLPORT */ - } - } /* namespace uhd */ } /* namespace gr */ diff --git a/gr-uhd/lib/usrp_sink_impl.h b/gr-uhd/lib/usrp_sink_impl.h index e0cb5a9a60..1575378d21 100644 --- a/gr-uhd/lib/usrp_sink_impl.h +++ b/gr-uhd/lib/usrp_sink_impl.h @@ -20,9 +20,9 @@ * Boston, MA 02110-1301, USA. */ +#include "usrp_block_impl.h" #include <gnuradio/uhd/usrp_sink.h> #include <uhd/convert.hpp> -#include "usrp_common.h" static const pmt::pmt_t SOB_KEY = pmt::string_to_symbol("tx_sob"); static const pmt::pmt_t EOB_KEY = pmt::string_to_symbol("tx_eob"); @@ -52,7 +52,7 @@ namespace gr { /*********************************************************************** * UHD Multi USRP Sink Impl **********************************************************************/ - class usrp_sink_impl : public usrp_sink, public usrp_common_impl + class usrp_sink_impl : public usrp_sink, public usrp_block_impl { public: usrp_sink_impl(const ::uhd::device_addr_t &device_addr, @@ -60,8 +60,6 @@ namespace gr { const std::string &length_tag_name); ~usrp_sink_impl(); - void setup_rpc(); - ::uhd::dict<std::string, std::string> get_usrp_info(size_t chan); double get_samp_rate(void); ::uhd::meta_range_t get_samp_rates(void); @@ -77,17 +75,7 @@ namespace gr { std::vector<std::string> get_antennas(size_t chan); ::uhd::sensor_value_t get_sensor(const std::string &name, size_t chan); std::vector<std::string> get_sensor_names(size_t chan); - ::uhd::sensor_value_t get_mboard_sensor(const std::string &name, size_t mboard); - std::vector<std::string> get_mboard_sensor_names(size_t mboard); - std::string get_time_source(const size_t mboard); - std::vector<std::string> get_time_sources(const size_t mboard); - std::string get_clock_source(const size_t mboard); - std::vector<std::string> get_clock_sources(const size_t mboard); - double get_clock_rate(size_t mboard); - ::uhd::time_spec_t get_time_now(size_t mboard = 0); - ::uhd::time_spec_t get_time_last_pps(size_t mboard); ::uhd::usrp::dboard_iface::sptr get_dboard_iface(size_t chan); - ::uhd::usrp::multi_usrp::sptr get_device(void); void set_subdev_spec(const std::string &spec, size_t mboard); std::string get_subdev_spec(size_t mboard); @@ -103,16 +91,6 @@ namespace gr { ::uhd::freq_range_t get_bandwidth_range(size_t chan); void set_dc_offset(const std::complex<double> &offset, size_t chan); void set_iq_balance(const std::complex<double> &correction, size_t chan); - void set_clock_config(const ::uhd::clock_config_t &clock_config, size_t mboard); - void set_time_source(const std::string &source, const size_t mboard); - void set_clock_source(const std::string &source, const size_t mboard); - void set_clock_rate(double rate, size_t mboard); - void set_time_now(const ::uhd::time_spec_t &time_spec, size_t mboard); - void set_time_next_pps(const ::uhd::time_spec_t &time_spec); - void set_time_unknown_pps(const ::uhd::time_spec_t &time_spec); - void set_command_time(const ::uhd::time_spec_t &time_spec, size_t mboard); - void clear_command_time(size_t mboard); - void set_user_register(const uint8_t addr, const uint32_t data, size_t mboard); void set_stream_args(const ::uhd::stream_args_t &stream_args); void set_start_time(const ::uhd::time_spec_t &time); @@ -126,14 +104,8 @@ namespace gr { inline void tag_work(int &ninput_items); private: - /*! \brief Run through all 'lock' sensors and make sure they are actually locked. - */ - bool _check_sensors_locked(); - //! Like set_center_freq(), but uses _curr_freq and _curr_lo_offset ::uhd::tune_result_t _set_center_freq_from_internals(size_t chan); - //! Calls _set_center_freq_from_internals() on all channels - void _set_center_freq_from_internals_allchans(); #ifdef GR_UHD_USE_STREAM_API ::uhd::tx_streamer::sptr _tx_stream; @@ -141,27 +113,11 @@ namespace gr { ::uhd::tx_metadata_t _metadata; double _sample_rate; - //stream tags related stuff std::vector<tag_t> _tags; const pmt::pmt_t _length_tag_key; long _nitems_to_send; - /****** Command interface related **********/ - //! Stores a list of commands for later execution - std::vector<pmt::pmt_t> _pending_cmds; - //! Receives commands and handles them - void msg_handler_command(pmt::pmt_t msg); - //! Stores the last value we told the USRP to tune to for every channel - // (this is not necessarily the true value the USRP is currently tuned to!). - // We could theoretically ask the device, but during streaming, we want to minimize - // communication with the USRP. - std::vector<double> _curr_freq; - //! Stores the last value we told the USRP to have the LO offset for every channel. - std::vector<double> _curr_lo_offset; - //! Stores the last gain value we told the USRP to have for every channel. - std::vector<double> _curr_gain; - boost::dynamic_bitset<> _chans_to_tune; }; } /* namespace uhd */ diff --git a/gr-uhd/lib/usrp_source_impl.cc b/gr-uhd/lib/usrp_source_impl.cc index 13457402be..6f0283e71f 100644 --- a/gr-uhd/lib/usrp_source_impl.cc +++ b/gr-uhd/lib/usrp_source_impl.cc @@ -20,10 +20,8 @@ * Boston, MA 02110-1301, USA. */ -#include "usrp_common.h" #include "usrp_source_impl.h" #include "gr_uhd_common.h" -#include <gnuradio/io_signature.h> #include <boost/format.hpp> #include <boost/thread/thread.hpp> #include <boost/make_shared.hpp> @@ -64,49 +62,21 @@ namespace gr { usrp_source_impl::usrp_source_impl(const ::uhd::device_addr_t &device_addr, const ::uhd::stream_args_t &stream_args): - sync_block("gr uhd usrp source", + usrp_block("gr uhd usrp source", io_signature::make(0, 0, 0), args_to_io_sig(stream_args)), - usrp_common_impl(device_addr, stream_args, ""), + usrp_block_impl(device_addr, stream_args, ""), _tag_now(false) { std::stringstream str; str << name() << unique_id(); _id = pmt::string_to_symbol(str.str()); - message_port_register_in(pmt::mp("command")); - set_msg_handler( - pmt::mp("command"), - boost::bind(&usrp_source_impl::msg_handler_command, this, _1) - ); - - _check_sensors_locked(); - } - - bool usrp_source_impl::_check_sensors_locked() - { - bool clocks_locked = true; - - // Check ref lock for all mboards - for (size_t mboard_index = 0; mboard_index < _dev->get_num_mboards(); mboard_index++) { - std::string sensor_name = "ref_locked"; - if (_dev->get_clock_source(mboard_index) == "internal") { - continue; - } - else if (_dev->get_clock_source(mboard_index) == "mimo") { - sensor_name = "mimo_locked"; - } - if (not _wait_for_locked_sensor( - get_mboard_sensor_names(mboard_index), - sensor_name, - boost::bind(&usrp_source_impl::get_mboard_sensor, this, _1, mboard_index) - )) { - GR_LOG_WARN(d_logger, boost::format("Sensor '%s' failed to lock within timeout on motherboard %d.") % sensor_name % mboard_index); - clocks_locked = false; - } - } - - return clocks_locked; + _samp_rate = this->get_samp_rate(); + _center_freq = this->get_center_freq(0); +#ifdef GR_UHD_USE_STREAM_API + _samps_per_packet = 1; +#endif } usrp_source_impl::~usrp_source_impl() @@ -175,6 +145,8 @@ namespace gr { return res; } + SET_CENTER_FREQ_FROM_INTERNALS(usrp_source_impl, set_rx_freq); + double usrp_source_impl::get_center_freq(size_t chan) { @@ -364,150 +336,6 @@ namespace gr { return _dev->get_rx_sensor_names(chan); } - ::uhd::sensor_value_t - usrp_source_impl::get_mboard_sensor(const std::string &name, size_t mboard) - { - return _dev->get_mboard_sensor(name, mboard); - } - - std::vector<std::string> - usrp_source_impl::get_mboard_sensor_names(size_t mboard) - { - return _dev->get_mboard_sensor_names(mboard); - } - - void - usrp_source_impl::set_clock_config(const ::uhd::clock_config_t &clock_config, - size_t mboard) - { - return _dev->set_clock_config(clock_config, mboard); - } - - void - usrp_source_impl::set_time_source(const std::string &source, - const size_t mboard) - { -#ifdef UHD_USRP_MULTI_USRP_REF_SOURCES_API - return _dev->set_time_source(source, mboard); -#else - throw std::runtime_error("not implemented in this version"); -#endif - } - - std::string - usrp_source_impl::get_time_source(const size_t mboard) - { -#ifdef UHD_USRP_MULTI_USRP_REF_SOURCES_API - return _dev->get_time_source(mboard); -#else - throw std::runtime_error("not implemented in this version"); -#endif - } - - std::vector<std::string> - usrp_source_impl::get_time_sources(const size_t mboard) - { -#ifdef UHD_USRP_MULTI_USRP_REF_SOURCES_API - return _dev->get_time_sources(mboard); -#else - throw std::runtime_error("not implemented in this version"); -#endif - } - - void - usrp_source_impl::set_clock_source(const std::string &source, - const size_t mboard) - { -#ifdef UHD_USRP_MULTI_USRP_REF_SOURCES_API - return _dev->set_clock_source(source, mboard); -#else - throw std::runtime_error("not implemented in this version"); -#endif - } - - std::string - usrp_source_impl::get_clock_source(const size_t mboard) - { -#ifdef UHD_USRP_MULTI_USRP_REF_SOURCES_API - return _dev->get_clock_source(mboard); -#else - throw std::runtime_error("not implemented in this version"); -#endif - } - - std::vector<std::string> - usrp_source_impl::get_clock_sources(const size_t mboard) - { -#ifdef UHD_USRP_MULTI_USRP_REF_SOURCES_API - return _dev->get_clock_sources(mboard); -#else - throw std::runtime_error("not implemented in this version"); -#endif - } - - double - usrp_source_impl::get_clock_rate(size_t mboard) - { - return _dev->get_master_clock_rate(mboard); - } - - void - usrp_source_impl::set_clock_rate(double rate, size_t mboard) - { - return _dev->set_master_clock_rate(rate, mboard); - } - - ::uhd::time_spec_t - usrp_source_impl::get_time_now(size_t mboard) - { - return _dev->get_time_now(mboard); - } - - ::uhd::time_spec_t - usrp_source_impl::get_time_last_pps(size_t mboard) - { - return _dev->get_time_last_pps(mboard); - } - - void - usrp_source_impl::set_time_now(const ::uhd::time_spec_t &time_spec, - size_t mboard) - { - return _dev->set_time_now(time_spec, mboard); - } - - void - usrp_source_impl::set_time_next_pps(const ::uhd::time_spec_t &time_spec) - { - return _dev->set_time_next_pps(time_spec); - } - - void - usrp_source_impl::set_time_unknown_pps(const ::uhd::time_spec_t &time_spec) - { - return _dev->set_time_unknown_pps(time_spec); - } - - void - usrp_source_impl::set_command_time(const ::uhd::time_spec_t &time_spec, size_t mboard) - { -#ifdef UHD_USRP_MULTI_USRP_COMMAND_TIME_API - return _dev->set_command_time(time_spec, mboard); -#else - throw std::runtime_error("not implemented in this version"); -#endif - } - - void - usrp_source_impl::clear_command_time(size_t mboard) - { -#ifdef UHD_USRP_MULTI_USRP_COMMAND_TIME_API - return _dev->clear_command_time(mboard); -#else - throw std::runtime_error("not implemented in this version"); -#endif - } - ::uhd::usrp::dboard_iface::sptr usrp_source_impl::get_dboard_iface(size_t chan) { @@ -515,24 +343,6 @@ namespace gr { return _dev->get_rx_dboard_iface(chan); } - ::uhd::usrp::multi_usrp::sptr - usrp_source_impl::get_device(void) - { - return _dev; - } - - void - usrp_source_impl::set_user_register(const uint8_t addr, - const uint32_t data, - size_t mboard) - { -#ifdef UHD_USRP_MULTI_USRP_USER_REGS_API - _dev->set_user_register(addr, data, mboard); -#else - throw std::runtime_error("not implemented in this version"); -#endif - } - void usrp_source_impl::set_stream_args(const ::uhd::stream_args_t &stream_args) { @@ -743,59 +553,5 @@ namespace gr { return num_samps; } - - /************** External interfaces (RPC + Message passing) ********************/ - void usrp_source_impl::msg_handler_command(pmt::pmt_t msg) - { - std::string command; - pmt::pmt_t cmd_value; - int chan = -1; - if (not _unpack_chan_command(command, cmd_value, chan, msg)) { - GR_LOG_ALERT(d_logger, "Error while unpacking command PMT."); - } - if (command == "freq") { - double freq = pmt::to_double(cmd_value); - for (size_t i = 0; i < _nchan; i++) { - if (chan == -1 || chan == int(i)) { - set_center_freq(freq, i); - } - } - // TODO: implement - //} else if (command == "lo_offset") { - //; - } else if (command == "gain") { - double gain = pmt::to_double(cmd_value); - for (size_t i = 0; i < _nchan; i++) { - if (chan == -1 || chan == int(i)) { - set_gain(gain, i); - } - } - } else { - GR_LOG_ALERT(d_logger, boost::format("Received unknown command: %s") % command); - } - } - - void - usrp_source_impl::setup_rpc() - { -#ifdef GR_CTRLPORT - add_rpc_variable( - rpcbasic_sptr(new rpcbasic_register_get<usrp_source, double>( - alias(), "samp_rate", - &usrp_source::get_samp_rate, - pmt::mp(100000.0f), pmt::mp(25000000.0f), pmt::mp(1000000.0f), - "sps", "RX Sample Rate", RPC_PRIVLVL_MIN, - DISPTIME | DISPOPTSTRIP))); - - add_rpc_variable( - rpcbasic_sptr(new rpcbasic_register_set<usrp_source, double>( - alias(), "samp_rate", - &usrp_source::set_samp_rate, - pmt::mp(100000.0f), pmt::mp(25000000.0f), pmt::mp(1000000.0f), - "sps", "RX Sample Rate", - RPC_PRIVLVL_MIN, DISPNULL))); -#endif /* GR_CTRLPORT */ - } - } /* namespace uhd */ } /* namespace gr */ diff --git a/gr-uhd/lib/usrp_source_impl.h b/gr-uhd/lib/usrp_source_impl.h index 0cbbe2b16b..9f6fc1a759 100644 --- a/gr-uhd/lib/usrp_source_impl.h +++ b/gr-uhd/lib/usrp_source_impl.h @@ -20,10 +20,10 @@ * Boston, MA 02110-1301, USA. */ +#include "usrp_block_impl.h" #include <gnuradio/uhd/usrp_source.h> #include <uhd/convert.hpp> #include <boost/thread/mutex.hpp> -#include "usrp_common.h" static const pmt::pmt_t TIME_KEY = pmt::string_to_symbol("rx_time"); static const pmt::pmt_t RATE_KEY = pmt::string_to_symbol("rx_rate"); @@ -51,15 +51,13 @@ namespace gr { /*********************************************************************** * UHD Multi USRP Source Impl **********************************************************************/ - class usrp_source_impl : public usrp_source, public usrp_common_impl + class usrp_source_impl : public usrp_source, public usrp_block_impl { public: usrp_source_impl(const ::uhd::device_addr_t &device_addr, const ::uhd::stream_args_t &stream_args); ~usrp_source_impl(); - void setup_rpc(); - // Get Commands ::uhd::dict<std::string, std::string> get_usrp_info(size_t chan); std::string get_subdev_spec(size_t mboard); @@ -77,17 +75,7 @@ namespace gr { std::vector<std::string> get_antennas(size_t chan); ::uhd::sensor_value_t get_sensor(const std::string &name, size_t chan); std::vector<std::string> get_sensor_names(size_t chan); - ::uhd::sensor_value_t get_mboard_sensor(const std::string &name, size_t mboard); - std::vector<std::string> get_mboard_sensor_names(size_t mboard); - std::string get_time_source(const size_t mboard); - std::vector<std::string> get_time_sources(const size_t mboard); - std::string get_clock_source(const size_t mboard); - std::vector<std::string> get_clock_sources(const size_t mboard); - double get_clock_rate(size_t mboard); - ::uhd::time_spec_t get_time_now(size_t mboard = 0); - ::uhd::time_spec_t get_time_last_pps(size_t mboard); ::uhd::usrp::dboard_iface::sptr get_dboard_iface(size_t chan); - ::uhd::usrp::multi_usrp::sptr get_device(void); // Set Commands void set_subdev_spec(const std::string &spec, size_t mboard); @@ -105,20 +93,10 @@ namespace gr { void set_dc_offset(const std::complex<double> &offset, size_t chan); void set_auto_iq_balance(const bool enable, size_t chan); void set_iq_balance(const std::complex<double> &correction, size_t chan); - void set_clock_config(const ::uhd::clock_config_t &clock_config, size_t mboard); - void set_time_source(const std::string &source, const size_t mboard); - void set_clock_source(const std::string &source, const size_t mboard); - void set_clock_rate(double rate, size_t mboard); - void set_time_now(const ::uhd::time_spec_t &time_spec, size_t mboard); - void set_time_next_pps(const ::uhd::time_spec_t &time_spec); - void set_time_unknown_pps(const ::uhd::time_spec_t &time_spec); - void set_command_time(const ::uhd::time_spec_t &time_spec, size_t mboard); - void set_user_register(const uint8_t addr, const uint32_t data, size_t mboard); void set_stream_args(const ::uhd::stream_args_t &stream_args); void set_start_time(const ::uhd::time_spec_t &time); void issue_stream_cmd(const ::uhd::stream_cmd_t &cmd); - void clear_command_time(size_t mboard); void flush(void); bool start(void); bool stop(void); @@ -129,9 +107,9 @@ namespace gr { gr_vector_void_star &output_items); private: - /*! \brief Run through all 'lock' sensors and make sure they are actually locked. - */ - bool _check_sensors_locked(); + //! Like set_center_freq(), but uses _curr_freq and _curr_lo_offset + ::uhd::tune_result_t _set_center_freq_from_internals(size_t chan); + #ifdef GR_UHD_USE_STREAM_API ::uhd::rx_streamer::sptr _rx_stream; size_t _samps_per_packet; @@ -145,21 +123,6 @@ namespace gr { double _center_freq; boost::recursive_mutex d_mutex; - - /****** Command interface related **********/ - //! Receives commands and handles them - void msg_handler_command(pmt::pmt_t msg); - //! Stores the last value we told the USRP to tune to for every channel - // (this is not necessarily the true value the USRP is currently tuned to!). - // We could theoretically ask the device, but during streaming, we want to minimize - // communication with the USRP. - std::vector<double> _curr_freq; - //! Stores the last value we told the USRP to have the LO offset for every channel. - std::vector<double> _curr_lo_offset; - //! Stores the last gain value we told the USRP to have for every channel. - std::vector<double> _curr_gain; - boost::dynamic_bitset<> _chans_to_tune; - bool _call_tune; }; } /* namespace uhd */ diff --git a/gr-uhd/swig/uhd_swig.i b/gr-uhd/swig/uhd_swig.i index a4b1528439..108f544da3 100644 --- a/gr-uhd/swig/uhd_swig.i +++ b/gr-uhd/swig/uhd_swig.i @@ -54,6 +54,8 @@ #include <gnuradio/uhd/amsg_source.h> %} +%include "gnuradio/uhd/usrp_block.h" + //////////////////////////////////////////////////////////////////////// // used types //////////////////////////////////////////////////////////////////////// diff --git a/grc/base/Block.py b/grc/base/Block.py index afe326bbf4..5e8a7179ac 100644 --- a/grc/base/Block.py +++ b/grc/base/Block.py @@ -19,12 +19,17 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA from . import odict from . Constants import ADVANCED_PARAM_TAB, DEFAULT_PARAM_TAB +from . Constants import BLOCK_FLAG_THROTTLE, BLOCK_FLAG_DISABLE_BYPASS +from . Constants import BLOCK_ENABLED, BLOCK_BYPASSED, BLOCK_DISABLED from Element import Element from Cheetah.Template import Template from UserDict import UserDict from itertools import imap +from .. gui import Messages + + class TemplateArg(UserDict): """ A cheetah template argument created from a param. @@ -46,11 +51,16 @@ class TemplateArg(UserDict): def __call__(self): return self._param.get_evaluated() -def _get_keys(lst): return [elem.get_key() for elem in lst] + +def _get_keys(lst): + return [elem.get_key() for elem in lst] + + def _get_elem(lst, key): try: return lst[_get_keys(lst).index(key)] except ValueError: raise ValueError, 'Key "%s" not found in %s.'%(key, _get_keys(lst)) + class Block(Element): def __init__(self, flow_graph, n): @@ -73,6 +83,10 @@ class Block(Element): self._name = n.find('name') self._key = n.find('key') self._category = n.find('category') or '' + self._flags = n.find('flags') or '' + # Backwards compatibility + if n.find('throttle') and BLOCK_FLAG_THROTTLE not in self._flags: + self._flags += BLOCK_FLAG_THROTTLE self._grc_source = n.find('grc_source') or '' self._block_wrapper_path = n.find('block_wrapper_path') self._bussify_sink = n.find('bus_sink') @@ -143,6 +157,10 @@ class Block(Element): and (self._key != "pad_sink")) is_variable = self._key.startswith('variable') + # Disable blocks that are virtual/pads or variables + if not is_not_virtual_or_pad or is_variable: + self._flags += BLOCK_FLAG_DISABLE_BYPASS + if is_not_virtual_or_pad and not is_variable: self.get_params().append(self.get_parent().get_parent().Param( block=self, @@ -197,7 +215,6 @@ class Block(Element): }) )) - def back_ofthe_bus(self, portlist): portlist.sort(key=lambda p: p._type == 'bus') @@ -205,6 +222,35 @@ class Block(Element): buslist = [p for p in ports if p._type == 'bus'] return buslist or ports + # Main functions to get and set the block state + # Also kept get_enabled and set_enabled to keep compatibility + def get_state(self): + """ + Gets the block's current state. + + Returns: + ENABLED - 0 + BYPASSED - 1 + DISABLED - 2 + """ + try: return int(eval(self.get_param('_enabled').get_value())) + except: return BLOCK_ENABLED + + def set_state(self, state): + """ + Sets the state for the block. + + Args: + ENABLED - 0 + BYPASSED - 1 + DISABLED - 2 + """ + if state in [BLOCK_ENABLED, BLOCK_BYPASSED, BLOCK_DISABLED]: + self.get_param('_enabled').set_value(str(state)) + else: + self.get_param('_enabled').set_value(str(BLOCK_ENABLED)) + + # Enable/Disable Aliases def get_enabled(self): """ Get the enabled state of the block. @@ -212,8 +258,7 @@ class Block(Element): Returns: true for enabled """ - try: return eval(self.get_param('_enabled').get_value()) - except: return True + return not (self.get_state() == BLOCK_DISABLED) def set_enabled(self, enabled): """ @@ -221,8 +266,45 @@ class Block(Element): Args: enabled: true for enabled + + Returns: + True if block changed state + """ + old_state = self.get_state() + new_state = BLOCK_ENABLED if enabled else BLOCK_DISABLED + self.set_state(new_state) + return old_state != new_state + + # Block bypassing + def get_bypassed(self): + """ + Check if the block is bypassed """ - self.get_param('_enabled').set_value(str(enabled)) + return self.get_state() == BLOCK_BYPASSED + + def set_bypassed(self): + """ + Bypass the block + + Returns: + True if block chagnes state + """ + if self.get_state() != BLOCK_BYPASSED and self.can_bypass(): + self.set_state(BLOCK_BYPASSED) + return True + return False + + def can_bypass(self): + """ Check the number of sinks and sources and see if this block can be bypassed """ + # Check to make sure this is a single path block + # Could possibly support 1 to many blocks + if len(self.get_sources()) != 1 or len(self.get_sinks()) != 1: + return False + if not (self.get_sources()[0].get_type() == self.get_sinks()[0].get_type()): + return False + if self.bypass_disabled(): + return False + return True def __str__(self): return 'Block - %s - %s(%s)'%(self.get_id(), self.get_name(), self.get_key()) @@ -240,6 +322,10 @@ class Block(Element): def get_block_wrapper_path(self): return self._block_wrapper_path def get_comment(self): return self.get_param('comment').get_value() + def get_flags(self): return self._flags + def throtteling(self): return BLOCK_FLAG_THROTTLE in self._flags + def bypass_disabled(self): return BLOCK_FLAG_DISABLE_BYPASS in self._flags + ############################################## # Access Params ############################################## @@ -414,7 +500,7 @@ class Block(Element): """ n = odict() n['key'] = self.get_key() - n['param'] = map(lambda p: p.export_data(), self.get_params()) + n['param'] = map(lambda p: p.export_data(), sorted(self.get_params(), key=str)) if 'bus' in map(lambda a: a.get_type(), self.get_sinks()): n['bus_sink'] = str(1); if 'bus' in map(lambda a: a.get_type(), self.get_sources()): diff --git a/grc/base/Constants.py b/grc/base/Constants.py index efae0ecbb5..0c5116c604 100644 --- a/grc/base/Constants.py +++ b/grc/base/Constants.py @@ -38,3 +38,11 @@ DOMAIN_DTD = os.path.join(DATA_DIR, 'domain.dtd') GR_STREAM_DOMAIN = "gr_stream" GR_MESSAGE_DOMAIN = "gr_message" DEFAULT_DOMAIN = GR_STREAM_DOMAIN + +BLOCK_FLAG_THROTTLE = 'throttle' +BLOCK_FLAG_DISABLE_BYPASS = 'disable_bypass' + +# Block States +BLOCK_DISABLED = 0 +BLOCK_ENABLED = 1 +BLOCK_BYPASSED = 2 diff --git a/grc/base/FlowGraph.py b/grc/base/FlowGraph.py index fb25b46821..7fd8df5f64 100644 --- a/grc/base/FlowGraph.py +++ b/grc/base/FlowGraph.py @@ -78,9 +78,6 @@ class FlowGraph(Element): bus_structure = block.form_bus_structure('sink'); if 'bus' in map(lambda a: a.get_type(), get_p_gui()): - - - if len(get_p_gui()) > len(bus_structure): times = range(len(bus_structure), len(get_p_gui())); for i in times: @@ -100,8 +97,6 @@ class FlowGraph(Element): port = block.get_parent().get_parent().Port(block=block, n=n, dir=direc); get_p().append(port); - - for child in self.get_children(): child.rewrite() refactor_bus_structure(); @@ -126,13 +121,13 @@ class FlowGraph(Element): def get_block(self, id): return filter(lambda b: b.get_id() == id, self.get_blocks())[0] def get_blocks_unordered(self): return filter(lambda e: e.is_block(), self.get_elements()) def get_blocks(self): - blocks = self.get_blocks_unordered(); - for i in range(len(blocks)): - if blocks[i].get_key() == 'variable': - blk = blocks[i]; - blocks.remove(blk); - blocks.insert(1, blk); - return blocks; + # refactored the slow, ugly version + # don't know why we need this here, using it for sorted export_data() + return sorted(self.get_blocks_unordered(), key=lambda b: ( + b.get_key() != 'options', # options to the front + not b.get_key().startswith('variable'), # then vars + str(b) + )) def get_connections(self): return filter(lambda e: e.is_connection(), self.get_elements()) def get_children(self): return self.get_elements() def get_elements(self): @@ -159,6 +154,15 @@ class FlowGraph(Element): """ return filter(lambda b: b.get_enabled(), self.get_blocks()) + def get_bypassed_blocks(self): + """ + Get a list of all blocks that are bypassed. + + Returns: + a list of blocks + """ + return filter(lambda b: b.get_bypassed(), self.get_blocks()) + def get_enabled_connections(self): """ Get a list of all connections that are enabled. @@ -166,7 +170,41 @@ class FlowGraph(Element): Returns: a list of connections """ - return filter(lambda c: c.get_enabled(), self.get_connections()) + # First get all the enabled connections, then get the bypassed blocks. + connections = filter(lambda c: c.get_enabled(), self.get_connections()) + bypassed_blocks = self.get_bypassed_blocks() + + # Bypassing blocks: Need to find all the enabled connections for the block using + # the *connections* object rather than get_connections(). Create new connections + # that bypass the selected block and remove the existing ones. This allows adjacent + # bypassed blocks to see the newly created connections to downstream blocks, + # allowing them to correctly construct bypass connections. + + for block in bypassed_blocks: + # Get the upstream connection (off of the sink ports) + # Use *connections* not get_connections() + get_source_connection = lambda c: c.get_sink() == block.get_sinks()[0] + source_connection = filter(get_source_connection, connections) + # The source connection should never have more than one element. + assert (len(source_connection) == 1) + + # Get the source of the connection. + source_port = source_connection[0].get_source() + + # Loop through all the downstream connections + get_sink_connections = lambda c: c.get_source() == block.get_sources()[0] + for sink in filter(get_sink_connections, connections): + if not sink.get_enabled(): + # Ignore disabled connections + continue + sink_port = sink.get_sink() + connection = self.get_parent().Connection(flow_graph=self, porta=source_port, portb=sink_port) + connections.append(connection) + # Remove this sink connection + connections.remove(sink) + # Remove the source connection + connections.remove(source_connection[0]) + return connections def get_new_block(self, key): """ @@ -250,8 +288,8 @@ class FlowGraph(Element): """ n = odict() n['timestamp'] = self._timestamp - n['block'] = [block.export_data() for block in self.get_blocks()] - n['connection'] = [connection.export_data() for connection in self.get_connections()] + n['block'] = [b.export_data() for b in self.get_blocks()] # already sorted + n['connection'] = [c.export_data() for c in sorted(self.get_connections(), key=str)] instructions = odict({ 'created': self.get_parent().get_version_short(), 'format': FLOW_GRAPH_FILE_FORMAT_VERSION, diff --git a/grc/gui/ActionHandler.py b/grc/gui/ActionHandler.py index fee96624bb..1ce4aeda2d 100644 --- a/grc/gui/ActionHandler.py +++ b/grc/gui/ActionHandler.py @@ -29,7 +29,7 @@ import subprocess import Preferences from threading import Thread import Messages -from .. base import ParseXML +from .. base import ParseXML, Constants from MainWindow import MainWindow from PropsDialog import PropsDialog from ParserErrorsDialog import ParserErrorsDialog @@ -171,6 +171,11 @@ class ActionHandler: self.get_flow_graph().update() self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data()) self.get_page().set_saved(False) + elif action == Actions.BLOCK_BYPASS: + if self.get_flow_graph().bypass_selected(): + self.get_flow_graph().update() + self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data()) + self.get_page().set_saved(False) ################################################## # Cut/Copy/Paste ################################################## @@ -553,23 +558,34 @@ class ActionHandler: ################################################## # Global Actions for all States ################################################## + selected_block = self.get_flow_graph().get_selected_block() + selected_blocks = self.get_flow_graph().get_selected_blocks() + #update general buttons Actions.ERRORS_WINDOW_DISPLAY.set_sensitive(not self.get_flow_graph().is_valid()) Actions.ELEMENT_DELETE.set_sensitive(bool(self.get_flow_graph().get_selected_elements())) - Actions.BLOCK_PARAM_MODIFY.set_sensitive(bool(self.get_flow_graph().get_selected_block())) - Actions.BLOCK_ROTATE_CCW.set_sensitive(bool(self.get_flow_graph().get_selected_blocks())) - Actions.BLOCK_ROTATE_CW.set_sensitive(bool(self.get_flow_graph().get_selected_blocks())) + Actions.BLOCK_PARAM_MODIFY.set_sensitive(bool(selected_block)) + Actions.BLOCK_ROTATE_CCW.set_sensitive(bool(selected_blocks)) + Actions.BLOCK_ROTATE_CW.set_sensitive(bool(selected_blocks)) #update cut/copy/paste - Actions.BLOCK_CUT.set_sensitive(bool(self.get_flow_graph().get_selected_blocks())) - Actions.BLOCK_COPY.set_sensitive(bool(self.get_flow_graph().get_selected_blocks())) + Actions.BLOCK_CUT.set_sensitive(bool(selected_blocks)) + Actions.BLOCK_COPY.set_sensitive(bool(selected_blocks)) Actions.BLOCK_PASTE.set_sensitive(bool(self.clipboard)) - #update enable/disable - Actions.BLOCK_ENABLE.set_sensitive(bool(self.get_flow_graph().get_selected_blocks())) - Actions.BLOCK_DISABLE.set_sensitive(bool(self.get_flow_graph().get_selected_blocks())) - Actions.BLOCK_CREATE_HIER.set_sensitive(bool(self.get_flow_graph().get_selected_blocks())) - Actions.OPEN_HIER.set_sensitive(bool(self.get_flow_graph().get_selected_blocks())) - Actions.BUSSIFY_SOURCES.set_sensitive(bool(self.get_flow_graph().get_selected_blocks())) - Actions.BUSSIFY_SINKS.set_sensitive(bool(self.get_flow_graph().get_selected_blocks())) + #update enable/disable/bypass + can_enable = any(block.get_state() != Constants.BLOCK_ENABLED + for block in selected_blocks) + can_disable = any(block.get_state() != Constants.BLOCK_DISABLED + for block in selected_blocks) + can_bypass_all = all(block.can_bypass() for block in selected_blocks) \ + and any (not block.get_bypassed() for block in selected_blocks) + Actions.BLOCK_ENABLE.set_sensitive(can_enable) + Actions.BLOCK_DISABLE.set_sensitive(can_disable) + Actions.BLOCK_BYPASS.set_sensitive(can_bypass_all) + + Actions.BLOCK_CREATE_HIER.set_sensitive(bool(selected_blocks)) + Actions.OPEN_HIER.set_sensitive(bool(selected_blocks)) + Actions.BUSSIFY_SOURCES.set_sensitive(bool(selected_blocks)) + Actions.BUSSIFY_SINKS.set_sensitive(bool(selected_blocks)) Actions.RELOAD_BLOCKS.set_sensitive(True) Actions.FIND_BLOCKS.set_sensitive(True) #set the exec and stop buttons diff --git a/grc/gui/Actions.py b/grc/gui/Actions.py index b2b3a76386..a028a33a11 100644 --- a/grc/gui/Actions.py +++ b/grc/gui/Actions.py @@ -247,6 +247,12 @@ BLOCK_DISABLE = Action( stock_id=gtk.STOCK_DISCONNECT, keypresses=(gtk.keysyms.d, NO_MODS_MASK), ) +BLOCK_BYPASS = Action( + label='_Bypass', + tooltip='Bypass the selected block', + stock_id=gtk.STOCK_MEDIA_FORWARD, + keypresses=(gtk.keysyms.b, NO_MODS_MASK), +) TOGGLE_SNAP_TO_GRID = ToggleAction( label='_Snap to grid', tooltip='Snap blocks to a grid for an easier connection alignment', diff --git a/grc/gui/Bars.py b/grc/gui/Bars.py index 40ce20536c..abcc3c6434 100644 --- a/grc/gui/Bars.py +++ b/grc/gui/Bars.py @@ -49,6 +49,7 @@ TOOLBAR_LIST = ( None, Actions.BLOCK_ENABLE, Actions.BLOCK_DISABLE, + Actions.BLOCK_BYPASS, Actions.TOGGLE_HIDE_DISABLED_BLOCKS, None, Actions.FIND_BLOCKS, @@ -85,6 +86,7 @@ MENU_BAR_LIST = ( None, Actions.BLOCK_ENABLE, Actions.BLOCK_DISABLE, + Actions.BLOCK_BYPASS, None, Actions.BLOCK_PARAM_MODIFY, ]), @@ -134,6 +136,7 @@ CONTEXT_MENU_LIST = [ Actions.BLOCK_ROTATE_CW, Actions.BLOCK_ENABLE, Actions.BLOCK_DISABLE, + Actions.BLOCK_BYPASS, None, (gtk.Action('More', '_More', None, None), [ Actions.BLOCK_CREATE_HIER, diff --git a/grc/gui/Block.py b/grc/gui/Block.py index 60f19fc1a4..83706ed1aa 100644 --- a/grc/gui/Block.py +++ b/grc/gui/Block.py @@ -145,7 +145,9 @@ class Block(Element): """Create the labels for the signal block.""" Element.create_labels(self) self._bg_color = self.is_dummy_block() and Colors.MISSING_BLOCK_BACKGROUND_COLOR or \ + self.get_bypassed() and Colors.BLOCK_BYPASSED_COLOR or \ self.get_enabled() and Colors.BLOCK_ENABLED_COLOR or Colors.BLOCK_DISABLED_COLOR + layouts = list() #create the main layout layout = gtk.DrawingArea().create_pango_layout('') diff --git a/grc/gui/Colors.py b/grc/gui/Colors.py index f64106b03f..52c95e8edf 100644 --- a/grc/gui/Colors.py +++ b/grc/gui/Colors.py @@ -38,6 +38,7 @@ try: #block color constants BLOCK_ENABLED_COLOR = get_color('#F1ECFF') BLOCK_DISABLED_COLOR = get_color('#CCCCCC') + BLOCK_BYPASSED_COLOR = get_color('#FFFFE6') #connection color constants CONNECTION_ENABLED_COLOR = get_color('black') CONNECTION_DISABLED_COLOR = get_color('#BBBBBB') diff --git a/grc/gui/FlowGraph.py b/grc/gui/FlowGraph.py index 97f814f1bf..bf6e1eed78 100644 --- a/grc/gui/FlowGraph.py +++ b/grc/gui/FlowGraph.py @@ -211,9 +211,21 @@ class FlowGraph(Element): """ changed = False for selected_block in self.get_selected_blocks(): - if selected_block.get_enabled() != enable: - selected_block.set_enabled(enable) - changed = True + if selected_block.set_enabled(enable): changed = True + return changed + + def bypass_selected(self): + """ + Bypass the selected blocks. + + Args: + None + Returns: + true if changed + """ + changed = False + for selected_block in self.get_selected_blocks(): + if selected_block.set_bypassed(): changed = True return changed def move_selected(self, delta_coordinate): diff --git a/grc/python/Block.py b/grc/python/Block.py index 191b03b452..5d52e2bf3c 100644 --- a/grc/python/Block.py +++ b/grc/python/Block.py @@ -52,7 +52,6 @@ class Block(_Block, _GUIBlock): self._var_make = n.find('var_make') self._checks = n.findall('check') self._callbacks = n.findall('callback') - self._throttle = n.find('throttle') or '' self._bus_structure_source = n.find('bus_structure_source') or '' self._bus_structure_sink = n.find('bus_structure_sink') or '' #build the block @@ -78,8 +77,6 @@ class Block(_Block, _GUIBlock): except: return '' - def throttle(self): return bool(self._throttle) - def validate(self): """ Validate this block. diff --git a/grc/python/Generator.py b/grc/python/Generator.py index a3f9f10fc1..d9e92cd31f 100644 --- a/grc/python/Generator.py +++ b/grc/python/Generator.py @@ -86,7 +86,7 @@ class TopBlockGenerator(object): def write(self): """generate output and write it to files""" # do throttle warning - throttling_blocks = filter(lambda b: b.throttle(), self._flow_graph.get_enabled_blocks()) + throttling_blocks = filter(lambda b: b.throtteling(), self._flow_graph.get_enabled_blocks()) if not throttling_blocks and self._generate_options != 'hb': Messages.send_warning("This flow graph may not have flow control: " "no audio or RF hardware blocks found. " diff --git a/grc/python/block.dtd b/grc/python/block.dtd index 8cfd3dd392..145f4d8610 100644 --- a/grc/python/block.dtd +++ b/grc/python/block.dtd @@ -25,7 +25,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA Top level element. A block contains a name, ...parameters list, and list of IO ports. --> -<!ELEMENT block (name, key, category?, throttle?, import*, var_make?, var_value?, make, callback*, param_tab_order?, param*, bus_sink?, bus_source?, check*, sink*, source*, bus_structure_sink?, bus_structure_source?, doc?, grc_source?)> +<!ELEMENT block (name, key, category?, throttle?, flags?, import*, var_make?, var_value?, + make, callback*, param_tab_order?, param*, bus_sink?, bus_source?, check*, + sink*, source*, bus_structure_sink?, bus_structure_source?, doc?, grc_source?)> <!-- Sub level elements. --> @@ -64,3 +66,4 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA <!ELEMENT callback (#PCDATA)> <!ELEMENT optional (#PCDATA)> <!ELEMENT throttle (#PCDATA)> +<!ELEMENT flags (#PCDATA)> diff --git a/grc/scripts/gnuradio-companion b/grc/scripts/gnuradio-companion index 7a407eaaf8..b8b960a91e 100755 --- a/grc/scripts/gnuradio-companion +++ b/grc/scripts/gnuradio-companion @@ -55,6 +55,14 @@ def show_gtk_error_dialog(title, message): d.run() +def check_gtk_init(): + try: + gtk.init_check() + except RuntimeError: + print 'GTK initialization failed - bailing' + exit(-1) + + def check_gnuradio_import(): try: from gnuradio import gr @@ -108,6 +116,7 @@ def main(): if __name__ == '__main__': + check_gtk_init() check_gnuradio_import() ensure_blocks_path() main() |