diff options
53 files changed, 1759 insertions, 499 deletions
| diff --git a/firmware/microblaze/apps/txrx_uhd.c b/firmware/microblaze/apps/txrx_uhd.c index dd43059a3..b7837f207 100644 --- a/firmware/microblaze/apps/txrx_uhd.c +++ b/firmware/microblaze/apps/txrx_uhd.c @@ -422,6 +422,7 @@ link_changed_callback(int speed)    link_is_up = speed != 0;    hal_set_leds(link_is_up ? LED_RJ45 : 0x0, LED_RJ45);    printf("\neth link changed: speed = %d\n", speed); +  if (link_is_up) send_gratuitous_arp();  }  static void setup_network(void){ @@ -479,15 +480,18 @@ main(void)    printf("FPGA compatibility number: %d\n", USRP2_FPGA_COMPAT_NUM);    printf("Firmware compatibility number: %d\n", USRP2_FW_COMPAT_NUM); -  ethernet_register_link_changed_callback(link_changed_callback); -  ethernet_init(); - +  //1) register the addresses into the network stack    register_mac_addr(ethernet_mac_addr());    register_ip_addr(get_ip_addr()); +  //2) register callbacks for udp ports we service    register_udp_listener(USRP2_UDP_CTRL_PORT, handle_udp_ctrl_packet);    register_udp_listener(USRP2_UDP_DATA_PORT, handle_udp_data_packet); +  //3) setup ethernet hardware to bring the link up +  ethernet_register_link_changed_callback(link_changed_callback); +  ethernet_init(); +    // initialize double buffering state machine for ethernet -> DSP Tx    dbsm_init(&dsp_tx_sm, DSP_TX_BUF_0, diff --git a/firmware/microblaze/lib/Makefile.inc b/firmware/microblaze/lib/Makefile.inc index a576d1ccb..2b5685d3f 100644 --- a/firmware/microblaze/lib/Makefile.inc +++ b/firmware/microblaze/lib/Makefile.inc @@ -26,6 +26,7 @@ COMMON_SRCS = \  	$(top_srcdir)/lib/clocks.c \  	$(top_srcdir)/lib/dbsm.c \  	$(top_srcdir)/lib/eeprom.c \ +	$(top_srcdir)/lib/eth_addrs.c \  	$(top_srcdir)/lib/eth_mac.c \  	$(top_srcdir)/lib/_exit.c \  	$(top_srcdir)/lib/exit.c \ diff --git a/firmware/microblaze/lib/eth_addrs.c b/firmware/microblaze/lib/eth_addrs.c new file mode 100644 index 000000000..d7c1e0394 --- /dev/null +++ b/firmware/microblaze/lib/eth_addrs.c @@ -0,0 +1,119 @@ +/* + * Copyright 2010 Ettus Research LLC + * Copyright 2007 Free Software Foundation, Inc. + * + * 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 "ethernet.h" +#include "memory_map.h" +#include "nonstdio.h" +#include <stdbool.h> +#include "i2c.h" +#include "usrp2/fw_common.h" + +static bool +unprogrammed(const void *t, size_t len) +{ +  int i; +  uint8_t *p = (uint8_t *)t; +  bool all_zeros = true; +  bool all_ones =  true; +  for (i = 0; i < len; i++){ +    all_zeros &= p[i] == 0x00; +    all_ones  &= p[i] == 0xff; +  } +  return all_ones | all_zeros; +} + +//////////////////// MAC Addr Stuff /////////////////////// + +static int8_t src_mac_addr_initialized = false; +static eth_mac_addr_t src_mac_addr = {{ +    0x00, 0x50, 0xC2, 0x85, 0x3f, 0xff +  }}; + +const eth_mac_addr_t * +ethernet_mac_addr(void) +{ +  if (!src_mac_addr_initialized){    // fetch from eeprom +    src_mac_addr_initialized = true; + +    // if we're simulating, don't read the EEPROM model, it's REALLY slow +    if (hwconfig_simulation_p()) +      return &src_mac_addr; + +    eth_mac_addr_t tmp; +    bool ok = eeprom_read(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_MAC_ADDR, &tmp, sizeof(tmp)); +    if (!ok || unprogrammed(&tmp, sizeof(tmp))){ +      // use the default +    } +    else +      src_mac_addr = tmp; +  } + +  return &src_mac_addr; +} + +bool +ethernet_set_mac_addr(const eth_mac_addr_t *t) +{ +  bool ok = eeprom_write(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_MAC_ADDR, t, sizeof(eth_mac_addr_t)); +  if (ok){ +    src_mac_addr = *t; +    src_mac_addr_initialized = true; +    //eth_mac_set_addr(t); //this breaks the link +  } + +  return ok; +} + +//////////////////// IP Addr Stuff /////////////////////// + +static int8_t src_ip_addr_initialized = false; +static struct ip_addr src_ip_addr = { +    (192 << 24 | 168 << 16 | 10 << 8 | 2 << 0) +}; + + +const struct ip_addr *get_ip_addr(void) +{ +  if (!src_ip_addr_initialized){    // fetch from eeprom +    src_ip_addr_initialized = true; + +    // if we're simulating, don't read the EEPROM model, it's REALLY slow +    if (hwconfig_simulation_p()) +      return &src_ip_addr; + +    struct ip_addr tmp; +    bool ok = eeprom_read(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_IP_ADDR, &tmp, sizeof(tmp)); +    if (!ok || unprogrammed(&tmp, sizeof(tmp))){ +      // use the default +    } +    else +      src_ip_addr = tmp; +  } + +  return &src_ip_addr; +} + +bool set_ip_addr(const struct ip_addr *t){ +  bool ok = eeprom_write(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_IP_ADDR, t, sizeof(struct ip_addr)); +  if (ok){ +    src_ip_addr = *t; +    src_ip_addr_initialized = true; +  } + +  return ok; +} diff --git a/firmware/microblaze/lib/net_common.c b/firmware/microblaze/lib/net_common.c index 6c9509c92..beaaa5948 100644 --- a/firmware/microblaze/lib/net_common.c +++ b/firmware/microblaze/lib/net_common.c @@ -351,6 +351,22 @@ send_arp_reply(struct arp_eth_ipv4 *req, eth_mac_addr_t our_mac)    send_pkt(t, ETHERTYPE_ARP, &reply, sizeof(reply), 0, 0, 0, 0);  } +void send_gratuitous_arp(void){ +  struct arp_eth_ipv4 req _AL4; +  req.ar_hrd = ARPHRD_ETHER; +  req.ar_pro = ETHERTYPE_IPV4; +  req.ar_hln = sizeof(eth_mac_addr_t); +  req.ar_pln = sizeof(struct ip_addr); +  req.ar_op = ARPOP_REQUEST; +  memcpy(req.ar_sha, ethernet_mac_addr(), sizeof(eth_mac_addr_t)); +  memcpy(req.ar_sip, get_ip_addr(),       sizeof(struct ip_addr)); +  memset(req.ar_tha, 0x00,                sizeof(eth_mac_addr_t)); +  memcpy(req.ar_tip, get_ip_addr(),       sizeof(struct ip_addr)); + +  //send the request with a broadcast ethernet mac address +  eth_mac_addr_t t; memset(&t, 0xff, sizeof(t)); +  send_pkt(t, ETHERTYPE_ARP, &req, sizeof(req), 0, 0, 0, 0); +}  static void  handle_arp_packet(struct arp_eth_ipv4 *p, size_t size) diff --git a/firmware/microblaze/lib/net_common.h b/firmware/microblaze/lib/net_common.h index 112669b46..3040e5ef3 100644 --- a/firmware/microblaze/lib/net_common.h +++ b/firmware/microblaze/lib/net_common.h @@ -47,4 +47,6 @@ void send_udp_pkt(int src_port, struct socket_address dst,  void handle_eth_packet(uint32_t *p, size_t nlines); +void send_gratuitous_arp(void); +  #endif /* INCLUDED_NET_COMMON_H */ diff --git a/firmware/microblaze/usrp2/Makefile.am b/firmware/microblaze/usrp2/Makefile.am index 8da013980..ba426b75c 100644 --- a/firmware/microblaze/usrp2/Makefile.am +++ b/firmware/microblaze/usrp2/Makefile.am @@ -22,10 +22,11 @@ AM_CFLAGS = \  AM_LDFLAGS = \  	$(COMMON_LFLAGS) \ -	libusrp2.a \  	-Wl,-defsym -Wl,_TEXT_START_ADDR=0x0050 \  	-Wl,-defsym -Wl,_STACK_SIZE=3072 +LDADD = libusrp2.a +  ########################################################################  # USRP2 specific library and programs  ######################################################################## diff --git a/firmware/microblaze/usrp2/ethernet.c b/firmware/microblaze/usrp2/ethernet.c index d60d7dc4c..5d4654bda 100644 --- a/firmware/microblaze/usrp2/ethernet.c +++ b/firmware/microblaze/usrp2/ethernet.c @@ -16,16 +16,12 @@   */  #include "ethernet.h" -#include "memory_map.h"  #include "eth_phy.h"  #include "eth_mac.h"  #include "eth_mac_regs.h"  #include "pic.h"  #include "hal_io.h"  #include "nonstdio.h" -#include <stdbool.h> -#include "i2c.h" -#include "usrp2/fw_common.h"  #define VERBOSE 1 @@ -269,101 +265,6 @@ ethernet_init(void)    eth_mac_miim_write(PHY_CTRL, t | MII_CR_RESTART_AUTO_NEG);  } -static bool  -unprogrammed(const void *t, size_t len) -{ -  int i; -  uint8_t *p = (uint8_t *)t; -  bool all_zeros = true; -  bool all_ones =  true; -  for (i = 0; i < len; i++){ -    all_zeros &= p[i] == 0x00; -    all_ones  &= p[i] == 0xff; -  } -  return all_ones | all_zeros; -} - -//////////////////// MAC Addr Stuff /////////////////////// - -static int8_t src_mac_addr_initialized = false; -static eth_mac_addr_t src_mac_addr = {{ -    0x00, 0x50, 0xC2, 0x85, 0x3f, 0xff -  }}; - -const eth_mac_addr_t * -ethernet_mac_addr(void) -{ -  if (!src_mac_addr_initialized){    // fetch from eeprom -    src_mac_addr_initialized = true; - -    // if we're simulating, don't read the EEPROM model, it's REALLY slow -    if (hwconfig_simulation_p()) -      return &src_mac_addr; -     -    eth_mac_addr_t tmp; -    bool ok = eeprom_read(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_MAC_ADDR, &tmp, sizeof(tmp)); -    if (!ok || unprogrammed(&tmp, sizeof(tmp))){ -      // use the default -    } -    else -      src_mac_addr = tmp; -  } - -  return &src_mac_addr; -} - -bool -ethernet_set_mac_addr(const eth_mac_addr_t *t) -{ -  bool ok = eeprom_write(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_MAC_ADDR, t, sizeof(eth_mac_addr_t)); -  if (ok){ -    src_mac_addr = *t; -    src_mac_addr_initialized = true; -    //eth_mac_set_addr(t); //this breaks the link -  } - -  return ok; -} - -//////////////////// IP Addr Stuff /////////////////////// - -static int8_t src_ip_addr_initialized = false; -static struct ip_addr src_ip_addr = { -    (192 << 24 | 168 << 16 | 10 << 8 | 2 << 0) -}; - - -const struct ip_addr *get_ip_addr(void) -{ -  if (!src_ip_addr_initialized){    // fetch from eeprom -    src_ip_addr_initialized = true; - -    // if we're simulating, don't read the EEPROM model, it's REALLY slow -    if (hwconfig_simulation_p()) -      return &src_ip_addr; -     -    struct ip_addr tmp; -    bool ok = eeprom_read(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_IP_ADDR, &tmp, sizeof(tmp)); -    if (!ok || unprogrammed(&tmp, sizeof(tmp))){ -      // use the default -    } -    else -      src_ip_addr = tmp; -  } - -  return &src_ip_addr; -} - -bool set_ip_addr(const struct ip_addr *t){ -  bool ok = eeprom_write(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_IP_ADDR, t, sizeof(struct ip_addr)); -  if (ok){ -    src_ip_addr = *t; -    src_ip_addr_initialized = true; -  } - -  return ok; -} -  int  ethernet_check_errors(void)  { 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>(&l)->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) | 
