summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--host/config/Python.cmake25
-rw-r--r--host/docs/dboards.rst36
-rw-r--r--host/docs/usrp2.rst2
-rw-r--r--host/examples/CMakeLists.txt53
-rw-r--r--host/examples/ascii_art_dft.hpp320
-rw-r--r--host/examples/benchmark_rx_rate.cpp1
-rw-r--r--host/examples/rx_ascii_art_dft.cpp143
-rw-r--r--host/examples/rx_samples_to_file.cpp135
-rw-r--r--host/examples/rx_samples_to_udp.cpp135
-rw-r--r--host/examples/rx_timed_samples.cpp19
-rw-r--r--host/examples/tx_timed_samples.cpp19
-rw-r--r--host/include/uhd/types/CMakeLists.txt2
-rw-r--r--host/include/uhd/types/dict.hpp86
-rw-r--r--host/include/uhd/types/dict.ipp128
-rw-r--r--host/include/uhd/types/metadata.hpp76
-rw-r--r--host/include/uhd/types/tune_request.hpp95
-rw-r--r--host/include/uhd/usrp/mimo_usrp.hpp20
-rw-r--r--host/include/uhd/usrp/multi_usrp.hpp39
-rw-r--r--host/include/uhd/usrp/simple_usrp.hpp18
-rw-r--r--host/include/uhd/usrp/single_usrp.hpp31
-rw-r--r--host/include/uhd/usrp/subdev_spec.hpp11
-rw-r--r--host/include/uhd/usrp/tune_helper.hpp31
-rw-r--r--host/include/uhd/utils/warning.hpp36
-rw-r--r--host/lib/CMakeLists.txt19
-rw-r--r--host/lib/transport/udp_zero_copy_asio.cpp2
-rw-r--r--host/lib/types.cpp21
-rw-r--r--host/lib/usrp/dboard/db_basic_and_lf.cpp39
-rw-r--r--host/lib/usrp/dboard/db_dbsrx.cpp14
-rw-r--r--host/lib/usrp/dboard/db_rfx.cpp21
-rw-r--r--host/lib/usrp/dboard/db_tvrx.cpp10
-rw-r--r--host/lib/usrp/dboard/db_unknown.cpp23
-rw-r--r--host/lib/usrp/dboard/db_wbx.cpp21
-rw-r--r--host/lib/usrp/dboard/db_xcvr2450.cpp8
-rw-r--r--host/lib/usrp/dboard_manager.cpp4
-rw-r--r--host/lib/usrp/misc_utils.cpp6
-rw-r--r--host/lib/usrp/multi_usrp.cpp35
-rw-r--r--host/lib/usrp/single_usrp.cpp24
-rw-r--r--host/lib/usrp/tune_helper.cpp141
-rw-r--r--host/lib/usrp/usrp1/mboard_impl.cpp2
-rw-r--r--host/lib/usrp/usrp1/usrp1_impl.cpp8
-rw-r--r--host/lib/usrp/wrapper_utils.hpp4
-rw-r--r--host/lib/utils/thread_priority.cpp2
-rw-r--r--host/lib/utils/warning.cpp59
-rw-r--r--host/test/tune_helper_test.cpp79
-rw-r--r--host/test/warning_test.cpp4
-rw-r--r--images/Makefile1
46 files changed, 1612 insertions, 396 deletions
diff --git a/host/config/Python.cmake b/host/config/Python.cmake
index 55ef6acca..a5080fc40 100644
--- a/host/config/Python.cmake
+++ b/host/config/Python.cmake
@@ -24,26 +24,23 @@ IF(NOT PYTHONINTERP_FOUND)
MESSAGE(FATAL_ERROR "Error: Python interpretor required by the build system.")
ENDIF(NOT PYTHONINTERP_FOUND)
-MACRO(PYTHON_CHECK_MODULE module have)
- MESSAGE(STATUS "Checking for python module ${module}")
+MACRO(PYTHON_CHECK_MODULE desc mod cmd have)
+ MESSAGE(STATUS "Python checking for ${desc}")
EXECUTE_PROCESS(
- COMMAND ${PYTHON_EXECUTABLE} -c "import ${module}"
+ COMMAND ${PYTHON_EXECUTABLE} -c "
+#########################################
+try: import ${mod}
+except: exit(-1)
+try: assert ${cmd}
+except: exit(-1)
+#########################################"
RESULT_VARIABLE ${have}
)
IF(${have} EQUAL 0)
- MESSAGE(STATUS "Checking for python module ${module} - found")
+ MESSAGE(STATUS "Python checking for ${desc} - found")
SET(${have} TRUE)
ELSE(${have} EQUAL 0)
- MESSAGE(STATUS "Checking for python module ${module} - not found")
+ MESSAGE(STATUS "Python checking for ${desc} - not found")
SET(${have} FALSE)
ENDIF(${have} EQUAL 0)
ENDMACRO(PYTHON_CHECK_MODULE)
-
-########################################################################
-# Check Modules
-########################################################################
-PYTHON_CHECK_MODULE("Cheetah" HAVE_PYTHON_MODULE_CHEETAH)
-
-IF(NOT HAVE_PYTHON_MODULE_CHEETAH)
- MESSAGE(FATAL_ERROR "Error: Cheetah Templates required by the build system.")
-ENDIF(NOT HAVE_PYTHON_MODULE_CHEETAH)
diff --git a/host/docs/dboards.rst b/host/docs/dboards.rst
index 080117651..b39c587f6 100644
--- a/host/docs/dboards.rst
+++ b/host/docs/dboards.rst
@@ -26,6 +26,14 @@ The boards have no tunable elements or programmable gains.
Though the magic of aliasing, you can down-convert signals
greater than the Nyquist rate of the ADC.
+BasicRX Bandwidth (Hz):
+ For Real-Mode (A or B subdevice): 250M
+ For Complex (AB or BA subdevice): 500M
+
+LFRX Bandwidth (Hz):
+ For Real-Mode (A or B subdevice): 33M
+ For Complex (AB or BA subdevice): 66M
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^
Basic TX and and LFTX
^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -40,6 +48,14 @@ The boards have no tunable elements or programmable gains.
Though the magic of aliasing, you can up-convert signals
greater than the Nyquist rate of the DAC.
+BasicTX Bandwidth (Hz): 250M
+ For Real-Mode (A or B subdevice): 250M
+ For Complex (AB or BA subdevice): 500M
+
+LFTX Bandwidth (Hz): 33M
+ For Real-Mode (A or B subdevice): 33M
+ For Complex (AB or BA subdevice): 66M
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^
DBSRX
^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -53,7 +69,7 @@ Receive Gains:
**GC1**, Range: 0-56dB
**GC2**, Range: 0-24dB
-Low-Pass Filter Bandwidth (Hz): 4M-33M
+Bandwidth (Hz): 8M-66M
^^^^^^^^^^^^^^^^^^^^^^^^^^^
RFX Series
@@ -68,6 +84,10 @@ the receive antenna will always be set to RX2, regardless of the settings.
Receive Gains: **PGA0**, Range: 0-70dB (except RFX400 range is 0-45dB)
+Bandwidths (Hz):
+ * **RX**: 40M
+ * **TX**: 40M
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^
XCVR 2450
^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -93,9 +113,9 @@ Receive Gains:
* **LNA**, Range: 0-30.5dB
* **VGA**, Range: 0-62dB
-Low-Pass Filter Bandwidths (Hz):
- * **RX**: 7.5M, 9.5M, 14M, 18M; (each +-0, 5, or 10%)
- * **TX**: 12M, 18M, 24M
+Bandwidths (Hz):
+ * **RX**: 15M, 19M, 28M, 36M; (each +-0, 5, or 10%)
+ * **TX**: 24M, 36M, 48M
^^^^^^^^^^^^^^^^^^^^^^^^^^^
WBX Series
@@ -112,9 +132,9 @@ Transmit Gains: **PGA0**, Range: 0-25dB
Receive Gains: **PGA0**, Range: 0-31.5dB
-Low-Pass Filter Bandwidths (Hz):
- * **RX**: 20M (Fixed)
- * **TX**: 20M (Fixed)
+Bandwidths (Hz):
+ * **RX**: 40M
+ * **TX**: 40M
^^^^^^^^^^^^^^^^^^^^^^^^^^^
TVRX
@@ -125,7 +145,7 @@ Receive Gains:
* **RF**, Range: -13.3-50.3dB (frequency-dependent)
* **IF**, Range: -1.5-32.5dB
-Bandpass Filter Bandwidth: 6MHz
+Bandwidth: 6MHz
------------------------------------------------------------------------
Daughterboard Modifications
diff --git a/host/docs/usrp2.rst b/host/docs/usrp2.rst
index 0ddcaa4e5..ada98000d 100644
--- a/host/docs/usrp2.rst
+++ b/host/docs/usrp2.rst
@@ -179,7 +179,7 @@ The LEDs reveal the following about the state of the device:
* **LED B:** undocumented
* **LED C:** receiving
* **LED D:** firmware loaded
-* **LED E:** undocumented
+* **LED E:** reference lock
* **LED F:** FPGA loaded
diff --git a/host/examples/CMakeLists.txt b/host/examples/CMakeLists.txt
index d19838335..ce2ca9640 100644
--- a/host/examples/CMakeLists.txt
+++ b/host/examples/CMakeLists.txt
@@ -16,30 +16,35 @@
#
########################################################################
-ADD_EXECUTABLE(benchmark_rx_rate benchmark_rx_rate.cpp)
-TARGET_LINK_LIBRARIES(benchmark_rx_rate uhd)
-
-ADD_EXECUTABLE(rx_timed_samples rx_timed_samples.cpp)
-TARGET_LINK_LIBRARIES(rx_timed_samples uhd)
-
-ADD_EXECUTABLE(test_async_messages test_async_messages.cpp)
-TARGET_LINK_LIBRARIES(test_async_messages uhd)
-
-ADD_EXECUTABLE(test_pps_input test_pps_input.cpp)
-TARGET_LINK_LIBRARIES(test_pps_input uhd)
+# example applications
+########################################################################
+SET(example_sources
+ benchmark_rx_rate.cpp
+ rx_samples_to_file.cpp
+ rx_samples_to_udp.cpp
+ rx_timed_samples.cpp
+ test_async_messages.cpp
+ test_pps_input.cpp
+ tx_timed_samples.cpp
+ tx_waveforms.cpp
+)
-ADD_EXECUTABLE(tx_timed_samples tx_timed_samples.cpp)
-TARGET_LINK_LIBRARIES(tx_timed_samples uhd)
+#for each source: build an executable and install
+FOREACH(example_source ${example_sources})
+ GET_FILENAME_COMPONENT(example_name ${example_source} NAME_WE)
+ ADD_EXECUTABLE(${example_name} ${example_source})
+ TARGET_LINK_LIBRARIES(${example_name} uhd)
+ INSTALL(TARGETS ${example_name} RUNTIME DESTINATION ${PKG_DATA_DIR}/examples)
+ENDFOREACH(example_source)
-ADD_EXECUTABLE(tx_waveforms tx_waveforms.cpp)
-TARGET_LINK_LIBRARIES(tx_waveforms uhd)
+########################################################################
+# ASCII Art DFT - requires curses, so this part is optional
+########################################################################
+INCLUDE(FindCurses)
-INSTALL(TARGETS
- benchmark_rx_rate
- rx_timed_samples
- test_async_messages
- test_pps_input
- tx_timed_samples
- tx_waveforms
- RUNTIME DESTINATION ${PKG_DATA_DIR}/examples
-)
+IF(CURSES_FOUND)
+ INCLUDE_DIRECTORIES(${CURSES_INCLUDE_DIR})
+ ADD_EXECUTABLE(rx_ascii_art_dft rx_ascii_art_dft.cpp)
+ TARGET_LINK_LIBRARIES(rx_ascii_art_dft uhd ${CURSES_LIBRARIES})
+ INSTALL(TARGETS rx_ascii_art_dft RUNTIME DESTINATION ${PKG_DATA_DIR}/examples)
+ENDIF(CURSES_FOUND)
diff --git a/host/examples/ascii_art_dft.hpp b/host/examples/ascii_art_dft.hpp
new file mode 100644
index 000000000..92fb77596
--- /dev/null
+++ b/host/examples/ascii_art_dft.hpp
@@ -0,0 +1,320 @@
+//
+// ASCII Art DFT Plotter - Josh Blum
+//
+
+#ifndef ASCII_ART_DFT_HPP
+#define ASCII_ART_DFT_HPP
+
+#include <string>
+#include <cstddef>
+#include <vector>
+#include <complex>
+#include <stdexcept>
+
+namespace acsii_art_dft{
+
+ //! Type produced by the log power DFT function
+ typedef std::vector<float> log_pwr_dft_type;
+
+ /*!
+ * Get a logarithmic power DFT of the input samples.
+ * Samples are expected to be in the range [-1.0, 1.0].
+ * \param samps a pointer to an array of complex samples
+ * \param nsamps the number of samples in the array
+ * \return a real range of DFT bins in units of dB
+ */
+ template <typename T> log_pwr_dft_type log_pwr_dft(
+ const std::complex<T> *samps, size_t nsamps
+ );
+
+ /*!
+ * Convert a DFT to a printable ascii plot.
+ * \param dft the log power dft bins
+ * \param width the frame width in characters
+ * \param height the frame height in characters
+ * \param samp_rate the sample rate in Sps
+ * \param dc_freq the DC frequency in Hz
+ * \param dyn_rng the dynamic range in dB
+ * \param ref_lvl the reference level in dB
+ * \return the plot as an ascii string
+ */
+ std::string dft_to_plot(
+ const log_pwr_dft_type &dft,
+ size_t width,
+ size_t height,
+ double samp_rate,
+ double dc_freq,
+ float dyn_rng,
+ float ref_lvl
+ );
+
+} //namespace ascii_dft
+
+/***********************************************************************
+ * Implementation includes
+ **********************************************************************/
+#include <cmath>
+#include <sstream>
+#include <algorithm>
+
+/***********************************************************************
+ * Helper functions
+ **********************************************************************/
+namespace {/*anon*/
+
+ static const double pi = double(std::acos(-1.0));
+
+ //! Round a floating-point value to the nearest integer
+ template <typename T> int iround(T val){
+ return (val > 0)? int(val + 0.5) : int(val - 0.5);
+ }
+
+ //! Pick the closest number that is nice to display
+ template <typename T> T to_clean_num(const T num){
+ if (num == 0) return 0;
+ const T pow10 = std::pow(T(10), int(std::floor(std::log10(std::abs(num)))));
+ const T norm = std::abs(num)/pow10;
+ static const int cleans[] = {1, 2, 5, 10};
+ int clean = cleans[0];
+ for (size_t i = 1; i < sizeof(cleans)/sizeof(cleans[0]); i++){
+ if (std::abs(norm - cleans[i]) < std::abs(norm - clean))
+ clean = cleans[i];
+ }
+ return ((num < 0)? -1 : 1)*clean*pow10;
+ }
+
+ //! Compute an FFT with pre-computed factors using Cooley-Tukey
+ template <typename T> std::complex<T> ct_fft_f(
+ const std::complex<T> *samps, size_t nsamps,
+ const std::complex<T> *factors,
+ size_t start = 0, size_t step = 1
+ ){
+ if (nsamps == 1) return samps[start];
+ std::complex<T> E_k = ct_fft_f(samps, nsamps/2, factors+1, start, step*2);
+ std::complex<T> O_k = ct_fft_f(samps, nsamps/2, factors+1, start+step, step*2);
+ return E_k + factors[0]*O_k;
+ }
+
+ //! Compute an FFT for a particular bin k using Cooley-Tukey
+ template <typename T> std::complex<T> ct_fft_k(
+ const std::complex<T> *samps, size_t nsamps, size_t k
+ ){
+ //pre-compute the factors to use in Cooley-Tukey
+ std::vector<std::complex<T> > factors;
+ for (size_t N = nsamps; N != 0; N /= 2){
+ factors.push_back(std::exp(std::complex<T>(0, T(-2*pi*k/N))));
+ }
+ return ct_fft_f(samps, nsamps, &factors.front());
+ }
+
+ //! Helper class to build a DFT plot frame
+ class frame_type{
+ public:
+ frame_type(size_t width, size_t height):
+ _frame(width-1, std::vector<char>(height, ' '))
+ {
+ /* NOP */
+ }
+
+ //accessors to parts of the frame
+ char &get_plot(size_t b, size_t z){return _frame.at(b+albl_w).at(z+flbl_h);}
+ char &get_albl(size_t b, size_t z){return _frame.at(b) .at(z+flbl_h);}
+ char &get_ulbl(size_t b) {return _frame.at(b) .at(flbl_h-1);}
+ char &get_flbl(size_t b) {return _frame.at(b+albl_w).at(flbl_h-1);}
+
+ //dimension accessors
+ size_t get_plot_h(void) const{return _frame.front().size() - flbl_h;}
+ size_t get_plot_w(void) const{return _frame.size() - albl_w;}
+ size_t get_albl_w(void) const{return albl_w;}
+
+ std::string to_string(void){
+ std::stringstream frame_ss;
+ for (size_t z = 0; z < _frame.front().size(); z++){
+ for (size_t b = 0; b < _frame.size(); b++){
+ frame_ss << _frame[b][_frame[b].size()-z-1];
+ }
+ frame_ss << std::endl;
+ }
+ return frame_ss.str();
+ }
+
+ private:
+ static const size_t albl_w = 6, flbl_h = 1;
+ std::vector<std::vector<char> > _frame;
+ };
+
+} //namespace /*anon*/
+
+/***********************************************************************
+ * Implementation code
+ **********************************************************************/
+namespace acsii_art_dft{
+
+ //! skip constants for amplitude and frequency labels
+ static const size_t albl_skip = 5, flbl_skip = 20;
+
+ template <typename T> log_pwr_dft_type log_pwr_dft(
+ const std::complex<T> *samps, size_t nsamps
+ ){
+ if (nsamps & (nsamps - 1))
+ throw std::runtime_error("num samps is not a power of 2");
+
+ //compute the window
+ double win_pwr = 0;
+ std::vector<std::complex<T> > win_samps;
+ for(size_t n = 0; n < nsamps; n++){
+ //double w_n = 1;
+ //double w_n = 0.54 //hamming window
+ // -0.46*std::cos(2*pi*n/(nsamps-1))
+ //;
+ double w_n = 0.35875 //blackman-harris window
+ -0.48829*std::cos(2*pi*n/(nsamps-1))
+ +0.14128*std::cos(4*pi*n/(nsamps-1))
+ -0.01168*std::cos(6*pi*n/(nsamps-1))
+ ;
+ //double w_n = 1 // flat top window
+ // -1.930*std::cos(2*pi*n/(nsamps-1))
+ // +1.290*std::cos(4*pi*n/(nsamps-1))
+ // -0.388*std::cos(6*pi*n/(nsamps-1))
+ // +0.032*std::cos(8*pi*n/(nsamps-1))
+ //;
+ win_samps.push_back(T(w_n)*samps[n]);
+ win_pwr += w_n*w_n;
+ }
+
+ //compute the log-power dft
+ log_pwr_dft_type log_pwr_dft;
+ for(size_t k = 0; k < nsamps; k++){
+ std::complex<T> dft_k = ct_fft_k(&win_samps.front(), nsamps, k);
+ log_pwr_dft.push_back(float(
+ + 20*std::log10(std::abs(dft_k))
+ - 20*std::log10(T(nsamps))
+ - 10*std::log10(win_pwr/nsamps)
+ + 3
+ ));
+ }
+
+ return log_pwr_dft;
+ }
+
+ std::string dft_to_plot(
+ const log_pwr_dft_type &dft_,
+ size_t width,
+ size_t height,
+ double samp_rate,
+ double dc_freq,
+ float dyn_rng,
+ float ref_lvl
+ ){
+ frame_type frame(width, height); //fill this frame
+
+ //re-order the dft so dc in in the center
+ const size_t num_bins = dft_.size() - 1 + dft_.size()%2; //make it odd
+ log_pwr_dft_type dft(num_bins);
+ for (size_t n = 0; n < num_bins; n++){
+ dft[n] = dft_[(n + num_bins/2)%num_bins];
+ }
+
+ //fill the plot with dft bins
+ for (size_t b = 0; b < frame.get_plot_w(); b++){
+ //indexes from the dft to grab for the plot
+ const size_t n_start = std::max(iround(double(b-0.5)*(num_bins-1)/(frame.get_plot_w()-1)), 0);
+ const size_t n_stop = std::min(iround(double(b+0.5)*(num_bins-1)/(frame.get_plot_w()-1)), int(num_bins));
+
+ //calculate val as the max across points
+ float val = dft.at(n_start);
+ for (size_t n = n_start; n < n_stop; n++) val = std::max(val, dft.at(n));
+
+ const float scaled = (val - (ref_lvl - dyn_rng))*(frame.get_plot_h()-1)/dyn_rng;
+ for (size_t z = 0; z < frame.get_plot_h(); z++){
+ static const std::string syms(".:!|");
+ if (scaled-z > 1) frame.get_plot(b, z) = syms.at(syms.size()-1);
+ else if (scaled-z > 0) frame.get_plot(b, z) = syms.at(size_t((scaled-z)*syms.size()));
+ }
+ }
+
+ //create vertical amplitude labels
+ const float db_step = to_clean_num(dyn_rng/(frame.get_plot_h()-1)*albl_skip);
+ for (
+ float db = db_step*(int((ref_lvl - dyn_rng)/db_step));
+ db <= db_step*(int(ref_lvl/db_step));
+ db += db_step
+ ){
+ const int z = iround((db - (ref_lvl - dyn_rng))*(frame.get_plot_h()-1)/dyn_rng);
+ if (z < 0 or size_t(z) >= frame.get_plot_h()) continue;
+ std::stringstream ss; ss << db; std::string lbl = ss.str();
+ for (size_t i = 0; i < lbl.size() and i < frame.get_albl_w(); i++){
+ frame.get_albl(i, z) = lbl[i];
+ }
+ }
+
+ //create vertical units label
+ std::string ulbl = "dBfs";
+ for (size_t i = 0; i < ulbl.size(); i++){
+ frame.get_ulbl(i+1) = ulbl[i];
+ }
+
+ //create horizontal frequency labels
+ const double f_step = to_clean_num(samp_rate/frame.get_plot_w()*flbl_skip);
+ for (
+ double freq = f_step*int((-samp_rate/2/f_step));
+ freq <= f_step*int((+samp_rate/2/f_step));
+ freq += f_step
+ ){
+ const int b = iround((freq + samp_rate/2)*(frame.get_plot_w()-1)/samp_rate);
+ std::stringstream ss; ss << (freq+dc_freq)/1e6 << "MHz"; std::string lbl = ss.str();
+ if (b < int(lbl.size()/2) or b + lbl.size() - lbl.size()/2 >= frame.get_plot_w()) continue;
+ for (size_t i = 0; i < lbl.size(); i++){
+ frame.get_flbl(b + i - lbl.size()/2) = lbl[i];
+ }
+ }
+
+ return frame.to_string();
+ }
+} //namespace ascii_dft
+
+#endif /*ASCII_ART_DFT_HPP*/
+
+/*
+
+//example main function to test the dft
+
+#include <iostream>
+#include <cstdlib>
+#include <curses.h>
+
+int main(void){
+ initscr();
+
+ while (true){
+ clear();
+
+ std::vector<std::complex<float> > samples;
+ for(size_t i = 0; i < 512; i++){
+ samples.push_back(std::complex<float>(
+ float(std::rand() - RAND_MAX/2)/(RAND_MAX)/4,
+ float(std::rand() - RAND_MAX/2)/(RAND_MAX)/4
+ ));
+ samples[i] += 0.5*std::sin(i*3.14/2) + 0.7;
+ }
+
+ acsii_art_dft::log_pwr_dft_type dft;
+ dft = acsii_art_dft::log_pwr_dft(&samples.front(), samples.size());
+
+ printw("%s", acsii_art_dft::dft_to_plot(
+ dft, COLS, LINES,
+ 12.5e4, 2.45e9,
+ 60, 0
+ ).c_str());
+
+ sleep(1);
+ }
+
+
+ endwin();
+ std::cout << "here\n";
+ return 0;
+}
+
+*/
+
diff --git a/host/examples/benchmark_rx_rate.cpp b/host/examples/benchmark_rx_rate.cpp
index 36611f97f..b189368f9 100644
--- a/host/examples/benchmark_rx_rate.cpp
+++ b/host/examples/benchmark_rx_rate.cpp
@@ -137,7 +137,6 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl;
uhd::usrp::single_usrp::sptr sdev = uhd::usrp::single_usrp::make(args);
std::cout << boost::format("Using Device: %s") % sdev->get_pp_string() << std::endl;
- sdev->issue_stream_cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS); //stop if left running
if (not vm.count("rate")){
sdev->set_rx_rate(500e3); //initial rate
diff --git a/host/examples/rx_ascii_art_dft.cpp b/host/examples/rx_ascii_art_dft.cpp
new file mode 100644
index 000000000..5a24867b4
--- /dev/null
+++ b/host/examples/rx_ascii_art_dft.cpp
@@ -0,0 +1,143 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program 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, see <http://www.gnu.org/licenses/>.
+//
+
+#include <uhd/utils/thread_priority.hpp>
+#include <uhd/utils/safe_main.hpp>
+#include <uhd/usrp/single_usrp.hpp>
+#include "ascii_art_dft.hpp" //implementation
+#include <boost/program_options.hpp>
+#include <boost/thread.hpp> //gets time
+#include <boost/format.hpp>
+#include <curses.h>
+#include <iostream>
+#include <complex>
+
+namespace po = boost::program_options;
+
+int UHD_SAFE_MAIN(int argc, char *argv[]){
+ uhd::set_thread_priority_safe();
+
+ //variables to be set by po
+ std::string args;
+ size_t num_bins;
+ double rate, freq, frame_rate;
+ float gain, ref_lvl, dyn_rng;
+
+ //setup the program options
+ po::options_description desc("Allowed options");
+ desc.add_options()
+ ("help", "help message")
+ ("args", po::value<std::string>(&args)->default_value(""), "single uhd device address args")
+ // hardware parameters
+ ("rate", po::value<double>(&rate), "rate of incoming samples (sps)")
+ ("freq", po::value<double>(&freq)->default_value(0), "RF center frequency in Hz")
+ ("gain", po::value<float>(&gain)->default_value(0), "gain for the RF chain")
+ // display parameters
+ ("num-bins", po::value<size_t>(&num_bins)->default_value(512), "the number of bins in the DFT")
+ ("frame-rate", po::value<double>(&frame_rate)->default_value(5), "frame rate of the display (fps)")
+ ("ref-lvl", po::value<float>(&ref_lvl)->default_value(0), "reference level for the display (dB)")
+ ("dyn-rng", po::value<float>(&dyn_rng)->default_value(60), "dynamic range for the display (dB)")
+ ;
+ po::variables_map vm;
+ po::store(po::parse_command_line(argc, argv, desc), vm);
+ po::notify(vm);
+
+ //print the help message
+ if (vm.count("help") or not vm.count("rate")){
+ std::cout << boost::format("UHD RX ASCII Art DFT %s") % desc << std::endl;
+ return ~0;
+ }
+
+ //create a usrp device
+ std::cout << std::endl;
+ std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl;
+ uhd::usrp::single_usrp::sptr sdev = uhd::usrp::single_usrp::make(args);
+ std::cout << boost::format("Using Device: %s") % sdev->get_pp_string() << std::endl;
+
+ //set the rx sample rate
+ std::cout << boost::format("Setting RX Rate: %f Msps...") % (rate/1e6) << std::endl;
+ sdev->set_rx_rate(rate);
+ std::cout << boost::format("Actual RX Rate: %f Msps...") % (sdev->get_rx_rate()/1e6) << std::endl << std::endl;
+
+ //set the rx center frequency
+ std::cout << boost::format("Setting RX Freq: %f Mhz...") % (freq/1e6) << std::endl;
+ sdev->set_rx_freq(freq);
+ std::cout << boost::format("Actual RX Freq: %f Mhz...") % (sdev->get_rx_freq()/1e6) << std::endl << std::endl;
+
+ //set the rx rf gain
+ std::cout << boost::format("Setting RX Gain: %f dB...") % gain << std::endl;
+ sdev->set_rx_gain(gain);
+ std::cout << boost::format("Actual RX Gain: %f dB...") % sdev->get_rx_gain() << std::endl << std::endl;
+
+ //allocate recv buffer and metatdata
+ uhd::rx_metadata_t md;
+ std::vector<std::complex<float> > buff(num_bins);
+ //------------------------------------------------------------------
+ //-- Initialize
+ //------------------------------------------------------------------
+ initscr(); //curses init
+ sdev->issue_stream_cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
+ boost::system_time next_refresh = boost::get_system_time();
+
+ //------------------------------------------------------------------
+ //-- Main loop
+ //------------------------------------------------------------------
+ while (true){
+ //read a buffer's worth of samples every iteration
+ size_t num_rx_samps = sdev->get_device()->recv(
+ &buff.front(), buff.size(), md,
+ uhd::io_type_t::COMPLEX_FLOAT32,
+ uhd::device::RECV_MODE_FULL_BUFF
+ );
+ if (num_rx_samps != buff.size()) continue;
+
+ //check and update the display refresh condition
+ if (boost::get_system_time() < next_refresh) continue;
+ next_refresh = boost::get_system_time() + boost::posix_time::microseconds(long(1e6/frame_rate));
+
+ //calculate the dft and create the ascii art frame
+ acsii_art_dft::log_pwr_dft_type lpdft(
+ acsii_art_dft::log_pwr_dft(&buff.front(), num_rx_samps)
+ );
+ std::string frame = acsii_art_dft::dft_to_plot(
+ lpdft, COLS, LINES,
+ sdev->get_rx_rate(),
+ sdev->get_rx_freq(),
+ dyn_rng, ref_lvl
+ );
+
+ //curses screen handling: clear and print frame
+ clear();
+ printw("%s", frame.c_str());
+
+ //curses key handling: no timeout, any key to exit
+ timeout(0);
+ int ch = getch();
+ if (ch != KEY_RESIZE and ch != ERR) break;
+ }
+
+ //------------------------------------------------------------------
+ //-- Cleanup
+ //------------------------------------------------------------------
+ sdev->issue_stream_cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS);
+ endwin(); //curses done
+
+ //finished
+ std::cout << std::endl << "Done!" << std::endl << std::endl;
+
+ return 0;
+}
diff --git a/host/examples/rx_samples_to_file.cpp b/host/examples/rx_samples_to_file.cpp
new file mode 100644
index 000000000..c80d2a6de
--- /dev/null
+++ b/host/examples/rx_samples_to_file.cpp
@@ -0,0 +1,135 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program 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, see <http://www.gnu.org/licenses/>.
+//
+
+#include <uhd/utils/thread_priority.hpp>
+#include <uhd/utils/safe_main.hpp>
+#include <uhd/usrp/single_usrp.hpp>
+#include <boost/program_options.hpp>
+#include <boost/format.hpp>
+#include <boost/thread.hpp>
+#include <iostream>
+#include <fstream>
+#include <complex>
+
+namespace po = boost::program_options;
+
+int UHD_SAFE_MAIN(int argc, char *argv[]){
+ uhd::set_thread_priority_safe();
+
+ //variables to be set by po
+ std::string args, file;
+ size_t total_num_samps;
+ double rate, freq;
+ float gain;
+
+ //setup the program options
+ po::options_description desc("Allowed options");
+ desc.add_options()
+ ("help", "help message")
+ ("args", po::value<std::string>(&args)->default_value(""), "single uhd device address args")
+ ("file", po::value<std::string>(&file)->default_value("out.16sc.dat"), "name of the file to write binary samples to")
+ ("nsamps", po::value<size_t>(&total_num_samps)->default_value(1000), "total number of samples to receive")
+ ("rate", po::value<double>(&rate)->default_value(100e6/16), "rate of incoming samples")
+ ("freq", po::value<double>(&freq)->default_value(0), "rf center frequency in Hz")
+ ("gain", po::value<float>(&gain)->default_value(0), "gain for the RF chain")
+ ;
+ po::variables_map vm;
+ po::store(po::parse_command_line(argc, argv, desc), vm);
+ po::notify(vm);
+
+ //print the help message
+ if (vm.count("help")){
+ std::cout << boost::format("UHD RX to File %s") % desc << std::endl;
+ return ~0;
+ }
+
+ //create a usrp device
+ std::cout << std::endl;
+ std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl;
+ uhd::usrp::single_usrp::sptr sdev = uhd::usrp::single_usrp::make(args);
+ uhd::device::sptr dev = sdev->get_device();
+ std::cout << boost::format("Using Device: %s") % sdev->get_pp_string() << std::endl;
+
+ //set the rx sample rate
+ std::cout << boost::format("Setting RX Rate: %f Msps...") % (rate/1e6) << std::endl;
+ sdev->set_rx_rate(rate);
+ std::cout << boost::format("Actual RX Rate: %f Msps...") % (sdev->get_rx_rate()/1e6) << std::endl << std::endl;
+
+ //set the rx center frequency
+ std::cout << boost::format("Setting RX Freq: %f Mhz...") % (freq/1e6) << std::endl;
+ sdev->set_rx_freq(freq);
+ std::cout << boost::format("Actual RX Freq: %f Mhz...") % (sdev->get_rx_freq()/1e6) << std::endl << std::endl;
+
+ //set the rx rf gain
+ std::cout << boost::format("Setting RX Gain: %f dB...") % gain << std::endl;
+ sdev->set_rx_gain(gain);
+ std::cout << boost::format("Actual RX Gain: %f dB...") % sdev->get_rx_gain() << std::endl << std::endl;
+
+ boost::this_thread::sleep(boost::posix_time::seconds(1)); //allow for some setup time
+ std::cout << "LO Locked = " << sdev->get_rx_lo_locked() << std::endl;
+
+ //setup streaming
+ uhd::stream_cmd_t stream_cmd(uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE);
+ stream_cmd.num_samps = total_num_samps;
+ stream_cmd.stream_now = true;
+ sdev->issue_stream_cmd(stream_cmd);
+
+ //loop until total number of samples reached
+ size_t num_acc_samps = 0; //number of accumulated samples
+ uhd::rx_metadata_t md;
+ std::vector<std::complex<short> > buff(dev->get_max_recv_samps_per_packet());
+ std::ofstream outfile(file.c_str(), std::ofstream::binary);
+
+ while(num_acc_samps < total_num_samps){
+ size_t num_rx_samps = dev->recv(
+ &buff.front(), buff.size(), md,
+ uhd::io_type_t::COMPLEX_INT16,
+ uhd::device::RECV_MODE_ONE_PACKET
+ );
+
+ //handle the error codes
+ switch(md.error_code){
+ case uhd::rx_metadata_t::ERROR_CODE_NONE:
+ break;
+
+ case uhd::rx_metadata_t::ERROR_CODE_TIMEOUT:
+ if (num_acc_samps == 0) continue;
+ std::cout << boost::format(
+ "Got timeout before all samples received, possible packet loss, exiting loop..."
+ ) << std::endl;
+ goto done_loop;
+
+ default:
+ std::cout << boost::format(
+ "Got error code 0x%x, exiting loop..."
+ ) % md.error_code << std::endl;
+ goto done_loop;
+ }
+
+ //write complex short integer samples to the binary file
+ outfile.write((const char*)&buff[0], num_rx_samps * sizeof(std::complex<short>));
+
+ num_acc_samps += num_rx_samps;
+ } done_loop:
+
+ outfile.close();
+
+ //finished
+ std::cout << std::endl << "Done!" << std::endl << std::endl;
+
+ return 0;
+}
diff --git a/host/examples/rx_samples_to_udp.cpp b/host/examples/rx_samples_to_udp.cpp
new file mode 100644
index 000000000..488c95494
--- /dev/null
+++ b/host/examples/rx_samples_to_udp.cpp
@@ -0,0 +1,135 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program 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, see <http://www.gnu.org/licenses/>.
+//
+
+#include <uhd/utils/thread_priority.hpp>
+#include <uhd/utils/safe_main.hpp>
+#include <uhd/usrp/single_usrp.hpp>
+#include <uhd/transport/udp_simple.hpp>
+#include <boost/program_options.hpp>
+#include <boost/format.hpp>
+#include <boost/thread.hpp>
+#include <iostream>
+#include <complex>
+
+namespace po = boost::program_options;
+
+int UHD_SAFE_MAIN(int argc, char *argv[]){
+ uhd::set_thread_priority_safe();
+
+ //variables to be set by po
+ std::string args;
+ size_t total_num_samps;
+ double rate, freq;
+ float gain;
+ std::string addr, port;
+
+ //setup the program options
+ po::options_description desc("Allowed options");
+ desc.add_options()
+ ("help", "help message")
+ ("args", po::value<std::string>(&args)->default_value(""), "single uhd device address args")
+ ("nsamps", po::value<size_t>(&total_num_samps)->default_value(1000), "total number of samples to receive")
+ ("rate", po::value<double>(&rate)->default_value(100e6/16), "rate of incoming samples")
+ ("freq", po::value<double>(&freq)->default_value(0), "rf center frequency in Hz")
+ ("gain", po::value<float>(&gain)->default_value(0), "gain for the RF chain")
+ ("port", po::value<std::string>(&port)->default_value("7124"), "server udp port")
+ ("addr", po::value<std::string>(&addr)->default_value("192.168.1.10"), "resolvable server address")
+ ;
+ po::variables_map vm;
+ po::store(po::parse_command_line(argc, argv, desc), vm);
+ po::notify(vm);
+
+ //print the help message
+ if (vm.count("help")){
+ std::cout << boost::format("UHD RX to UDP %s") % desc << std::endl;
+ return ~0;
+ }
+
+ //create a usrp device
+ std::cout << std::endl;
+ std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl;
+ uhd::usrp::single_usrp::sptr sdev = uhd::usrp::single_usrp::make(args);
+ uhd::device::sptr dev = sdev->get_device();
+ std::cout << boost::format("Using Device: %s") % sdev->get_pp_string() << std::endl;
+
+ //set the rx sample rate
+ std::cout << boost::format("Setting RX Rate: %f Msps...") % (rate/1e6) << std::endl;
+ sdev->set_rx_rate(rate);
+ std::cout << boost::format("Actual RX Rate: %f Msps...") % (sdev->get_rx_rate()/1e6) << std::endl << std::endl;
+
+ //set the rx center frequency
+ std::cout << boost::format("Setting RX Freq: %f Mhz...") % (freq/1e6) << std::endl;
+ sdev->set_rx_freq(freq);
+ std::cout << boost::format("Actual RX Freq: %f Mhz...") % (sdev->get_rx_freq()/1e6) << std::endl << std::endl;
+
+ //set the rx rf gain
+ std::cout << boost::format("Setting RX Gain: %f dB...") % gain << std::endl;
+ sdev->set_rx_gain(gain);
+ std::cout << boost::format("Actual RX Gain: %f dB...") % sdev->get_rx_gain() << std::endl << std::endl;
+
+ boost::this_thread::sleep(boost::posix_time::seconds(1)); //allow for some setup time
+ std::cout << "LO Locked = " << sdev->get_rx_lo_locked() << std::endl;
+
+ //setup streaming
+ uhd::stream_cmd_t stream_cmd(uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE);
+ stream_cmd.num_samps = total_num_samps;
+ stream_cmd.stream_now = true;
+ sdev->issue_stream_cmd(stream_cmd);
+
+ //loop until total number of samples reached
+ size_t num_acc_samps = 0; //number of accumulated samples
+ uhd::rx_metadata_t md;
+ std::vector<std::complex<float> > buff(dev->get_max_recv_samps_per_packet());
+ uhd::transport::udp_simple::sptr udp_xport = uhd::transport::udp_simple::make_connected(addr, port);
+
+ while(num_acc_samps < total_num_samps){
+ size_t num_rx_samps = dev->recv(
+ &buff.front(), buff.size(), md,
+ uhd::io_type_t::COMPLEX_FLOAT32,
+ uhd::device::RECV_MODE_ONE_PACKET
+ );
+
+ //handle the error codes
+ switch(md.error_code){
+ case uhd::rx_metadata_t::ERROR_CODE_NONE:
+ break;
+
+ case uhd::rx_metadata_t::ERROR_CODE_TIMEOUT:
+ if (num_acc_samps == 0) continue;
+ std::cout << boost::format(
+ "Got timeout before all samples received, possible packet loss, exiting loop..."
+ ) << std::endl;
+ goto done_loop;
+
+ default:
+ std::cout << boost::format(
+ "Got error code 0x%x, exiting loop..."
+ ) % md.error_code << std::endl;
+ goto done_loop;
+ }
+
+ //send complex single precision floating point samples over udp
+ udp_xport->send(boost::asio::buffer(buff, num_rx_samps));
+
+ num_acc_samps += num_rx_samps;
+ } done_loop:
+
+ //finished
+ std::cout << std::endl << "Done!" << std::endl << std::endl;
+
+ return 0;
+}
diff --git a/host/examples/rx_timed_samples.cpp b/host/examples/rx_timed_samples.cpp
index 441665900..8a810811f 100644
--- a/host/examples/rx_timed_samples.cpp
+++ b/host/examples/rx_timed_samples.cpp
@@ -32,7 +32,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
std::string args;
time_t seconds_in_future;
size_t total_num_samps;
- double rx_rate, freq;
+ double rate, freq;
//setup the program options
po::options_description desc("Allowed options");
@@ -41,7 +41,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
("args", po::value<std::string>(&args)->default_value(""), "single uhd device address args")
("secs", po::value<time_t>(&seconds_in_future)->default_value(3), "number of seconds in the future to receive")
("nsamps", po::value<size_t>(&total_num_samps)->default_value(1000), "total number of samples to receive")
- ("rxrate", po::value<double>(&rx_rate)->default_value(100e6/16), "rate of incoming samples")
+ ("rate", po::value<double>(&rate)->default_value(100e6/16), "rate of incoming samples")
("freq", po::value<double>(&freq)->default_value(0), "rf center frequency in Hz")
("dilv", "specify to disable inner-loop verbose")
;
@@ -64,12 +64,17 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
uhd::device::sptr dev = sdev->get_device();
std::cout << boost::format("Using Device: %s") % sdev->get_pp_string() << std::endl;
- //set properties on the device
- std::cout << boost::format("Setting RX Rate: %f Msps...") % (rx_rate/1e6) << std::endl;
- sdev->set_rx_rate(rx_rate);
- std::cout << boost::format("Actual RX Rate: %f Msps...") % (sdev->get_rx_rate()/1e6) << std::endl;
- std::cout << boost::format("Setting device timestamp to 0...") << std::endl;
+ //set the rx sample rate
+ std::cout << boost::format("Setting RX Rate: %f Msps...") % (rate/1e6) << std::endl;
+ sdev->set_rx_rate(rate);
+ std::cout << boost::format("Actual RX Rate: %f Msps...") % (sdev->get_rx_rate()/1e6) << std::endl << std::endl;
+
+ //set the rx center frequency
+ std::cout << boost::format("Setting RX Freq: %f Mhz...") % (freq/1e6) << std::endl;
sdev->set_rx_freq(freq);
+ std::cout << boost::format("Actual RX Freq: %f Mhz...") % (sdev->get_rx_freq()/1e6) << std::endl << std::endl;
+
+ std::cout << boost::format("Setting device timestamp to 0...") << std::endl;
sdev->set_time_now(uhd::time_spec_t(0.0));
//setup streaming
diff --git a/host/examples/tx_timed_samples.cpp b/host/examples/tx_timed_samples.cpp
index 863446682..799da37e0 100644
--- a/host/examples/tx_timed_samples.cpp
+++ b/host/examples/tx_timed_samples.cpp
@@ -33,7 +33,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
time_t seconds_in_future;
size_t total_num_samps;
size_t samps_per_packet;
- double tx_rate, freq;
+ double rate, freq;
float ampl;
//setup the program options
@@ -44,7 +44,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
("secs", po::value<time_t>(&seconds_in_future)->default_value(3), "number of seconds in the future to transmit")
("nsamps", po::value<size_t>(&total_num_samps)->default_value(1000), "total number of samples to transmit")
("spp", po::value<size_t>(&samps_per_packet)->default_value(1000), "number of samples per packet")
- ("txrate", po::value<double>(&tx_rate)->default_value(100e6/16), "rate of outgoing samples")
+ ("rate", po::value<double>(&rate)->default_value(100e6/16), "rate of outgoing samples")
("freq", po::value<double>(&freq)->default_value(0), "rf center frequency in Hz")
("ampl", po::value<float>(&ampl)->default_value(float(0.3)), "amplitude of each sample")
("dilv", "specify to disable inner-loop verbose")
@@ -68,12 +68,17 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
uhd::device::sptr dev = sdev->get_device();
std::cout << boost::format("Using Device: %s") % sdev->get_pp_string() << std::endl;
- //set properties on the device
- std::cout << boost::format("Setting TX Rate: %f Msps...") % (tx_rate/1e6) << std::endl;
- sdev->set_tx_rate(tx_rate);
- std::cout << boost::format("Actual TX Rate: %f Msps...") % (sdev->get_tx_rate()/1e6) << std::endl;
- std::cout << boost::format("Setting device timestamp to 0...") << std::endl;
+ //set the tx sample rate
+ std::cout << boost::format("Setting TX Rate: %f Msps...") % (rate/1e6) << std::endl;
+ sdev->set_tx_rate(rate);
+ std::cout << boost::format("Actual TX Rate: %f Msps...") % (sdev->get_tx_rate()/1e6) << std::endl << std::endl;
+
+ //set the tx center frequency
+ std::cout << boost::format("Setting TX Freq: %f Mhz...") % (freq/1e6) << std::endl;
sdev->set_tx_freq(freq);
+ std::cout << boost::format("Actual TX Freq: %f Mhz...") % (sdev->get_tx_freq()/1e6) << std::endl << std::endl;
+
+ std::cout << boost::format("Setting device timestamp to 0...") << std::endl;
sdev->set_time_now(uhd::time_spec_t(0.0));
//allocate data to send
diff --git a/host/include/uhd/types/CMakeLists.txt b/host/include/uhd/types/CMakeLists.txt
index dbce21c98..a96976b5e 100644
--- a/host/include/uhd/types/CMakeLists.txt
+++ b/host/include/uhd/types/CMakeLists.txt
@@ -19,6 +19,7 @@
INSTALL(FILES
clock_config.hpp
device_addr.hpp
+ dict.ipp
dict.hpp
io_type.hpp
mac_addr.hpp
@@ -28,6 +29,7 @@ INSTALL(FILES
serial.hpp
stream_cmd.hpp
time_spec.hpp
+ tune_request.hpp
tune_result.hpp
DESTINATION ${INCLUDE_DIR}/uhd/types
)
diff --git a/host/include/uhd/types/dict.hpp b/host/include/uhd/types/dict.hpp
index de96ea768..6166140a0 100644
--- a/host/include/uhd/types/dict.hpp
+++ b/host/include/uhd/types/dict.hpp
@@ -19,11 +19,6 @@
#define INCLUDED_UHD_TYPES_DICT_HPP
#include <uhd/config.hpp>
-#include <boost/foreach.hpp>
-#include <boost/format.hpp>
-#include <boost/lexical_cast.hpp>
-#include <stdexcept>
-#include <typeinfo>
#include <vector>
#include <list>
@@ -34,14 +29,10 @@ namespace uhd{
*/
template <typename Key, typename Val> class dict{
public:
- typedef std::pair<Key, Val> pair_t;
-
/*!
* Create a new empty dictionary.
*/
- dict(void){
- /* NOP */
- }
+ dict(void);
/*!
* Input iterator constructor:
@@ -50,64 +41,42 @@ namespace uhd{
* \param last the end iterator
*/
template <typename InputIterator>
- dict(InputIterator first, InputIterator last){
- for(InputIterator it = first; it != last; it++){
- _map.push_back(*it);
- }
- }
-
- /*!
- * Destroy this dict.
- */
- ~dict(void){
- /* NOP */
- }
+ dict(InputIterator first, InputIterator last);
/*!
* Get the number of elements in this dict.
* \return the number of elements
*/
- std::size_t size(void) const{
- return _map.size();
- }
+ std::size_t size(void) const;
/*!
* Get a list of the keys in this dict.
* Key order depends on insertion precedence.
* \return vector of keys
*/
- const std::vector<Key> keys(void) const{
- std::vector<Key> keys;
- BOOST_FOREACH(const pair_t &p, _map){
- keys.push_back(p.first);
- }
- return keys;
- }
+ const std::vector<Key> keys(void) const;
/*!
* Get a list of the values in this dict.
* Value order depends on insertion precedence.
* \return vector of values
*/
- const std::vector<Val> vals(void) const{
- std::vector<Val> vals;
- BOOST_FOREACH(const pair_t &p, _map){
- vals.push_back(p.second);
- }
- return vals;
- }
+ const std::vector<Val> vals(void) const;
/*!
* Does the dictionary contain this key?
* \param key the key to look for
* \return true if found
*/
- bool has_key(const Key &key) const{
- BOOST_FOREACH(const pair_t &p, _map){
- if (p.first == key) return true;
- }
- return false;
- }
+ bool has_key(const Key &key) const;
+
+ /*!
+ * Get a value in the dict or default.
+ * \param key the key to look for
+ * \param def use if key not found
+ * \return the value or default
+ */
+ const Val &get(const Key &key, const Val &def) const;
/*!
* Get a value for the given key if it exists.
@@ -116,15 +85,7 @@ namespace uhd{
* \return the value at the key
* \throw an exception when not found
*/
- const Val &operator[](const Key &key) const{
- BOOST_FOREACH(const pair_t &p, _map){
- if (p.first == key) return p.second;
- }
- throw std::invalid_argument(str(boost::format(
- "key \"%s\" not found in dict(%s, %s)"
- ) % boost::lexical_cast<std::string>(key)
- % typeid(Key).name() % typeid(Val).name()));
- }
+ const Val &operator[](const Key &key) const;
/*!
* Set a value for the given key, however, in reality
@@ -132,13 +93,7 @@ namespace uhd{
* \param key the key to set to
* \return a reference to the value
*/
- Val &operator[](const Key &key){
- BOOST_FOREACH(pair_t &p, _map){
- if (p.first == key) return p.second;
- }
- _map.push_back(std::make_pair(key, Val()));
- return _map.back().second;
- }
+ Val &operator[](const Key &key);
/*!
* Pop an item out of the dictionary.
@@ -146,16 +101,15 @@ namespace uhd{
* \return the value of the item
* \throw an exception when not found
*/
- Val pop(const Key &key){
- Val val = (*this)[key];
- _map.remove(pair_t(key, val));
- return val;
- }
+ Val pop(const Key &key);
private:
+ typedef std::pair<Key, Val> pair_t;
std::list<pair_t> _map; //private container
};
} //namespace uhd
+#include <uhd/types/dict.ipp>
+
#endif /* INCLUDED_UHD_TYPES_DICT_HPP */
diff --git a/host/include/uhd/types/dict.ipp b/host/include/uhd/types/dict.ipp
new file mode 100644
index 000000000..ba05d5272
--- /dev/null
+++ b/host/include/uhd/types/dict.ipp
@@ -0,0 +1,128 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program 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, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_UHD_TYPES_DICT_IPP
+#define INCLUDED_UHD_TYPES_DICT_IPP
+
+#include <boost/foreach.hpp>
+#include <boost/format.hpp>
+#include <boost/lexical_cast.hpp>
+#include <stdexcept>
+#include <typeinfo>
+
+namespace uhd{
+
+ namespace /*anon*/{
+ template<typename Key, typename Val>
+ struct key_not_found: std::out_of_range{
+ key_not_found(const Key &key): std::out_of_range(
+ str(boost::format(
+ "key \"%s\" not found in dict(%s, %s)"
+ ) % boost::lexical_cast<std::string>(key)
+ % typeid(Key).name() % typeid(Val).name()
+ )
+ ){
+ /* NOP */
+ }
+ };
+ } // namespace /*anon*/
+
+ template <typename Key, typename Val>
+ dict<Key, Val>::dict(void){
+ /* NOP */
+ }
+
+ template <typename Key, typename Val>
+ template <typename InputIterator>
+ dict<Key, Val>::dict(InputIterator first, InputIterator last){
+ for(InputIterator it = first; it != last; it++){
+ _map.push_back(*it);
+ }
+ }
+
+ template <typename Key, typename Val>
+ std::size_t dict<Key, Val>::size(void) const{
+ return _map.size();
+ }
+
+ template <typename Key, typename Val>
+ const std::vector<Key> dict<Key, Val>::keys(void) const{
+ std::vector<Key> keys;
+ BOOST_FOREACH(const pair_t &p, _map){
+ keys.push_back(p.first);
+ }
+ return keys;
+ }
+
+ template <typename Key, typename Val>
+ const std::vector<Val> dict<Key, Val>::vals(void) const{
+ std::vector<Val> vals;
+ BOOST_FOREACH(const pair_t &p, _map){
+ vals.push_back(p.second);
+ }
+ return vals;
+ }
+
+ template <typename Key, typename Val>
+ bool dict<Key, Val>::has_key(const Key &key) const{
+ BOOST_FOREACH(const pair_t &p, _map){
+ if (p.first == key) return true;
+ }
+ return false;
+ }
+
+ template <typename Key, typename Val>
+ const Val &dict<Key, Val>::get(const Key &key, const Val &def) const{
+ BOOST_FOREACH(const pair_t &p, _map){
+ if (p.first == key) return p.second;
+ }
+ return def;
+ }
+
+ template <typename Key, typename Val>
+ const Val &dict<Key, Val>::operator[](const Key &key) const{
+ BOOST_FOREACH(const pair_t &p, _map){
+ if (p.first == key) return p.second;
+ }
+ throw key_not_found<Key, Val>(key);
+ }
+
+ template <typename Key, typename Val>
+ Val &dict<Key, Val>::operator[](const Key &key){
+ BOOST_FOREACH(pair_t &p, _map){
+ if (p.first == key) return p.second;
+ }
+ _map.push_back(std::make_pair(key, Val()));
+ return _map.back().second;
+ }
+
+ template <typename Key, typename Val>
+ Val dict<Key, Val>::pop(const Key &key){
+ typename std::list<pair_t>::iterator it;
+ for (it = _map.begin(); it != _map.end(); it++){
+ if (it->first == key){
+ Val val = it->second;
+ _map.erase(it);
+ return val;
+ }
+ }
+ throw key_not_found<Key, Val>(key);
+ }
+
+} //namespace uhd
+
+#endif /* INCLUDED_UHD_TYPES_DICT_IPP */
diff --git a/host/include/uhd/types/metadata.hpp b/host/include/uhd/types/metadata.hpp
index 65952941c..3f250d13e 100644
--- a/host/include/uhd/types/metadata.hpp
+++ b/host/include/uhd/types/metadata.hpp
@@ -19,7 +19,6 @@
#define INCLUDED_UHD_TYPES_METADATA_HPP
#include <uhd/config.hpp>
-#include <boost/cstdint.hpp>
#include <uhd/types/time_spec.hpp>
namespace uhd{
@@ -30,58 +29,59 @@ namespace uhd{
* The receive routines will convert IF data headers into metadata.
*/
struct UHD_API rx_metadata_t{
- /*!
- * Time specification:
- * Set from timestamps on incoming data when provided.
- */
+ //! Has time specification?
bool has_time_spec;
+
+ //! Time of the first sample.
time_spec_t time_spec;
/*!
- * Fragmentation flag and offset:
+ * Fragmentation flag:
* Similar to IPv4 fragmentation: http://en.wikipedia.org/wiki/IPv4#Fragmentation_and_reassembly
* More fragments is true when the input buffer has insufficient size to fit
* an entire received packet. More fragments will be false for the last fragment.
- * The fragment offset is the sample number at the start of the receive buffer.
- * For non-fragmented receives, the fragment offset should always be zero.
*/
bool more_fragments;
- size_t fragment_offset;
/*!
- * Burst flags:
- * Start of burst will be true for the first packet in the chain.
- * End of burst will be true for the last packet in the chain.
+ * Fragmentation offset:
+ * The fragment offset is the sample number at the start of the receive buffer.
+ * For non-fragmented receives, the fragment offset should always be zero.
*/
+ size_t fragment_offset;
+
+ //! Start of burst will be true for the first packet in the chain.
bool start_of_burst;
+
+ //! End of burst will be true for the last packet in the chain.
bool end_of_burst;
/*!
- * Error conditions:
- * - none: no error associated with this metadata
- * - timeout: no packet received, underlying code timed-out
- * - late command: a stream command was issued in the past
- * - broken chain: expected another stream command
- * - overflow: an internal receive buffer has filled
- * - bad packet: the buffer was unrecognizable as a vrt packet
+ * The error condition on a receive call.
*
* Note: When an overrun occurs in continuous streaming mode,
* the device will continue to send samples to the host.
* For other streaming modes, streaming will discontinue
* until the user issues a new stream command.
*
- * Note: The metadata fields have meaning for the following error codes:
+ * The metadata fields have meaning for the following error codes:
* - none
* - late command
* - broken chain
* - overflow
*/
enum error_code_t {
+ //! No error associated with this metadata.
ERROR_CODE_NONE = 0x0,
+ //! No packet received, implementation timed-out.
ERROR_CODE_TIMEOUT = 0x1,
+ //! A stream command was issued in the past.
ERROR_CODE_LATE_COMMAND = 0x2,
+ //! Expected another stream command.
ERROR_CODE_BROKEN_CHAIN = 0x4,
+ //! An internal receive buffer has filled.
ERROR_CODE_OVERFLOW = 0x8,
+ //! The packet could not be parsed.
ERROR_CODE_BAD_PACKET = 0xf
} error_code;
};
@@ -93,19 +93,19 @@ namespace uhd{
*/
struct UHD_API tx_metadata_t{
/*!
- * Time specification:
- * Set has time spec to false to perform a send "now".
- * Or, set to true, and fill in time spec for a send "at".
+ * Has time specification?
+ * - Set false to send immediately.
+ * - Set true to send at the time specified by time spec.
*/
bool has_time_spec;
+
+ //! When to send the first sample.
time_spec_t time_spec;
- /*!
- * Burst flags:
- * Set start of burst to true for the first packet in the chain.
- * Set end of burst to true for the last packet in the chain.
- */
+ //! Set start of burst to true for the first packet in the chain.
bool start_of_burst;
+
+ //! Set end of burst to true for the last packet in the chain.
bool end_of_burst;
/*!
@@ -122,27 +122,27 @@ namespace uhd{
//! The channel number in a mimo configuration
size_t channel;
- /*!
- * Time specification: when the async event occurred.
- */
+ //! Has time specification?
bool has_time_spec;
+
+ //! When the async event occurred.
time_spec_t time_spec;
/*!
- * Event codes:
- * - success: a packet was successfully transmitted
- * - underflow: an internal send buffer has emptied
- * - sequence error: packet loss between host and device
- * - time error: packet had time that was late (or too early)
- * - underflow in packet: underflow occurred inside a packet
- * - sequence error in burst: packet loss within a burst
+ * The type of event for a receive async message call.
*/
enum event_code_t {
+ //! A packet was successfully transmitted.
EVENT_CODE_SUCCESS = 0x1,
+ //! An internal send buffer has emptied.
EVENT_CODE_UNDERFLOW = 0x2,
+ //! Packet loss between host and device.
EVENT_CODE_SEQ_ERROR = 0x4,
+ //! Packet had time that was late (or too early).
EVENT_CODE_TIME_ERROR = 0x8,
+ //! Underflow occurred inside a packet.
EVENT_CODE_UNDERFLOW_IN_PACKET = 0x10,
+ //! Packet loss within a burst.
EVENT_CODE_SEQ_ERROR_IN_BURST = 0x20
} event_code;
};
diff --git a/host/include/uhd/types/tune_request.hpp b/host/include/uhd/types/tune_request.hpp
new file mode 100644
index 000000000..942b93251
--- /dev/null
+++ b/host/include/uhd/types/tune_request.hpp
@@ -0,0 +1,95 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program 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, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_UHD_TYPES_TUNE_REQUEST_HPP
+#define INCLUDED_UHD_TYPES_TUNE_REQUEST_HPP
+
+#include <uhd/config.hpp>
+
+namespace uhd{
+
+ /*!
+ * A tune request instructs the implementation how to tune the RF chain.
+ * The policies can be used to select automatic tuning or
+ * fined control over the daughterboard IF and DSP tuning.
+ * Not all combinations of policies are applicable.
+ * Convenience constructors are supplied for most use cases.
+ */
+ struct UHD_API tune_request_t{
+ /*!
+ * Make a new tune request for a particular center frequency.
+ * Use an automatic policy for the intermediate and DSP frequency
+ * to tune the chain as close as possible to the target frequency.
+ * \param target_freq the target frequency in Hz
+ */
+ tune_request_t(double target_freq = 0);
+
+ /*!
+ * Make a new tune request for a particular center frequency.
+ * Use a manual policy for the intermediate frequency,
+ * and an automatic policy for the DSP frequency,
+ * to tune the chain as close as possible to the target frequency.
+ * \param target_freq the target frequency in Hz
+ * \param lo_off the LO offset frequency in Hz
+ */
+ tune_request_t(double target_freq, double lo_off);
+
+ //! Policy options for tunable elements in the RF chain.
+ enum policy_t {
+ //! Do not set this argument, use current setting.
+ POLICY_NONE = 'N',
+ //! Automatically determine the argument's value.
+ POLICY_AUTO = 'A',
+ //! Use the argument's value for the setting.
+ POLICY_MANUAL = 'M'
+ };
+
+ /*!
+ * The target frequency of the overall chain in Hz.
+ * Set this even if all policies are set to manual.
+ */
+ double target_freq;
+
+ /*!
+ * The policy for the intermediate frequency.
+ * Automatic behavior: the target frequency + default LO offset.
+ */
+ policy_t inter_freq_policy;
+
+ /*!
+ * The intermediate frequency in Hz.
+ * Set when the policy is set to manual.
+ */
+ double inter_freq;
+
+ /*!
+ * The policy for the DSP frequency.
+ * Automatic behavior: the difference between the target and IF.
+ */
+ policy_t dsp_freq_policy;
+
+ /*!
+ * The DSP frequency in Hz.
+ * Set when the policy is set to manual.
+ */
+ double dsp_freq;
+
+ };
+
+} //namespace uhd
+
+#endif /* INCLUDED_UHD_TYPES_TUNE_REQUEST_HPP */
diff --git a/host/include/uhd/usrp/mimo_usrp.hpp b/host/include/uhd/usrp/mimo_usrp.hpp
index 78833e24e..a2092f04f 100644
--- a/host/include/uhd/usrp/mimo_usrp.hpp
+++ b/host/include/uhd/usrp/mimo_usrp.hpp
@@ -127,7 +127,7 @@ public:
virtual double get_rx_rate_all(void) = 0;
virtual tune_result_t set_rx_freq(size_t chan, double freq) = 0;
- virtual tune_result_t set_rx_freq(size_t chan, double freq, double lo_off) = 0;
+ //virtual tune_result_t set_rx_freq(size_t chan, double freq, double lo_off) = 0;
virtual double get_rx_freq(size_t chan) = 0;
virtual freq_range_t get_rx_freq_range(size_t chan) = 0;
@@ -161,7 +161,7 @@ public:
virtual double get_tx_rate_all(void) = 0;
virtual tune_result_t set_tx_freq(size_t chan, double freq) = 0;
- virtual tune_result_t set_tx_freq(size_t chan, double freq, double lo_off) = 0;
+ //virtual tune_result_t set_tx_freq(size_t chan, double freq, double lo_off) = 0;
virtual double get_tx_freq(size_t chan) = 0;
virtual freq_range_t get_tx_freq_range(size_t chan) = 0;
@@ -298,7 +298,7 @@ public:
time_spec_t time_0 = _mboard(0)[MBOARD_PROP_TIME_NOW].as<time_spec_t>();
time_spec_t time_i = _mboard(chan)[MBOARD_PROP_TIME_NOW].as<time_spec_t>();
if (time_i < time_0 or (time_i - time_0) > time_spec_t(0.01)){ //10 ms: greater than RTT but not too big
- uhd::print_warning(str(boost::format(
+ uhd::warning::post(str(boost::format(
"Detected time deviation between board %d and board 0.\n"
"Board 0 time is %f seconds.\n"
"Board %d time is %f seconds.\n"
@@ -345,9 +345,9 @@ public:
return tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan), 0, target_freq);
}
- tune_result_t set_rx_freq(size_t chan, double target_freq, double lo_off){
- return tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan), 0, target_freq, lo_off);
- }
+ //tune_result_t set_rx_freq(size_t chan, double target_freq, double lo_off){
+ // return tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan), 0, target_freq, lo_off);
+ //}
double get_rx_freq(size_t chan){
return derive_freq_from_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan), 0);
@@ -425,9 +425,9 @@ public:
return tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan), 0, target_freq);
}
- tune_result_t set_tx_freq(size_t chan, double target_freq, double lo_off){
- return tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan), 0, target_freq, lo_off);
- }
+ //tune_result_t set_tx_freq(size_t chan, double target_freq, double lo_off){
+ // return tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan), 0, target_freq, lo_off);
+ //}
double get_tx_freq(size_t chan){
return derive_freq_from_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan), 0);
@@ -512,7 +512,7 @@ namespace uhd{ namespace usrp{
* The Make Function
**********************************************************************/
inline mimo_usrp::sptr mimo_usrp::make(const device_addr_t &dev_addr){
- uhd::print_warning(
+ uhd::warning::post(
"The mimo USRP interface has been deprecated.\n"
"Please switch to the multi USRP interface.\n"
"#include <uhd/usrp/multi_usrp.hpp>\n"
diff --git a/host/include/uhd/usrp/multi_usrp.hpp b/host/include/uhd/usrp/multi_usrp.hpp
index 2f71f80b1..98ba07fc0 100644
--- a/host/include/uhd/usrp/multi_usrp.hpp
+++ b/host/include/uhd/usrp/multi_usrp.hpp
@@ -23,6 +23,7 @@
#include <uhd/types/ranges.hpp>
#include <uhd/types/stream_cmd.hpp>
#include <uhd/types/clock_config.hpp>
+#include <uhd/types/tune_request.hpp>
#include <uhd/types/tune_result.hpp>
#include <uhd/usrp/subdev_spec.hpp>
#include <uhd/usrp/dboard_iface.hpp>
@@ -144,6 +145,14 @@ public:
virtual void set_time_unknown_pps(const time_spec_t &time_spec) = 0;
/*!
+ * Are the times across all motherboards in this configuration synchronized?
+ * Checks that all time registers are approximately close but not exact,
+ * given that the RTT may varying for a control packet transaction.
+ * \return true when all motherboards time registers are in sync
+ */
+ virtual bool get_time_synchronized(void) = 0;
+
+ /*!
* Issue a stream command to the usrp device.
* This tells the usrp to send samples into the host.
* See the documentation for stream_cmd_t for more info.
@@ -213,20 +222,13 @@ public:
/*!
* Set the RX center frequency.
- * \param freq the frequency in Hz
+ * \param tune_request tune request instructions
* \param chan the channel index 0 to N-1
* \return a tune result object
*/
- virtual tune_result_t set_rx_freq(double freq, size_t chan) = 0;
-
- /*!
- * Set the RX center frequency.
- * \param freq the frequency in Hz
- * \param lo_off an LO offset in Hz
- * \param chan the channel index 0 to N-1
- * \return a tune result object
- */
- virtual tune_result_t set_rx_freq(double freq, double lo_off, size_t chan) = 0;
+ virtual tune_result_t set_rx_freq(
+ const tune_request_t &tune_request, size_t chan = 0
+ ) = 0;
/*!
* Get the RX center frequency.
@@ -399,20 +401,13 @@ public:
/*!
* Set the TX center frequency.
- * \param freq the frequency in Hz
- * \param chan the channel index 0 to N-1
- * \return a tune result object
- */
- virtual tune_result_t set_tx_freq(double freq, size_t chan) = 0;
-
- /*!
- * Set the TX center frequency.
- * \param freq the frequency in Hz
- * \param lo_off an LO offset in Hz
+ * \param tune_request tune request instructions
* \param chan the channel index 0 to N-1
* \return a tune result object
*/
- virtual tune_result_t set_tx_freq(double freq, double lo_off, size_t chan) = 0;
+ virtual tune_result_t set_tx_freq(
+ const tune_request_t &tune_request, size_t chan = 0
+ ) = 0;
/*!
* Get the TX center frequency.
diff --git a/host/include/uhd/usrp/simple_usrp.hpp b/host/include/uhd/usrp/simple_usrp.hpp
index 22f4d64ba..77416dbbd 100644
--- a/host/include/uhd/usrp/simple_usrp.hpp
+++ b/host/include/uhd/usrp/simple_usrp.hpp
@@ -117,7 +117,7 @@ public:
virtual double get_rx_rate(void) = 0;
virtual tune_result_t set_rx_freq(double freq) = 0;
- virtual tune_result_t set_rx_freq(double freq, double lo_off) = 0;
+ //virtual tune_result_t set_rx_freq(double freq, double lo_off) = 0;
virtual double get_rx_freq(void) = 0;
virtual freq_range_t get_rx_freq_range(void) = 0;
@@ -152,7 +152,7 @@ public:
virtual double get_tx_rate(void) = 0;
virtual tune_result_t set_tx_freq(double freq) = 0;
- virtual tune_result_t set_tx_freq(double freq, double lo_off) = 0;
+ //virtual tune_result_t set_tx_freq(double freq, double lo_off) = 0;
virtual double get_tx_freq(void) = 0;
virtual freq_range_t get_tx_freq_range(void) = 0;
@@ -243,9 +243,9 @@ public:
return _sdev->set_rx_freq(target_freq);
}
- tune_result_t set_rx_freq(double target_freq, double lo_off){
- return _sdev->set_rx_freq(target_freq, lo_off);
- }
+ //tune_result_t set_rx_freq(double target_freq, double lo_off){
+ // return _sdev->set_rx_freq(target_freq, lo_off);
+ //}
double get_rx_freq(void){
return _sdev->get_rx_freq();
@@ -318,9 +318,9 @@ public:
return _sdev->set_tx_freq(target_freq);
}
- tune_result_t set_tx_freq(double target_freq, double lo_off){
- return _sdev->set_tx_freq(target_freq, lo_off);
- }
+ //tune_result_t set_tx_freq(double target_freq, double lo_off){
+ // return _sdev->set_tx_freq(target_freq, lo_off);
+ //}
double get_tx_freq(void){
return _sdev->get_tx_freq();
@@ -374,7 +374,7 @@ namespace uhd{ namespace usrp{
* The Make Function
**********************************************************************/
inline simple_usrp::sptr simple_usrp::make(const device_addr_t &dev_addr){
- uhd::print_warning(
+ uhd::warning::post(
"The simple USRP interface has been deprecated.\n"
"Please switch to the single USRP interface.\n"
"#include <uhd/usrp/single_usrp.hpp>\n"
diff --git a/host/include/uhd/usrp/single_usrp.hpp b/host/include/uhd/usrp/single_usrp.hpp
index a068fbed8..26303fe10 100644
--- a/host/include/uhd/usrp/single_usrp.hpp
+++ b/host/include/uhd/usrp/single_usrp.hpp
@@ -23,6 +23,7 @@
#include <uhd/types/ranges.hpp>
#include <uhd/types/stream_cmd.hpp>
#include <uhd/types/clock_config.hpp>
+#include <uhd/types/tune_request.hpp>
#include <uhd/types/tune_result.hpp>
#include <uhd/usrp/subdev_spec.hpp>
#include <uhd/usrp/dboard_iface.hpp>
@@ -154,20 +155,13 @@ public:
/*!
* Set the RX center frequency.
- * \param freq the frequency in Hz
+ * \param tune_request tune request instructions
* \param chan the channel index 0 to N-1
* \return a tune result object
*/
- virtual tune_result_t set_rx_freq(double freq, size_t chan = 0) = 0;
-
- /*!
- * Set the RX center frequency.
- * \param freq the frequency in Hz
- * \param lo_off an LO offset in Hz
- * \param chan the channel index 0 to N-1
- * \return a tune result object
- */
- virtual tune_result_t set_rx_freq(double freq, double lo_off, size_t chan = 0) = 0;
+ virtual tune_result_t set_rx_freq(
+ const tune_request_t &tune_request, size_t chan = 0
+ ) = 0;
/*!
* Get the RX center frequency.
@@ -330,20 +324,13 @@ public:
/*!
* Set the TX center frequency.
- * \param freq the frequency in Hz
- * \param chan the channel index 0 to N-1
- * \return a tune result object
- */
- virtual tune_result_t set_tx_freq(double freq, size_t chan = 0) = 0;
-
- /*!
- * Set the TX center frequency.
- * \param freq the frequency in Hz
- * \param lo_off an LO offset in Hz
+ * \param tune_request tune request instructions
* \param chan the channel index 0 to N-1
* \return a tune result object
*/
- virtual tune_result_t set_tx_freq(double freq, double lo_off, size_t chan = 0) = 0;
+ virtual tune_result_t set_tx_freq(
+ const tune_request_t &tune_request, size_t chan = 0
+ ) = 0;
/*!
* Get the TX center frequency.
diff --git a/host/include/uhd/usrp/subdev_spec.hpp b/host/include/uhd/usrp/subdev_spec.hpp
index 5de3bb3b8..b189724c9 100644
--- a/host/include/uhd/usrp/subdev_spec.hpp
+++ b/host/include/uhd/usrp/subdev_spec.hpp
@@ -26,10 +26,10 @@
namespace uhd{ namespace usrp{
/*!
- * A subdevice specification (daughterboard, subdevice) name pairing.
+ * A subdevice specification (daughterboard slot, subdevice) name pairing.
*/
struct UHD_API subdev_spec_pair_t : boost::equality_comparable<subdev_spec_pair_t>{
- //! The daughterboard name
+ //! The daughterboard slot name
std::string db_name;
//! The subdevice name
@@ -50,7 +50,7 @@ namespace uhd{ namespace usrp{
UHD_API bool operator==(const subdev_spec_pair_t &, const subdev_spec_pair_t &);
/*!
- * A list of (daughterboard name, subdevice name) pairs:
+ * A list of (daughterboard slot name, subdevice name) pairs:
*
* A subdevice specification represents a list of subdevices on a motherboard.
* The subdevices specified may span across multiple daughterboards;
@@ -62,6 +62,11 @@ namespace uhd{ namespace usrp{
* The markup-string is a whitespace separated list of dboard:subdev pairs.
* The first pair represents the subdevice for channel zero,
* the second pair represents the subdevice for channel one, and so on.
+ *
+ * Special handling for empty conditions:
+ * - An empty subdevice specification means: select the first subdevice found in the configuration
+ * - An empty daughterboard name means: select the only daughterboard slot or error if multiple exist
+ * - An empty subdevice name means: select the only subdevice on that board or error if multiple exist
*/
class UHD_API subdev_spec_t : public std::vector<subdev_spec_pair_t>{
public:
diff --git a/host/include/uhd/usrp/tune_helper.hpp b/host/include/uhd/usrp/tune_helper.hpp
index ec133fa08..db12241c1 100644
--- a/host/include/uhd/usrp/tune_helper.hpp
+++ b/host/include/uhd/usrp/tune_helper.hpp
@@ -20,6 +20,7 @@
#include <uhd/config.hpp>
#include <uhd/wax.hpp>
+#include <uhd/types/tune_request.hpp>
#include <uhd/types/tune_result.hpp>
namespace uhd{ namespace usrp{
@@ -32,23 +33,12 @@ namespace uhd{ namespace usrp{
* \param subdev the dboard subdevice object with properties
* \param ddc the mboard dsp object with properties
* \param chan the channel of the dsp to tune
- * \param target_freq the desired center frequency
- * \param lo_offset an offset for the subdevice IF from center
+ * \param tune_request tune request instructions
* \return a tune result struct
*/
UHD_API tune_result_t tune_rx_subdev_and_dsp(
wax::obj subdev, wax::obj ddc, size_t chan,
- double target_freq, double lo_offset
- );
-
- /*!
- * Tune a rx chain to the desired frequency:
- * Same as the above, except the LO offset
- * is calculated based on the subdevice and BW.
- */
- UHD_API tune_result_t tune_rx_subdev_and_dsp(
- wax::obj subdev, wax::obj ddc,
- size_t chan, double target_freq
+ const tune_request_t &tune_request
);
/*!
@@ -70,23 +60,12 @@ namespace uhd{ namespace usrp{
* \param subdev the dboard subdevice object with properties
* \param duc the mboard dsp object with properties
* \param chan the channel of the dsp to tune
- * \param target_freq the desired center frequency
- * \param lo_offset an offset for the subdevice IF from center
+ * \param tune_request tune request instructions
* \return a tune result struct
*/
UHD_API tune_result_t tune_tx_subdev_and_dsp(
wax::obj subdev, wax::obj duc, size_t chan,
- double target_freq, double lo_offset
- );
-
- /*!
- * Tune a tx chain to the desired frequency:
- * Same as the above, except the LO offset
- * is calculated based on the subdevice and BW.
- */
- UHD_API tune_result_t tune_tx_subdev_and_dsp(
- wax::obj subdev, wax::obj duc,
- size_t chan, double target_freq
+ const tune_request_t &tune_request
);
/*!
diff --git a/host/include/uhd/utils/warning.hpp b/host/include/uhd/utils/warning.hpp
index 91d8400ab..a1e3f0d1e 100644
--- a/host/include/uhd/utils/warning.hpp
+++ b/host/include/uhd/utils/warning.hpp
@@ -19,16 +19,44 @@
#define INCLUDED_UHD_UTILS_WARNING_HPP
#include <uhd/config.hpp>
+#include <boost/function.hpp>
+#include <vector>
#include <string>
-namespace uhd{
+namespace uhd{ namespace warning{
+
+ //! Callback function type for a message handler
+ typedef boost::function<void(std::string)> handler_t;
/*!
- * Print a formatted warning string to stderr.
+ * Post a warning message to all registered handlers.
* \param msg the multiline warning message
*/
- UHD_API void print_warning(const std::string &msg);
+ UHD_API void post(const std::string &msg);
+
+ /*!
+ * Register a new handler with this name.
+ * If the name was already registered for this name,
+ * the old registered handler will be replaced.
+ * \param name a unique name for this handler
+ * \param handler the callback handler function
+ */
+ UHD_API void register_handler(const std::string &name, const handler_t &handler);
+
+ /*!
+ * Unregister a handler for this name.
+ * \param name a unique name for a registered handler
+ * \return the handler that was registered
+ * \throw error when the name was not found in the registry
+ */
+ UHD_API handler_t unregister_handler(const std::string &name);
+
+ /*!
+ * Get a list of registered handler names.
+ * \return a vector of unique string names
+ */
+ UHD_API const std::vector<std::string> registry_names(void);
-} //namespace uhd
+}} //namespace uhd::warning
#endif /* INCLUDED_UHD_UTILS_WARNING_HPP */
diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt
index 81845de21..e4de7bcc7 100644
--- a/host/lib/CMakeLists.txt
+++ b/host/lib/CMakeLists.txt
@@ -16,6 +16,25 @@
#
########################################################################
+# Check Python Modules
+########################################################################
+PYTHON_CHECK_MODULE(
+ "Python version 2.6 or greater"
+ "platform" "platform.python_version() >= '2.6'"
+ HAVE_PYTHON_PLAT_MIN_VERSION
+)
+
+PYTHON_CHECK_MODULE(
+ "Cheetah templates 2.0.0 or greater"
+ "Cheetah" "Cheetah.Version >= '2.0.0'"
+ HAVE_PYTHON_MODULE_CHEETAH
+)
+
+IF(NOT HAVE_PYTHON_PLAT_MIN_VERSION OR NOT HAVE_PYTHON_MODULE_CHEETAH)
+ MESSAGE(FATAL_ERROR "Error: python requirements not met for the build system.")
+ENDIF(NOT HAVE_PYTHON_PLAT_MIN_VERSION OR NOT HAVE_PYTHON_MODULE_CHEETAH)
+
+########################################################################
# Helpful Macros
########################################################################
MACRO(LIBUHD_APPEND_SOURCES)
diff --git a/host/lib/transport/udp_zero_copy_asio.cpp b/host/lib/transport/udp_zero_copy_asio.cpp
index d84aeefdd..ed29864e9 100644
--- a/host/lib/transport/udp_zero_copy_asio.cpp
+++ b/host/lib/transport/udp_zero_copy_asio.cpp
@@ -336,7 +336,7 @@ template<typename Opt> static void resize_buff_helper(
else std::cout << boost::format(
"Current %s sock buff size: %d bytes"
) % name % actual_size << std::endl;
- if (actual_size < target_size) uhd::print_warning(str(boost::format(
+ if (actual_size < target_size) uhd::warning::post(str(boost::format(
"The %s buffer is smaller than the requested size.\n"
"The minimum recommended buffer size is %d bytes.\n"
"See the transport application notes on buffer resizing.\n%s"
diff --git a/host/lib/types.cpp b/host/lib/types.cpp
index 6aa82b012..4188568aa 100644
--- a/host/lib/types.cpp
+++ b/host/lib/types.cpp
@@ -17,6 +17,7 @@
#include <uhd/utils/assert.hpp>
#include <uhd/types/ranges.hpp>
+#include <uhd/types/tune_request.hpp>
#include <uhd/types/tune_result.hpp>
#include <uhd/types/clock_config.hpp>
#include <uhd/types/stream_cmd.hpp>
@@ -58,6 +59,26 @@ freq_range_t::freq_range_t(double min, double max):
}
/***********************************************************************
+ * tune request
+ **********************************************************************/
+tune_request_t::tune_request_t(double target_freq):
+ target_freq(target_freq),
+ inter_freq_policy(POLICY_AUTO),
+ dsp_freq_policy(POLICY_AUTO)
+{
+ /* NOP */
+}
+
+tune_request_t::tune_request_t(double target_freq, double lo_off):
+ target_freq(target_freq),
+ inter_freq_policy(POLICY_MANUAL),
+ inter_freq(target_freq + lo_off),
+ dsp_freq_policy(POLICY_AUTO)
+{
+ /* NOP */
+}
+
+/***********************************************************************
* tune result
**********************************************************************/
std::string tune_result_t::to_pp_string(void) const{
diff --git a/host/lib/usrp/dboard/db_basic_and_lf.cpp b/host/lib/usrp/dboard/db_basic_and_lf.cpp
index 41f6f8002..f03dd43d1 100644
--- a/host/lib/usrp/dboard/db_basic_and_lf.cpp
+++ b/host/lib/usrp/dboard/db_basic_and_lf.cpp
@@ -20,6 +20,7 @@
#include <uhd/types/ranges.hpp>
#include <uhd/utils/assert.hpp>
#include <uhd/utils/static.hpp>
+#include <uhd/utils/warning.hpp>
#include <uhd/usrp/dboard_base.hpp>
#include <uhd/usrp/dboard_manager.hpp>
#include <boost/assign/list_of.hpp>
@@ -30,6 +31,16 @@ using namespace uhd::usrp;
using namespace boost::assign;
/***********************************************************************
+ * Constants
+ **********************************************************************/
+static const uhd::dict<std::string, double> subdev_bandwidth_scalar = map_list_of
+ ("A", 1.0)
+ ("B", 1.0)
+ ("AB", 2.0)
+ ("BA", 2.0)
+;
+
+/***********************************************************************
* The basic and lf boards:
* They share a common class because only the frequency bounds differ.
**********************************************************************/
@@ -68,11 +79,11 @@ static const uhd::dict<std::string, subdev_conn_t> sd_name_to_conn = map_list_of
* Register the basic and LF dboards
**********************************************************************/
static dboard_base::sptr make_basic_rx(dboard_base::ctor_args_t args){
- return dboard_base::sptr(new basic_rx(args, 90e9));
+ return dboard_base::sptr(new basic_rx(args, 250e6));
}
static dboard_base::sptr make_basic_tx(dboard_base::ctor_args_t args){
- return dboard_base::sptr(new basic_tx(args, 90e9));
+ return dboard_base::sptr(new basic_tx(args, 250e6));
}
static dboard_base::sptr make_lf_rx(dboard_base::ctor_args_t args){
@@ -161,6 +172,10 @@ void basic_rx::rx_get(const wax::obj &key_, wax::obj &val){
val = true; //there is no LO, so it must be true!
return;
+ case SUBDEV_PROP_BANDWIDTH:
+ val = subdev_bandwidth_scalar[get_subdev_name()]*_max_freq;
+ return;
+
default: UHD_THROW_PROP_GET_ERROR();
}
}
@@ -185,6 +200,14 @@ void basic_rx::rx_set(const wax::obj &key_, const wax::obj &val){
case SUBDEV_PROP_ENABLED:
return; //always enabled
+ case SUBDEV_PROP_BANDWIDTH:
+ uhd::warning::post(
+ str(boost::format("%s: No tunable bandwidth, fixed filtered to %0.2fMHz")
+ % get_rx_id().to_pp_string() % _max_freq
+ )
+ );
+ return;
+
default: UHD_THROW_PROP_SET_ERROR();
}
}
@@ -260,6 +283,10 @@ void basic_tx::tx_get(const wax::obj &key_, wax::obj &val){
val = true; //there is no LO, so it must be true!
return;
+ case SUBDEV_PROP_BANDWIDTH:
+ val = subdev_bandwidth_scalar[get_subdev_name()]*_max_freq;
+ return;
+
default: UHD_THROW_PROP_GET_ERROR();
}
}
@@ -284,6 +311,14 @@ void basic_tx::tx_set(const wax::obj &key_, const wax::obj &val){
case SUBDEV_PROP_ENABLED:
return; //always enabled
+ case SUBDEV_PROP_BANDWIDTH:
+ uhd::warning::post(
+ str(boost::format("%s: No tunable bandwidth, fixed filtered to %0.2fMHz")
+ % get_tx_id().to_pp_string() % _max_freq
+ )
+ );
+ return;
+
default: UHD_THROW_PROP_SET_ERROR();
}
}
diff --git a/host/lib/usrp/dboard/db_dbsrx.cpp b/host/lib/usrp/dboard/db_dbsrx.cpp
index 0b8b4db83..85251bdf9 100644
--- a/host/lib/usrp/dboard/db_dbsrx.cpp
+++ b/host/lib/usrp/dboard/db_dbsrx.cpp
@@ -175,7 +175,7 @@ UHD_STATIC_BLOCK(reg_dbsrx_dboard){
dbsrx::dbsrx(ctor_args_t args) : rx_dboard_base(args){
//warn user about incorrect DBID on USRP1, requires R193 populated
if (this->get_iface()->get_special_props().soft_clock_divider and this->get_rx_id() == 0x000D)
- uhd::print_warning(
+ uhd::warning::post(
str(boost::format(
"DBSRX: incorrect dbid\n"
"Expected dbid 0x0002 and R193\n"
@@ -186,7 +186,7 @@ dbsrx::dbsrx(ctor_args_t args) : rx_dboard_base(args){
//warn user about incorrect DBID on non-USRP1, requires R194 populated
if (not this->get_iface()->get_special_props().soft_clock_divider and this->get_rx_id() == 0x0002)
- uhd::print_warning(
+ uhd::warning::post(
str(boost::format(
"DBSRX: incorrect dbid\n"
"Expected dbid 0x000D and R194\n"
@@ -236,8 +236,10 @@ void dbsrx::set_lo_freq(double target_freq){
bool update_filter_settings = false;
//choose refclock
std::vector<double> clock_rates = this->get_iface()->get_clock_rates(dboard_iface::UNIT_RX);
+ const double max_clock_rate = std::sorted(clock_rates).back();
BOOST_FOREACH(ref_clock, std::reversed(std::sorted(clock_rates))){
if (ref_clock > 27.0e6) continue;
+ if (size_t(max_clock_rate/ref_clock)%2 == 1) continue; //reject asymmetric clocks (odd divisors)
//choose m_divider such that filter tuning constraint is met
m = 31;
@@ -340,7 +342,7 @@ void dbsrx::set_lo_freq(double target_freq){
//vtune is too low, try lower frequency vco
if (_max2118_read_regs.adc == 0){
if (_max2118_write_regs.osc_band == 0){
- uhd::print_warning(
+ uhd::warning::post(
str(boost::format(
"DBSRX: Tuning exceeded vco range, _max2118_write_regs.osc_band == %d\n"
) % int(_max2118_write_regs.osc_band))
@@ -354,7 +356,7 @@ void dbsrx::set_lo_freq(double target_freq){
//vtune is too high, try higher frequency vco
if (_max2118_read_regs.adc == 7){
if (_max2118_write_regs.osc_band == 7){
- uhd::print_warning(
+ uhd::warning::post(
str(boost::format(
"DBSRX: Tuning exceeded vco range, _max2118_write_regs.osc_band == %d\n"
) % int(_max2118_write_regs.osc_band))
@@ -561,7 +563,7 @@ void dbsrx::rx_get(const wax::obj &key_, wax::obj &val){
return;
case SUBDEV_PROP_BANDWIDTH:
- val = _bandwidth;
+ val = 2*_bandwidth; //_bandwidth is low-pass, we want complex double-sided
return;
default: UHD_THROW_PROP_GET_ERROR();
@@ -586,7 +588,7 @@ void dbsrx::rx_set(const wax::obj &key_, const wax::obj &val){
return; //always enabled
case SUBDEV_PROP_BANDWIDTH:
- this->set_bandwidth(val.as<double>());
+ this->set_bandwidth(val.as<double>()/2.0); //complex double-sided, we want low-pass
return;
default: UHD_THROW_PROP_SET_ERROR();
diff --git a/host/lib/usrp/dboard/db_rfx.cpp b/host/lib/usrp/dboard/db_rfx.cpp
index 3c24d90db..152198c3a 100644
--- a/host/lib/usrp/dboard/db_rfx.cpp
+++ b/host/lib/usrp/dboard/db_rfx.cpp
@@ -43,6 +43,7 @@
#include <uhd/utils/assert.hpp>
#include <uhd/utils/static.hpp>
#include <uhd/utils/algorithm.hpp>
+#include <uhd/utils/warning.hpp>
#include <uhd/usrp/dboard_id.hpp>
#include <uhd/usrp/dboard_base.hpp>
#include <uhd/usrp/dboard_manager.hpp>
@@ -456,6 +457,10 @@ void rfx_xcvr::rx_get(const wax::obj &key_, wax::obj &val){
val = this->get_locked(dboard_iface::UNIT_RX);
return;
+ case SUBDEV_PROP_BANDWIDTH:
+ val = 2*20.0e6; //20MHz low-pass, we want complex double-sided
+ return;
+
default: UHD_THROW_PROP_GET_ERROR();
}
}
@@ -481,6 +486,12 @@ void rfx_xcvr::rx_set(const wax::obj &key_, const wax::obj &val){
case SUBDEV_PROP_ENABLED:
return; //always enabled
+ case SUBDEV_PROP_BANDWIDTH:
+ uhd::warning::post(
+ str(boost::format("RFX: No tunable bandwidth, fixed filtered to 40MHz"))
+ );
+ return;
+
default: UHD_THROW_PROP_SET_ERROR();
}
}
@@ -543,6 +554,10 @@ void rfx_xcvr::tx_get(const wax::obj &key_, wax::obj &val){
val = this->get_locked(dboard_iface::UNIT_TX);
return;
+ case SUBDEV_PROP_BANDWIDTH:
+ val = 2*20.0e6; //20MHz low-pass, we want complex double-sided
+ return;
+
default: UHD_THROW_PROP_GET_ERROR();
}
}
@@ -568,6 +583,12 @@ void rfx_xcvr::tx_set(const wax::obj &key_, const wax::obj &val){
case SUBDEV_PROP_ENABLED:
return; //always enabled
+ case SUBDEV_PROP_BANDWIDTH:
+ uhd::warning::post(
+ str(boost::format("RFX: No tunable bandwidth, fixed filtered to 40MHz"))
+ );
+ return;
+
default: UHD_THROW_PROP_SET_ERROR();
}
}
diff --git a/host/lib/usrp/dboard/db_tvrx.cpp b/host/lib/usrp/dboard/db_tvrx.cpp
index d39dc3bf8..2873e3d54 100644
--- a/host/lib/usrp/dboard/db_tvrx.cpp
+++ b/host/lib/usrp/dboard/db_tvrx.cpp
@@ -459,6 +459,10 @@ void tvrx::rx_get(const wax::obj &key_, wax::obj &val){
val = true;
return;
+ case SUBDEV_PROP_BANDWIDTH:
+ val = 6.0e6;
+ return;
+
default: UHD_THROW_PROP_GET_ERROR();
}
}
@@ -479,6 +483,12 @@ void tvrx::rx_set(const wax::obj &key_, const wax::obj &val){
case SUBDEV_PROP_ENABLED:
return; //always enabled
+ case SUBDEV_PROP_BANDWIDTH:
+ uhd::warning::post(
+ str(boost::format("TVRX: No tunable bandwidth, fixed filtered to 6MHz"))
+ );
+ return;
+
default: UHD_THROW_PROP_SET_ERROR();
}
}
diff --git a/host/lib/usrp/dboard/db_unknown.cpp b/host/lib/usrp/dboard/db_unknown.cpp
index ec7ab440b..a342471c4 100644
--- a/host/lib/usrp/dboard/db_unknown.cpp
+++ b/host/lib/usrp/dboard/db_unknown.cpp
@@ -19,6 +19,7 @@
#include <uhd/types/ranges.hpp>
#include <uhd/utils/assert.hpp>
#include <uhd/utils/static.hpp>
+#include <uhd/utils/warning.hpp>
#include <uhd/usrp/dboard_base.hpp>
#include <uhd/usrp/dboard_manager.hpp>
#include <boost/assign/list_of.hpp>
@@ -134,6 +135,10 @@ void unknown_rx::rx_get(const wax::obj &key_, wax::obj &val){
val = true; //there is no LO, so it must be true!
return;
+ case SUBDEV_PROP_BANDWIDTH:
+ val = 0.0;
+ return;
+
default: UHD_THROW_PROP_GET_ERROR();
}
}
@@ -158,12 +163,18 @@ void unknown_rx::rx_set(const wax::obj &key_, const wax::obj &val){
case SUBDEV_PROP_ENABLED:
return; //always enabled
+ case SUBDEV_PROP_BANDWIDTH:
+ uhd::warning::post(
+ str(boost::format("Unknown Daughterboard: No tunable bandwidth, fixed filtered to 0.0MHz"))
+ );
+ return;
+
default: UHD_THROW_PROP_SET_ERROR();
}
}
/***********************************************************************
- * Basic and LF TX dboard
+ * Unknown TX dboard
**********************************************************************/
unknown_tx::unknown_tx(ctor_args_t args) : tx_dboard_base(args){
/* NOP */
@@ -230,6 +241,10 @@ void unknown_tx::tx_get(const wax::obj &key_, wax::obj &val){
val = true; //there is no LO, so it must be true!
return;
+ case SUBDEV_PROP_BANDWIDTH:
+ val = 0.0;
+ return;
+
default: UHD_THROW_PROP_GET_ERROR();
}
}
@@ -254,6 +269,12 @@ void unknown_tx::tx_set(const wax::obj &key_, const wax::obj &val){
case SUBDEV_PROP_ENABLED:
return; //always enabled
+ case SUBDEV_PROP_BANDWIDTH:
+ uhd::warning::post(
+ str(boost::format("Unknown Daughterboard: No tunable bandwidth, fixed filtered to 0.0MHz"))
+ );
+ return;
+
default: UHD_THROW_PROP_SET_ERROR();
}
}
diff --git a/host/lib/usrp/dboard/db_wbx.cpp b/host/lib/usrp/dboard/db_wbx.cpp
index 907268aac..572f5de97 100644
--- a/host/lib/usrp/dboard/db_wbx.cpp
+++ b/host/lib/usrp/dboard/db_wbx.cpp
@@ -71,6 +71,7 @@
#include <uhd/utils/assert.hpp>
#include <uhd/utils/static.hpp>
#include <uhd/utils/algorithm.hpp>
+#include <uhd/utils/warning.hpp>
#include <uhd/usrp/dboard_base.hpp>
#include <uhd/usrp/dboard_manager.hpp>
#include <boost/assign/list_of.hpp>
@@ -525,6 +526,10 @@ void wbx_xcvr::rx_get(const wax::obj &key_, wax::obj &val){
val = this->get_locked(dboard_iface::UNIT_RX);
return;
+ case SUBDEV_PROP_BANDWIDTH:
+ val = 2*20.0e6; //20MHz low-pass, we want complex double-sided
+ return;
+
default: UHD_THROW_PROP_GET_ERROR();
}
}
@@ -550,6 +555,12 @@ void wbx_xcvr::rx_set(const wax::obj &key_, const wax::obj &val){
case SUBDEV_PROP_ENABLED:
return; //always enabled
+ case SUBDEV_PROP_BANDWIDTH:
+ uhd::warning::post(
+ str(boost::format("WBX: No tunable bandwidth, fixed filtered to 40MHz"))
+ );
+ return;
+
default: UHD_THROW_PROP_SET_ERROR();
}
}
@@ -616,6 +627,10 @@ void wbx_xcvr::tx_get(const wax::obj &key_, wax::obj &val){
val = this->get_locked(dboard_iface::UNIT_TX);
return;
+ case SUBDEV_PROP_BANDWIDTH:
+ val = 2*20.0e6; //20MHz low-pass, we want complex double-sided
+ return;
+
default: UHD_THROW_PROP_GET_ERROR();
}
}
@@ -641,6 +656,12 @@ void wbx_xcvr::tx_set(const wax::obj &key_, const wax::obj &val){
case SUBDEV_PROP_ENABLED:
return; //always enabled
+ case SUBDEV_PROP_BANDWIDTH:
+ uhd::warning::post(
+ str(boost::format("WBX: No tunable bandwidth, fixed filtered to 40MHz"))
+ );
+ return;
+
default: UHD_THROW_PROP_SET_ERROR();
}
}
diff --git a/host/lib/usrp/dboard/db_xcvr2450.cpp b/host/lib/usrp/dboard/db_xcvr2450.cpp
index fb1367113..be0e42b92 100644
--- a/host/lib/usrp/dboard/db_xcvr2450.cpp
+++ b/host/lib/usrp/dboard/db_xcvr2450.cpp
@@ -626,7 +626,7 @@ void xcvr2450::rx_get(const wax::obj &key_, wax::obj &val){
return;
case SUBDEV_PROP_BANDWIDTH:
- val = _rx_bandwidth;
+ val = 2*_rx_bandwidth; //_tx_bandwidth is low-pass, we want complex double-sided
return;
default: UHD_THROW_PROP_GET_ERROR();
@@ -652,7 +652,7 @@ void xcvr2450::rx_set(const wax::obj &key_, const wax::obj &val){
return;
case SUBDEV_PROP_BANDWIDTH:
- this->set_rx_bandwidth(val.as<double>());
+ this->set_rx_bandwidth(val.as<double>()/2.0); //complex double-sided, we want low-pass
return;
case SUBDEV_PROP_ENABLED:
@@ -725,7 +725,7 @@ void xcvr2450::tx_get(const wax::obj &key_, wax::obj &val){
return;
case SUBDEV_PROP_BANDWIDTH:
- val = _tx_bandwidth;
+ val = 2*_tx_bandwidth; //_tx_bandwidth is low-pass, we want complex double-sided
return;
default: UHD_THROW_PROP_GET_ERROR();
@@ -747,7 +747,7 @@ void xcvr2450::tx_set(const wax::obj &key_, const wax::obj &val){
return;
case SUBDEV_PROP_BANDWIDTH:
- this->set_tx_bandwidth(val.as<double>());
+ this->set_tx_bandwidth(val.as<double>()/2.0); //complex double-sided, we want low-pass
return;
case SUBDEV_PROP_ANTENNA:
diff --git a/host/lib/usrp/dboard_manager.cpp b/host/lib/usrp/dboard_manager.cpp
index d73a698ae..5a98bb8eb 100644
--- a/host/lib/usrp/dboard_manager.cpp
+++ b/host/lib/usrp/dboard_manager.cpp
@@ -189,7 +189,7 @@ static args_t get_dboard_args(
//verify that there is a registered constructor for this id
if (not get_id_to_args_map().has_key(dboard_id)){
- uhd::print_warning(str(boost::format(
+ uhd::warning::post(str(boost::format(
"Unknown dboard ID: %s.\n"
) % dboard_id.to_pp_string()));
return get_dboard_args(unit, dboard_id, true);
@@ -217,7 +217,7 @@ dboard_manager_impl::dboard_manager_impl(
//warn for invalid dboard id xcvr combinations
if (rx_dboard_is_xcvr != this_dboard_is_xcvr or tx_dboard_is_xcvr != this_dboard_is_xcvr){
- uhd::print_warning(str(boost::format(
+ uhd::warning::post(str(boost::format(
"Unknown transceiver board ID combination...\n"
"RX dboard ID: %s\n"
"TX dboard ID: %s\n"
diff --git a/host/lib/usrp/misc_utils.cpp b/host/lib/usrp/misc_utils.cpp
index 7e49baa52..5856d706f 100644
--- a/host/lib/usrp/misc_utils.cpp
+++ b/host/lib/usrp/misc_utils.cpp
@@ -164,13 +164,13 @@ static void verify_xx_subdev_spec(
}
//sanity check that the dboard/subdevice names exist for this mboard
- BOOST_FOREACH(const subdev_spec_pair_t &pair, subdev_spec){
+ BOOST_FOREACH(subdev_spec_pair_t &pair, subdev_spec){
//empty db name means select dboard automatically
if (pair.db_name.empty()){
if (dboard_names.size() != 1) throw std::runtime_error(
"A daughterboard name must be provided for multi-slot motherboards: " + subdev_spec.to_string()
);
- pair.db_name == dboard_names.front();
+ pair.db_name = dboard_names.front();
}
uhd::assert_has(dboard_names, pair.db_name, xx_type + " dboard name");
wax::obj dboard = mboard[named_prop_t(dboard_prop, pair.db_name)];
@@ -181,7 +181,7 @@ static void verify_xx_subdev_spec(
if (subdev_names.size() != 1) throw std::runtime_error(
"A subdevice name must be provided for multi-subdev daughterboards: " + subdev_spec.to_string()
);
- pair.sd_name == subdev_names.front();
+ pair.sd_name = subdev_names.front();
}
uhd::assert_has(subdev_names, pair.sd_name, xx_type + " subdev name");
}
diff --git a/host/lib/usrp/multi_usrp.cpp b/host/lib/usrp/multi_usrp.cpp
index 443b91594..876f1a3fc 100644
--- a/host/lib/usrp/multi_usrp.cpp
+++ b/host/lib/usrp/multi_usrp.cpp
@@ -145,7 +145,7 @@ public:
time_spec_t time_0 = _mboard(0)[MBOARD_PROP_TIME_NOW].as<time_spec_t>();
time_spec_t time_i = _mboard(m)[MBOARD_PROP_TIME_NOW].as<time_spec_t>();
if (time_i < time_0 or (time_i - time_0) > time_spec_t(0.01)){ //10 ms: greater than RTT but not too big
- uhd::print_warning(str(boost::format(
+ uhd::warning::post(str(boost::format(
"Detected time deviation between board %d and board 0.\n"
"Board 0 time is %f seconds.\n"
"Board %d time is %f seconds.\n"
@@ -154,6 +154,15 @@ public:
}
}
+ bool get_time_synchronized(void){
+ for (size_t m = 1; m < get_num_mboards(); m++){
+ time_spec_t time_0 = _mboard(0)[MBOARD_PROP_TIME_NOW].as<time_spec_t>();
+ time_spec_t time_i = _mboard(m)[MBOARD_PROP_TIME_NOW].as<time_spec_t>();
+ if (time_i < time_0 or (time_i - time_0) > time_spec_t(0.01)) return false;
+ }
+ return true;
+ }
+
void issue_stream_cmd(const stream_cmd_t &stream_cmd){
for (size_t m = 0; m < get_num_mboards(); m++){
_mboard(m)[MBOARD_PROP_STREAM_CMD] = stream_cmd;
@@ -210,15 +219,9 @@ public:
return _rx_dsp(0)[DSP_PROP_HOST_RATE].as<double>();
}
- tune_result_t set_rx_freq(double target_freq, size_t chan){
- tune_result_t r = tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan/rx_cpm()), chan%rx_cpm(), target_freq);
- do_tune_freq_warning_message(target_freq, get_rx_freq(chan), "RX");
- return r;
- }
-
- tune_result_t set_rx_freq(double target_freq, double lo_off, size_t chan){
- tune_result_t r = tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan/rx_cpm()), chan%rx_cpm(), target_freq, lo_off);
- do_tune_freq_warning_message(target_freq, get_rx_freq(chan), "RX");
+ tune_result_t set_rx_freq(const tune_request_t &tune_request, size_t chan){
+ tune_result_t r = tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan/rx_cpm()), chan%rx_cpm(), tune_request);
+ do_tune_freq_warning_message(tune_request.target_freq, get_rx_freq(chan), "RX");
return r;
}
@@ -314,15 +317,9 @@ public:
return _tx_dsp(0)[DSP_PROP_HOST_RATE].as<double>();
}
- tune_result_t set_tx_freq(double target_freq, size_t chan){
- tune_result_t r = tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan/tx_cpm()), chan%tx_cpm(), target_freq);
- do_tune_freq_warning_message(target_freq, get_tx_freq(chan), "TX");
- return r;
- }
-
- tune_result_t set_tx_freq(double target_freq, double lo_off, size_t chan){
- tune_result_t r = tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan/tx_cpm()), chan%tx_cpm(), target_freq, lo_off);
- do_tune_freq_warning_message(target_freq, get_tx_freq(chan), "TX");
+ tune_result_t set_tx_freq(const tune_request_t &tune_request, size_t chan){
+ tune_result_t r = tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan/tx_cpm()), chan%tx_cpm(), tune_request);
+ do_tune_freq_warning_message(tune_request.target_freq, get_tx_freq(chan), "TX");
return r;
}
diff --git a/host/lib/usrp/single_usrp.cpp b/host/lib/usrp/single_usrp.cpp
index 5e57849b8..a0456d1f0 100644
--- a/host/lib/usrp/single_usrp.cpp
+++ b/host/lib/usrp/single_usrp.cpp
@@ -146,15 +146,9 @@ public:
return _rx_dsp()[DSP_PROP_HOST_RATE].as<double>();
}
- tune_result_t set_rx_freq(double target_freq, size_t chan){
- tune_result_t r = tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(), chan, target_freq);
- do_tune_freq_warning_message(target_freq, get_rx_freq(chan), "RX");
- return r;
- }
-
- tune_result_t set_rx_freq(double target_freq, double lo_off, size_t chan){
- tune_result_t r = tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(), chan, target_freq, lo_off);
- do_tune_freq_warning_message(target_freq, get_rx_freq(chan), "RX");
+ tune_result_t set_rx_freq(const tune_request_t &tune_request, size_t chan){
+ tune_result_t r = tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(), chan, tune_request);
+ do_tune_freq_warning_message(tune_request.target_freq, get_rx_freq(chan), "RX");
return r;
}
@@ -238,15 +232,9 @@ public:
return _tx_dsp()[DSP_PROP_HOST_RATE].as<double>();
}
- tune_result_t set_tx_freq(double target_freq, size_t chan){
- tune_result_t r = tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(), chan, target_freq);
- do_tune_freq_warning_message(target_freq, get_tx_freq(chan), "TX");
- return r;
- }
-
- tune_result_t set_tx_freq(double target_freq, double lo_off, size_t chan){
- tune_result_t r = tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(), chan, target_freq, lo_off);
- do_tune_freq_warning_message(target_freq, get_tx_freq(chan), "TX");
+ tune_result_t set_tx_freq(const tune_request_t &tune_request, size_t chan){
+ tune_result_t r = tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(), chan, tune_request);
+ do_tune_freq_warning_message(tune_request.target_freq, get_tx_freq(chan), "TX");
return r;
}
diff --git a/host/lib/usrp/tune_helper.cpp b/host/lib/usrp/tune_helper.cpp
index 7633c67f2..fa40a8a26 100644
--- a/host/lib/usrp/tune_helper.cpp
+++ b/host/lib/usrp/tune_helper.cpp
@@ -19,6 +19,7 @@
#include <uhd/usrp/subdev_props.hpp>
#include <uhd/usrp/dsp_props.hpp>
#include <uhd/usrp/dboard_iface.hpp> //unit_t
+#include <uhd/utils/algorithm.hpp>
#include <boost/math/special_functions/sign.hpp>
#include <cmath>
@@ -28,55 +29,99 @@ using namespace uhd::usrp;
/***********************************************************************
* Tune Helper Functions
**********************************************************************/
-static tune_result_t tune_xx_subdev_and_dxc(
+static tune_result_t tune_xx_subdev_and_dsp(
dboard_iface::unit_t unit,
- wax::obj subdev, wax::obj dxc, size_t chan,
- double target_freq, double lo_offset
+ wax::obj subdev, wax::obj dsp, size_t chan,
+ const tune_request_t &tune_request
){
wax::obj subdev_freq_proxy = subdev[SUBDEV_PROP_FREQ];
- std::string freq_name = dxc[DSP_PROP_FREQ_SHIFT_NAMES].as<prop_names_t>().at(chan);
- wax::obj dxc_freq_proxy = dxc[named_prop_t(DSP_PROP_FREQ_SHIFT, freq_name)];
- double dxc_sample_rate = dxc[DSP_PROP_CODEC_RATE].as<double>();
+ std::string freq_name = dsp[DSP_PROP_FREQ_SHIFT_NAMES].as<prop_names_t>().at(chan);
+ wax::obj dsp_freq_proxy = dsp[named_prop_t(DSP_PROP_FREQ_SHIFT, freq_name)];
+ double dsp_sample_rate = dsp[DSP_PROP_CODEC_RATE].as<double>();
- // Ask the d'board to tune as closely as it can to target_freq+lo_offset
- double target_inter_freq = target_freq + lo_offset;
- subdev_freq_proxy = target_inter_freq;
- double actual_inter_freq = subdev_freq_proxy.as<double>();
-
- //perform the correction correction for dxc rates outside of nyquist
- double delta_freq = std::fmod(target_freq - actual_inter_freq, dxc_sample_rate);
- bool outside_of_nyquist = std::abs(delta_freq) > dxc_sample_rate/2.0;
- double target_dxc_freq = (outside_of_nyquist)?
- boost::math::sign(delta_freq)*dxc_sample_rate - delta_freq : -delta_freq;
+ //------------------------------------------------------------------
+ //-- calculate the LO offset, only used with automatic policy
+ //------------------------------------------------------------------
+ double lo_offset = 0.0;
+ if (subdev[SUBDEV_PROP_USE_LO_OFFSET].as<bool>()){
+ //If the local oscillator will be in the passband, use an offset.
+ //But constrain the LO offset by the width of the filter bandwidth.
+ double rate = dsp[DSP_PROP_HOST_RATE].as<double>();
+ double bw = subdev[SUBDEV_PROP_BANDWIDTH].as<double>();
+ if (bw > rate) lo_offset = std::min((bw - rate)/2, rate/2);
+ }
- //invert the sign on the dxc freq given the following conditions
- if (unit == dboard_iface::UNIT_TX) target_dxc_freq *= -1.0;
+ //------------------------------------------------------------------
+ //-- set the intermediate frequency depending upon the IF policy
+ //------------------------------------------------------------------
+ double target_inter_freq = 0.0;
+ switch (tune_request.inter_freq_policy){
+ case tune_request_t::POLICY_AUTO:
+ target_inter_freq = tune_request.target_freq + lo_offset;
+ subdev_freq_proxy = target_inter_freq;
+ break;
+
+ case tune_request_t::POLICY_MANUAL:
+ target_inter_freq = tune_request.inter_freq;
+ subdev_freq_proxy = target_inter_freq;
+ break;
+
+ case tune_request_t::POLICY_NONE: break; //does not set
+ }
+ double actual_inter_freq = subdev_freq_proxy.as<double>();
- dxc_freq_proxy = target_dxc_freq;
- double actual_dxc_freq = dxc_freq_proxy.as<double>();
+ //------------------------------------------------------------------
+ //-- calculate the dsp freq, only used with automatic policy
+ //------------------------------------------------------------------
+ double delta_freq = std::fmod(tune_request.target_freq - actual_inter_freq, dsp_sample_rate);
+ bool outside_of_nyquist = std::abs(delta_freq) > dsp_sample_rate/2.0;
+ double target_dsp_freq = (outside_of_nyquist)?
+ boost::math::sign(delta_freq)*dsp_sample_rate - delta_freq : -delta_freq;
+
+ //invert the sign on the dsp freq given the following conditions
+ if (unit == dboard_iface::UNIT_TX) target_dsp_freq *= -1.0;
+
+ //------------------------------------------------------------------
+ //-- set the dsp frequency depending upon the dsp frequency policy
+ //------------------------------------------------------------------
+ switch (tune_request.dsp_freq_policy){
+ case tune_request_t::POLICY_AUTO:
+ dsp_freq_proxy = target_dsp_freq;
+ break;
+
+ case tune_request_t::POLICY_MANUAL:
+ target_dsp_freq = tune_request.dsp_freq;
+ dsp_freq_proxy = target_dsp_freq;
+ break;
+
+ case tune_request_t::POLICY_NONE: break; //does not set
+ }
+ double actual_dsp_freq = dsp_freq_proxy.as<double>();
- //load and return the tune result
+ //------------------------------------------------------------------
+ //-- load and return the tune result
+ //------------------------------------------------------------------
tune_result_t tune_result;
tune_result.target_inter_freq = target_inter_freq;
tune_result.actual_inter_freq = actual_inter_freq;
- tune_result.target_dsp_freq = target_dxc_freq;
- tune_result.actual_dsp_freq = actual_dxc_freq;
+ tune_result.target_dsp_freq = target_dsp_freq;
+ tune_result.actual_dsp_freq = actual_dsp_freq;
return tune_result;
}
-static double derive_freq_from_xx_subdev_and_dxc(
+static double derive_freq_from_xx_subdev_and_dsp(
dboard_iface::unit_t unit,
- wax::obj subdev, wax::obj dxc, size_t chan
+ wax::obj subdev, wax::obj dsp, size_t chan
){
//extract actual dsp and IF frequencies
double actual_inter_freq = subdev[SUBDEV_PROP_FREQ].as<double>();
- std::string freq_name = dxc[DSP_PROP_FREQ_SHIFT_NAMES].as<prop_names_t>().at(chan);
- double actual_dxc_freq = dxc[named_prop_t(DSP_PROP_FREQ_SHIFT, freq_name)].as<double>();
+ std::string freq_name = dsp[DSP_PROP_FREQ_SHIFT_NAMES].as<prop_names_t>().at(chan);
+ double actual_dsp_freq = dsp[named_prop_t(DSP_PROP_FREQ_SHIFT, freq_name)].as<double>();
- //invert the sign on the dxc freq given the following conditions
- if (unit == dboard_iface::UNIT_TX) actual_dxc_freq *= -1.0;
+ //invert the sign on the dsp freq given the following conditions
+ if (unit == dboard_iface::UNIT_TX) actual_dsp_freq *= -1.0;
- return actual_inter_freq - actual_dxc_freq;
+ return actual_inter_freq - actual_dsp_freq;
}
/***********************************************************************
@@ -84,27 +129,15 @@ static double derive_freq_from_xx_subdev_and_dxc(
**********************************************************************/
tune_result_t usrp::tune_rx_subdev_and_dsp(
wax::obj subdev, wax::obj ddc, size_t chan,
- double target_freq, double lo_offset
-){
- return tune_xx_subdev_and_dxc(dboard_iface::UNIT_RX, subdev, ddc, chan, target_freq, lo_offset);
-}
-
-tune_result_t usrp::tune_rx_subdev_and_dsp(
- wax::obj subdev, wax::obj ddc,
- size_t chan, double target_freq
+ const tune_request_t &tune_request
){
- double lo_offset = 0.0;
- //if the local oscillator will be in the passband, use an offset
- if (subdev[SUBDEV_PROP_USE_LO_OFFSET].as<bool>()){
- lo_offset = 2.0*ddc[DSP_PROP_HOST_RATE].as<double>();
- }
- return tune_rx_subdev_and_dsp(subdev, ddc, chan, target_freq, lo_offset);
+ return tune_xx_subdev_and_dsp(dboard_iface::UNIT_RX, subdev, ddc, chan, tune_request);
}
double usrp::derive_freq_from_rx_subdev_and_dsp(
wax::obj subdev, wax::obj ddc, size_t chan
){
- return derive_freq_from_xx_subdev_and_dxc(dboard_iface::UNIT_RX, subdev, ddc, chan);
+ return derive_freq_from_xx_subdev_and_dsp(dboard_iface::UNIT_RX, subdev, ddc, chan);
}
/***********************************************************************
@@ -112,25 +145,13 @@ double usrp::derive_freq_from_rx_subdev_and_dsp(
**********************************************************************/
tune_result_t usrp::tune_tx_subdev_and_dsp(
wax::obj subdev, wax::obj duc, size_t chan,
- double target_freq, double lo_offset
+ const tune_request_t &tune_request
){
- return tune_xx_subdev_and_dxc(dboard_iface::UNIT_TX, subdev, duc, chan, target_freq, lo_offset);
-}
-
-tune_result_t usrp::tune_tx_subdev_and_dsp(
- wax::obj subdev, wax::obj duc,
- size_t chan, double target_freq
-){
- double lo_offset = 0.0;
- //if the local oscillator will be in the passband, use an offset
- if (subdev[SUBDEV_PROP_USE_LO_OFFSET].as<bool>()){
- lo_offset = 2.0*duc[DSP_PROP_HOST_RATE].as<double>();
- }
- return tune_tx_subdev_and_dsp(subdev, duc, chan, target_freq, lo_offset);
+ return tune_xx_subdev_and_dsp(dboard_iface::UNIT_TX, subdev, duc, chan, tune_request);
}
double usrp::derive_freq_from_tx_subdev_and_dsp(
wax::obj subdev, wax::obj duc, size_t chan
){
- return derive_freq_from_xx_subdev_and_dxc(dboard_iface::UNIT_TX, subdev, duc, chan);
+ return derive_freq_from_xx_subdev_and_dsp(dboard_iface::UNIT_TX, subdev, duc, chan);
}
diff --git a/host/lib/usrp/usrp1/mboard_impl.cpp b/host/lib/usrp/usrp1/mboard_impl.cpp
index fe3774eb4..669b20efa 100644
--- a/host/lib/usrp/usrp1/mboard_impl.cpp
+++ b/host/lib/usrp/usrp1/mboard_impl.cpp
@@ -98,7 +98,7 @@ static boost::uint32_t calc_rx_mux(
// for all quadrature sources: Z = 0
// for mixed sources: warning + Z = 0
int Z = (num_quads > 0)? 0 : 1;
- if (num_quads != 0 and num_reals != 0) uhd::print_warning(
+ if (num_quads != 0 and num_reals != 0) uhd::warning::post(
"Mixing real and quadrature rx subdevices is not supported.\n"
"The Q input to the real source(s) will be non-zero.\n"
);
diff --git a/host/lib/usrp/usrp1/usrp1_impl.cpp b/host/lib/usrp/usrp1/usrp1_impl.cpp
index 276ca86f6..bc478c7fb 100644
--- a/host/lib/usrp/usrp1/usrp1_impl.cpp
+++ b/host/lib/usrp/usrp1/usrp1_impl.cpp
@@ -59,12 +59,10 @@ static device_addrs_t usrp1_find(const device_addr_t &hint)
//extract the firmware path for the USRP1
std::string usrp1_fw_image;
try{
- usrp1_fw_image = find_image_path(
- hint.has_key("fw")? hint["fw"] : "usrp1_fw.ihx"
- );
+ usrp1_fw_image = find_image_path(hint.get("fw", "usrp1_fw.ihx"));
}
catch(...){
- uhd::print_warning(
+ uhd::warning::post(
"Could not locate USRP1 firmware.\n"
"Please install the images package.\n"
);
@@ -110,7 +108,7 @@ static device::sptr usrp1_make(const device_addr_t &device_addr){
//extract the FPGA path for the USRP1
std::string usrp1_fpga_image = find_image_path(
- device_addr.has_key("fpga")? device_addr["fpga"] : "usrp1_fpga.rbf"
+ device_addr.get("fpga", "usrp1_fpga.rbf")
);
//std::cout << "USRP1 FPGA image: " << usrp1_fpga_image << std::endl;
diff --git a/host/lib/usrp/wrapper_utils.hpp b/host/lib/usrp/wrapper_utils.hpp
index aee230fc0..6f9fdbfca 100644
--- a/host/lib/usrp/wrapper_utils.hpp
+++ b/host/lib/usrp/wrapper_utils.hpp
@@ -40,7 +40,7 @@ static inline void do_samp_rate_warning_message(
){
static const double max_allowed_error = 1.0; //Sps
if (std::abs(target_rate - actual_rate) > max_allowed_error){
- uhd::print_warning(str(boost::format(
+ uhd::warning::post(str(boost::format(
"The hardware does not support the requested %s sample rate:\n"
"Target sample rate: %f MSps\n"
"Actual sample rate: %f MSps\n"
@@ -55,7 +55,7 @@ static inline void do_tune_freq_warning_message(
){
static const double max_allowed_error = 1.0; //Hz
if (std::abs(target_freq - actual_freq) > max_allowed_error){
- uhd::print_warning(str(boost::format(
+ uhd::warning::post(str(boost::format(
"The hardware does not support the requested %s frequency:\n"
"Target frequency: %f MHz\n"
"Actual frequency: %f MHz\n"
diff --git a/host/lib/utils/thread_priority.cpp b/host/lib/utils/thread_priority.cpp
index f09d1b1d6..40b74f655 100644
--- a/host/lib/utils/thread_priority.cpp
+++ b/host/lib/utils/thread_priority.cpp
@@ -26,7 +26,7 @@ bool uhd::set_thread_priority_safe(float priority, bool realtime){
set_thread_priority(priority, realtime);
return true;
}catch(const std::exception &e){
- uhd::print_warning(str(boost::format(
+ uhd::warning::post(str(boost::format(
"%s\n"
"Failed to set thread priority %d (%s):\n"
"Performance may be negatively affected.\n"
diff --git a/host/lib/utils/warning.cpp b/host/lib/utils/warning.cpp
index 8a7d35a23..05be7ae4d 100644
--- a/host/lib/utils/warning.cpp
+++ b/host/lib/utils/warning.cpp
@@ -17,16 +17,67 @@
#include <uhd/utils/warning.hpp>
#include <uhd/utils/algorithm.hpp>
+#include <uhd/utils/static.hpp>
+#include <uhd/types/dict.hpp>
#include <boost/foreach.hpp>
+#include <sstream>
+#include <stdexcept>
#include <iostream>
#include <vector>
using namespace uhd;
-void uhd::print_warning(const std::string &msg){
- //print the warning message
- std::cerr << std::endl << "Warning:" << std::endl;
+/***********************************************************************
+ * Registry implementation
+ **********************************************************************/
+//create the registry for the handlers
+typedef uhd::dict<std::string, warning::handler_t> registry_t;
+UHD_SINGLETON_FCN(registry_t, get_registry)
+
+//the default warning handler
+static void stderr_warning(const std::string &msg){
+ std::cerr << msg;
+}
+
+//register a default handler
+UHD_STATIC_BLOCK(warning_register_default){
+ warning::register_handler("default", &stderr_warning);
+}
+
+/***********************************************************************
+ * Post + format
+ **********************************************************************/
+void warning::post(const std::string &msg){
+ std::stringstream ss;
+
+ //format the warning message
+ ss << std::endl << "Warning:" << std::endl;
BOOST_FOREACH(const std::string &line, std::split_string(msg, "\n")){
- std::cerr << " " << line << std::endl;
+ ss << " " << line << std::endl;
+ }
+
+ //post the formatted message
+ BOOST_FOREACH(const std::string &name, get_registry().keys()){
+ get_registry()[name](ss.str());
}
}
+
+/***********************************************************************
+ * Registry accessor functions
+ **********************************************************************/
+void warning::register_handler(
+ const std::string &name, const handler_t &handler
+){
+ get_registry()[name] = handler;
+}
+
+warning::handler_t warning::unregister_handler(const std::string &name){
+ if (not get_registry().has_key(name)) throw std::runtime_error(
+ "The warning registry does not have a handler registered to " + name
+ );
+ return get_registry().pop(name);
+}
+
+const std::vector<std::string> warning::registry_names(void){
+ return get_registry().keys();
+}
diff --git a/host/test/tune_helper_test.cpp b/host/test/tune_helper_test.cpp
index 1ef4af330..e0500ae3f 100644
--- a/host/test/tune_helper_test.cpp
+++ b/host/test/tune_helper_test.cpp
@@ -91,6 +91,44 @@ private:
}
};
+class dummy_subdev_bw : public wax::obj{
+private:
+ void get(const wax::obj &key, wax::obj &val){
+ switch(key.as<subdev_prop_t>()){
+
+ case SUBDEV_PROP_FREQ:
+ val = _freq;
+ return;
+
+ case SUBDEV_PROP_USE_LO_OFFSET:
+ val = true;
+ return;
+
+ case SUBDEV_PROP_BANDWIDTH:
+ val = _bandwidth;
+ return;
+
+ default: UHD_THROW_PROP_GET_ERROR();
+ }
+ }
+
+ void set(const wax::obj &key, const wax::obj &val){
+ switch(key.as<subdev_prop_t>()){
+ case SUBDEV_PROP_FREQ:
+ _freq = val.as<double>();
+ return;
+
+ case SUBDEV_PROP_BANDWIDTH:
+ _bandwidth = val.as<double>();
+ return;
+
+ default: UHD_THROW_PROP_SET_ERROR();
+ }
+ }
+
+ double _freq, _bandwidth;
+};
+
class dummy_dsp : public wax::obj{
public:
dummy_dsp(double codec_rate):
@@ -106,6 +144,10 @@ private:
val = _codec_rate;
return;
+ case DSP_PROP_HOST_RATE:
+ val = _host_rate;
+ return;
+
case DSP_PROP_FREQ_SHIFT:
val = _freq_shift;
return;
@@ -125,11 +167,15 @@ private:
_freq_shift = val.as<double>();
return;
+ case DSP_PROP_HOST_RATE:
+ _host_rate = val.as<double>();
+ return;
+
default: UHD_THROW_PROP_SET_ERROR();
}
}
- double _codec_rate, _freq_shift;
+ double _codec_rate, _freq_shift, _host_rate;
};
/***********************************************************************
@@ -141,7 +187,7 @@ BOOST_AUTO_TEST_CASE(test_tune_helper_rx){
dummy_subdev subdev(1e6);
dummy_dsp dsp(100e6);
- std::cout << "Testing tune helper RX automatic LO offset" << std::endl;
+ std::cout << "Testing tune helper RX automatic IF offset" << std::endl;
tune_result_t tr = tune_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 0, 2.3451e9);
std::cout << tr.to_pp_string() << std::endl;
BOOST_CHECK_CLOSE(tr.actual_inter_freq, 2.345e9, tolerance);
@@ -155,7 +201,7 @@ BOOST_AUTO_TEST_CASE(test_tune_helper_tx){
dummy_subdev subdev(1e6);
dummy_dsp dsp(100e6);
- std::cout << "Testing tune helper TX automatic LO offset" << std::endl;
+ std::cout << "Testing tune helper TX automatic IF offset" << std::endl;
tune_result_t tr = tune_tx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 0, 2.3451e9);
std::cout << tr.to_pp_string() << std::endl;
BOOST_CHECK_CLOSE(tr.actual_inter_freq, 2.345e9, tolerance);
@@ -178,3 +224,30 @@ BOOST_AUTO_TEST_CASE(test_tune_helper_rx_nyquist){
double freq_derived = derive_freq_from_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 0);
BOOST_CHECK_CLOSE(freq_derived, -45e6, tolerance);
}
+
+BOOST_AUTO_TEST_CASE(test_tune_helper_rx_lo_off){
+ dummy_subdev_bw subdev;
+ dummy_dsp dsp(100e6);
+ tune_result_t tr;
+
+ std::cout << "Testing tune helper RX automatic LO offset B >> fs" << std::endl;
+ subdev[SUBDEV_PROP_BANDWIDTH] = double(40e6);
+ dsp[DSP_PROP_HOST_RATE] = double(4e6);
+ tr = tune_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 0, 2.45e9);
+ std::cout << tr.to_pp_string() << std::endl;
+ BOOST_CHECK_CLOSE(tr.actual_inter_freq, 2.45e9+4e6/2, tolerance);
+
+ std::cout << "Testing tune helper RX automatic LO offset B > fs" << std::endl;
+ subdev[SUBDEV_PROP_BANDWIDTH] = double(40e6);
+ dsp[DSP_PROP_HOST_RATE] = double(25e6);
+ tr = tune_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 0, 2.45e9);
+ std::cout << tr.to_pp_string() << std::endl;
+ BOOST_CHECK_CLOSE(tr.actual_inter_freq, 2.45e9+(40e6-25e6)/2, tolerance);
+
+ std::cout << "Testing tune helper RX automatic LO offset B < fs" << std::endl;
+ subdev[SUBDEV_PROP_BANDWIDTH] = double(20e6);
+ dsp[DSP_PROP_HOST_RATE] = double(25e6);
+ tr = tune_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 0, 2.45e9);
+ std::cout << tr.to_pp_string() << std::endl;
+ BOOST_CHECK_CLOSE(tr.actual_inter_freq, 2.45e9, tolerance);
+}
diff --git a/host/test/warning_test.cpp b/host/test/warning_test.cpp
index 6202c4270..db19955de 100644
--- a/host/test/warning_test.cpp
+++ b/host/test/warning_test.cpp
@@ -19,9 +19,9 @@
#include <uhd/utils/warning.hpp>
#include <iostream>
-BOOST_AUTO_TEST_CASE(test_print_warning){
+BOOST_AUTO_TEST_CASE(test_warning_post){
std::cerr << "---begin print test ---" << std::endl;
- uhd::print_warning(
+ uhd::warning::post(
"This is a test print for a warning message.\n"
"And this is the second line of the test print.\n"
);
diff --git a/images/Makefile b/images/Makefile
index 57277e787..a2e3d945b 100644
--- a/images/Makefile
+++ b/images/Makefile
@@ -119,6 +119,7 @@ $(BUILT_IMAGES_DIR):
mkdir $@
images: $(BUILT_IMAGES_DIR) $(IMAGES_LIST)
+ chmod -x $(BUILT_IMAGES_DIR)/*
clean:
$(RM) -rf $(BUILT_IMAGES_DIR)