diff options
23 files changed, 367 insertions, 106 deletions
diff --git a/firmware/microblaze/apps/txrx_uhd.c b/firmware/microblaze/apps/txrx_uhd.c index 7ad4ab110..45e5ff5fe 100644 --- a/firmware/microblaze/apps/txrx_uhd.c +++ b/firmware/microblaze/apps/txrx_uhd.c @@ -100,7 +100,7 @@ typedef struct{  #define MK_RX_CTRL_WORD(num_words) (((num_words)*sizeof(uint32_t)) | (1 << 16))  // DSP Rx writes ethernet header words -#define DSP_RX_FIRST_LINE 1 //1 = number of control words (see above) +#define DSP_RX_FIRST_LINE ((offsetof(rx_dsp_buff_t, vrt_header))/sizeof(uint32_t))  // receive from DSP  buf_cmd_args_t dsp_rx_recv_args = { @@ -423,7 +423,7 @@ fw_sets_seqno_inspector(dbsm_t *sm, int buf_this)	// returns false  {    // insert the correct length into the control word and vrt header    rx_dsp_buff_t *buff = (rx_dsp_buff_t*)buffer_ram(buf_this); -  size_t vrt_len = buffer_pool_status->last_line[buf_this]-1; +  size_t vrt_len = buffer_pool_status->last_line[buf_this]-DSP_RX_FIRST_LINE;    buff->control_word = MK_RX_CTRL_WORD(vrt_len);    buff->vrt_header[0] = (buff->vrt_header[0] & ~VRTH_PKT_SIZE_MASK) | (vrt_len & VRTH_PKT_SIZE_MASK); diff --git a/host/docs/general.rst b/host/docs/general.rst index 7d1f467a0..6b309cba0 100644 --- a/host/docs/general.rst +++ b/host/docs/general.rst @@ -58,14 +58,12 @@ Misc notes  ------------------------------------------------------------------------  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Process scheduling +Thread priority scheduling  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -The UHD will try to automatically boost the process's scheduling priority. -Currently, this is only supported on platforms with *sched.h*. - +When the UHD spawns a new thread it may try to boost the thread's scheduling priority.  When setting the priority fails, the UHD prints out an error. -This error is harmless, it simply means that your process will have a normal scheduling priority. +This error is harmless, it simply means that the thread will have a normal scheduling priority.  **Linux Notes:** diff --git a/host/examples/rx_timed_samples.cpp b/host/examples/rx_timed_samples.cpp index 64da260d5..6920b34d1 100644 --- a/host/examples/rx_timed_samples.cpp +++ b/host/examples/rx_timed_samples.cpp @@ -15,6 +15,7 @@  // 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/simple_usrp.hpp>  #include <boost/program_options.hpp> @@ -25,6 +26,8 @@  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;      int seconds_in_future; diff --git a/host/examples/tx_timed_samples.cpp b/host/examples/tx_timed_samples.cpp index e9e0c785e..28fd2ee67 100644 --- a/host/examples/tx_timed_samples.cpp +++ b/host/examples/tx_timed_samples.cpp @@ -15,6 +15,7 @@  // 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/simple_usrp.hpp>  #include <boost/program_options.hpp> @@ -25,6 +26,8 @@  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;      int seconds_in_future; diff --git a/host/include/uhd/usrp/dboard_iface.hpp b/host/include/uhd/usrp/dboard_iface.hpp index 7ecfcd3c0..caf1e6ee6 100644 --- a/host/include/uhd/usrp/dboard_iface.hpp +++ b/host/include/uhd/usrp/dboard_iface.hpp @@ -22,6 +22,7 @@  #include <uhd/types/serial.hpp>  #include <boost/shared_ptr.hpp>  #include <boost/cstdint.hpp> +#include <vector>  namespace uhd{ namespace usrp{ @@ -35,13 +36,13 @@ class UHD_API dboard_iface{  public:      typedef boost::shared_ptr<dboard_iface> sptr; -    //tells the host which unit to use +    //! tells the host which unit to use      enum unit_t{          UNIT_RX = 'r',          UNIT_TX = 't'      }; -    //possible atr registers +    //! possible atr registers      enum atr_reg_t{          ATR_REG_IDLE        = 'i',          ATR_REG_TX_ONLY     = 't', @@ -49,6 +50,20 @@ public:          ATR_REG_FULL_DUPLEX = 'f'      }; +    //! aux dac selection enums (per unit) +    enum aux_dac_t{ +        AUX_DAC_A = 'a', +        AUX_DAC_B = 'b', +        AUX_DAC_C = 'c', +        AUX_DAC_D = 'd' +    }; + +    //! aux adc selection enums (per unit) +    enum aux_adc_t{ +        AUX_ADC_A = 'a', +        AUX_ADC_B = 'b' +    }; +      /*!       * Write to an aux dac.       * @@ -56,7 +71,7 @@ public:       * \param which_dac the dac index 0, 1, 2, 3...       * \param value the value in volts       */ -    virtual void write_aux_dac(unit_t unit, int which_dac, float value) = 0; +    virtual void write_aux_dac(unit_t unit, aux_dac_t which_dac, float value) = 0;      /*!       * Read from an aux adc. @@ -65,7 +80,7 @@ public:       * \param which_adc the adc index 0, 1, 2, 3...       * \return the value in volts       */ -    virtual float read_aux_adc(unit_t unit, int which_adc) = 0; +    virtual float read_aux_adc(unit_t unit, aux_adc_t which_adc) = 0;      /*!       * Set a daughterboard output pin control source. @@ -159,6 +174,14 @@ public:      ) = 0;      /*! +     * Set the rate of a dboard clock. +     * +     * \param unit which unit rx or tx +     * \param rate the clock rate in Hz +     */ +    virtual void set_clock_rate(unit_t unit, double rate) = 0; + +    /*!       * Get the rate of a dboard clock.       *       * \param unit which unit rx or tx @@ -167,6 +190,14 @@ public:      virtual double get_clock_rate(unit_t unit) = 0;      /*! +     * Get a list of possible rates for the dboard clock. +     * +     * \param unit which unit rx or tx +     * \return a list of clock rates in Hz +     */ +    virtual std::vector<double> get_clock_rates(unit_t unit) = 0; + +    /*!       * Enable or disable a dboard clock.       *       * \param unit which unit rx or tx diff --git a/host/include/uhd/utils/CMakeLists.txt b/host/include/uhd/utils/CMakeLists.txt index 3684fd6e7..c98eec639 100644 --- a/host/include/uhd/utils/CMakeLists.txt +++ b/host/include/uhd/utils/CMakeLists.txt @@ -25,5 +25,6 @@ INSTALL(FILES      props.hpp      safe_main.hpp      static.hpp +    thread_priority.hpp      DESTINATION ${INCLUDE_DIR}/uhd/utils  ) diff --git a/host/include/uhd/utils/thread_priority.hpp b/host/include/uhd/utils/thread_priority.hpp new file mode 100644 index 000000000..988fc3012 --- /dev/null +++ b/host/include/uhd/utils/thread_priority.hpp @@ -0,0 +1,58 @@ +// +// 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_UTILS_THREAD_PRIORITY_HPP +#define INCLUDED_UHD_UTILS_THREAD_PRIORITY_HPP + +#include <uhd/config.hpp> + +namespace uhd{ + +    static const float default_thread_priority = float(0.5); + +    /*! +     * Set the scheduling priority on the current thread. +     * +     * A new thread or calling process should make this call +     * with the defailts this to enable realtime scheduling. +     * +     * A priority of zero corresponds to normal priority. +     * Positive priority values are higher than normal. +     * Negative priority values are lower than normal. +     * +     * \param priority a value between -1 and 1 +     * \param realtime true to use realtime mode +     * \throw exception on set priority failure +     */ +    UHD_API void set_thread_priority( +        float priority = default_thread_priority, +        bool realtime = true +    ); + +    /*! +     * Set the scheduling priority on the current thread. +     * Same as set_thread_priority but does not throw on failure. +     * \return true on success, false on failure +     */ +    UHD_API bool set_thread_priority_safe( +        float priority = default_thread_priority, +        bool realtime = true +    ); + +} //namespace uhd + +#endif /* INCLUDED_UHD_UTILS_THREAD_PRIORITY_HPP */ diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt index 50787f6a2..d13c43bfb 100644 --- a/host/lib/CMakeLists.txt +++ b/host/lib/CMakeLists.txt @@ -76,17 +76,38 @@ INCLUDE(${CMAKE_CURRENT_SOURCE_DIR}/usrp/usrp2/CMakeLists.txt)  ########################################################################  # Setup defines for process scheduling  ######################################################################## -MESSAGE(STATUS "Configuring process scheduling...") +MESSAGE(STATUS "Configuring priority scheduling...") + +INCLUDE(CheckCXXSourceCompiles) +CHECK_CXX_SOURCE_COMPILES(" +    #include <pthread.h> +    int main(){ +        struct sched_param sp; +        pthread_setschedparam(pthread_self(), SCHED_RR, &sp); +        return 0; +    } +    " HAVE_PTHREAD_SETSCHEDPARAM +) -INCLUDE(CheckIncludeFileCXX) -CHECK_INCLUDE_FILE_CXX(sched.h HAVE_SCHED_H) +CHECK_CXX_SOURCE_COMPILES(" +    #include <windows.h> +    int main(){ +        SetThreadPriority(GetCurrentThread(), 0); +        SetPriorityClass(GetCurrentProcess(), 0); +        return 0; +    } +    " HAVE_WIN_SETTHREADPRIORITY +) -IF(HAVE_SCHED_H) -    MESSAGE(STATUS "  Process scheduling supported through sched_setscheduler.") -    ADD_DEFINITIONS(-DHAVE_SCHED_H) -ELSE(HAVE_SCHED_H) -    MESSAGE(STATUS "  Process scheduling not supported.") -ENDIF(HAVE_SCHED_H) +IF(HAVE_PTHREAD_SETSCHEDPARAM) +    MESSAGE(STATUS "  Priority scheduling supported through pthread_setschedparam.") +    ADD_DEFINITIONS(-DHAVE_PTHREAD_SETSCHEDPARAM) +ELSEIF(HAVE_WIN_SETTHREADPRIORITY) +    MESSAGE(STATUS "  Priority scheduling supported through windows SetThreadPriority.") +    ADD_DEFINITIONS(-DHAVE_WIN_SETTHREADPRIORITY) +ELSE(HAVE_PTHREAD_SETSCHEDPARAM) +    MESSAGE(STATUS "  Priority scheduling not supported.") +ENDIF(HAVE_PTHREAD_SETSCHEDPARAM)  ########################################################################  # Setup defines for module loading @@ -114,7 +135,7 @@ LIBUHD_APPEND_SOURCES(      ${CMAKE_CURRENT_SOURCE_DIR}/device.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/gain_handler.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/load_modules.cpp -    ${CMAKE_CURRENT_SOURCE_DIR}/sched.cpp +    ${CMAKE_CURRENT_SOURCE_DIR}/thread_priority.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/types.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/utils.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/wax.cpp diff --git a/host/lib/load_modules.cpp b/host/lib/load_modules.cpp index d6bfe1369..dbb8d0695 100644 --- a/host/lib/load_modules.cpp +++ b/host/lib/load_modules.cpp @@ -30,7 +30,7 @@ namespace fs = boost::filesystem;  /***********************************************************************   * Module Load Function   **********************************************************************/ -#ifdef HAVE_DLFCN_H +#if defined(HAVE_DLFCN_H)  #include <dlfcn.h>  static const std::string env_path_sep = ":"; @@ -42,7 +42,7 @@ static void load_module(const std::string &file_name){      }  } -#elif HAVE_WINDOWS_H +#elif defined(HAVE_WINDOWS_H)  #include <windows.h>  static const std::string env_path_sep = ";"; diff --git a/host/lib/sched.cpp b/host/lib/sched.cpp deleted file mode 100644 index 712014c9c..000000000 --- a/host/lib/sched.cpp +++ /dev/null @@ -1,45 +0,0 @@ -// -// 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/static.hpp> -#include <stdexcept> -#include <iostream> - -#ifdef HAVE_SCHED_H -#include <sched.h> - -/* - * # /etc/security/limits.conf -# -@usrp   -       rtprio  99 -*/ - -UHD_STATIC_BLOCK(setup_process_sched){ -    try{ -        int policy = SCHED_RR; -        int max_pri = sched_get_priority_max(policy); -        if (max_pri == -1) throw std::runtime_error("sched_get_priority_max with SCHED_RR failed"); -        sched_param sp; sp.sched_priority = max_pri; -        int ss_ret = sched_setscheduler(0, policy, &sp); -        if (ss_ret == -1) throw std::runtime_error("sched_setscheduler with SCHED_RR failed"); -    } -    catch(const std::exception &e){ -        std::cerr << "Process scheduling error: " << e.what() << std::endl; -    } -} - -#endif /* HAVE_SCHED_H */ diff --git a/host/lib/thread_priority.cpp b/host/lib/thread_priority.cpp new file mode 100644 index 000000000..30b184123 --- /dev/null +++ b/host/lib/thread_priority.cpp @@ -0,0 +1,98 @@ +// +// 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 <stdexcept> +#include <iostream> + +bool uhd::set_thread_priority_safe(float priority, bool realtime){ +    try{ +        set_thread_priority(priority, realtime); +        return true; +    }catch(const std::exception &e){ +        std::cerr << "set_thread_priority: " << e.what() << std::endl; +        return false; +    } +} + +static void check_priority_range(float priority){ +    if (priority > +1.0 or priority < -1.0) +        throw std::range_error("priority out of range [-1.0, +1.0]"); +} + +/*********************************************************************** + * Pthread API to set priority + **********************************************************************/ +#if defined(HAVE_PTHREAD_SETSCHEDPARAM) +    #include <pthread.h> + +    void uhd::set_thread_priority(float priority, bool realtime){ +        check_priority_range(priority); + +        //when realtime is not enabled, use sched other +        int policy = (realtime)? SCHED_RR : SCHED_OTHER; + +        //we cannot have below normal priority, set to zero +        if (priority < 0) priority = 0; + +        //get the priority bounds for the selected policy +        int min_pri = sched_get_priority_min(policy); +        int max_pri = sched_get_priority_max(policy); +        if (min_pri == -1 or max_pri == -1) throw std::runtime_error("error in sched_get_priority_min/max"); + +        //set the new priority and policy +        sched_param sp; +        sp.sched_priority = int(priority*(max_pri - min_pri)) + min_pri; +        int ret = pthread_setschedparam(pthread_self(), policy, &sp); +        if (ret == -1) throw std::runtime_error("error in pthread_setschedparam"); +    } + +/*********************************************************************** + * Windows API to set priority + **********************************************************************/ +#elif defined(HAVE_WIN_SETTHREADPRIORITY) +    #include <windows.h> + +    void uhd::set_thread_priority(float priority, bool realtime){ +        check_priority_range(priority); + +        //set the priority class on the process +        int pri_class = (realtime)? REALTIME_PRIORITY_CLASS : NORMAL_PRIORITY_CLASS; +        if (SetPriorityClass(GetCurrentProcess(), pri_class) == 0) +            throw std::runtime_error("error in SetPriorityClass"); + +        //scale the priority value to the constants +        int priorities[] = { +            THREAD_PRIORITY_IDLE, THREAD_PRIORITY_LOWEST, THREAD_PRIORITY_BELOW_NORMAL, THREAD_PRIORITY_NORMAL, +            THREAD_PRIORITY_ABOVE_NORMAL, THREAD_PRIORITY_HIGHEST, THREAD_PRIORITY_TIME_CRITICAL +        }; +        size_t pri_index = size_t((priority+1.0)*6/2.0); // -1 -> 0, +1 -> 6 + +        //set the thread priority on the thread +        if (SetThreadPriority(GetCurrentThread(), priorities[pri_index]) == 0) +            throw std::runtime_error("error in SetThreadPriority"); +    } + +/*********************************************************************** + * Unimplemented API to set priority + **********************************************************************/ +#else +    void uhd::set_thread_priority(float, bool){ +        throw std::runtime_error("set thread priority not implemented"); +    } + +#endif /* HAVE_PTHREAD_SETSCHEDPARAM */ diff --git a/host/lib/transport/if_addrs.cpp b/host/lib/transport/if_addrs.cpp index 5c8c8a176..ad9a2325b 100644 --- a/host/lib/transport/if_addrs.cpp +++ b/host/lib/transport/if_addrs.cpp @@ -27,7 +27,7 @@ uhd::transport::if_addrs_t::if_addrs_t(void){  /***********************************************************************   * Interface address discovery through ifaddrs api   **********************************************************************/ -#ifdef HAVE_IFADDRS_H +#if defined(HAVE_IFADDRS_H)  #include <ifaddrs.h>  static boost::asio::ip::address_v4 sockaddr_to_ip_addr(sockaddr *addr){ @@ -59,9 +59,9 @@ std::vector<uhd::transport::if_addrs_t> uhd::transport::get_if_addrs(void){  }  /*********************************************************************** - * Interface address discovery through windows api (TODO) + * Interface address discovery through windows api   **********************************************************************/ -#elif HAVE_WINSOCK2_H +#elif defined(HAVE_WINSOCK2_H)  #include <winsock2.h>  std::vector<uhd::transport::if_addrs_t> uhd::transport::get_if_addrs(void){ diff --git a/host/lib/usrp/dboard/db_rfx.cpp b/host/lib/usrp/dboard/db_rfx.cpp index 2585dfa8d..7f2275b07 100644 --- a/host/lib/usrp/dboard/db_rfx.cpp +++ b/host/lib/usrp/dboard/db_rfx.cpp @@ -257,7 +257,7 @@ void rfx_xcvr::set_rx_gain(float gain, const std::string &name){          _rx_gains[name] = gain;          //write the new voltage to the aux dac -        this->get_iface()->write_aux_dac(dboard_iface::UNIT_RX, 0, dac_volts); +        this->get_iface()->write_aux_dac(dboard_iface::UNIT_RX, dboard_iface::AUX_DAC_A, dac_volts);      }      else UHD_THROW_INVALID_CODE_PATH();  } diff --git a/host/lib/usrp/dboard/db_wbx.cpp b/host/lib/usrp/dboard/db_wbx.cpp index 95dcb3802..aa5daf9a3 100644 --- a/host/lib/usrp/dboard/db_wbx.cpp +++ b/host/lib/usrp/dboard/db_wbx.cpp @@ -246,7 +246,7 @@ void wbx_xcvr::set_tx_gain(float gain, const std::string &name){          _tx_gains[name] = gain;          //write the new voltage to the aux dac -        this->get_iface()->write_aux_dac(dboard_iface::UNIT_TX, 0, dac_volts); +        this->get_iface()->write_aux_dac(dboard_iface::UNIT_TX, dboard_iface::AUX_DAC_A, dac_volts);      }      else UHD_THROW_INVALID_CODE_PATH();  } diff --git a/host/lib/usrp/dboard/db_xcvr2450.cpp b/host/lib/usrp/dboard/db_xcvr2450.cpp index 974a378bd..d83781965 100644 --- a/host/lib/usrp/dboard/db_xcvr2450.cpp +++ b/host/lib/usrp/dboard/db_xcvr2450.cpp @@ -144,7 +144,7 @@ private:          static const float min_v = float(0.5), max_v = float(2.5);          static const float rssi_dyn_range = 60;          //calculate the rssi from the voltage -        float voltage = this->get_iface()->read_aux_adc(dboard_iface::UNIT_RX, 1); +        float voltage = this->get_iface()->read_aux_adc(dboard_iface::UNIT_RX, dboard_iface::AUX_ADC_B);          return rssi_dyn_range*(voltage - min_v)/(max_v - min_v);      }  }; diff --git a/host/lib/usrp/usrp2/clock_ctrl.cpp b/host/lib/usrp/usrp2/clock_ctrl.cpp index d9baa66cf..59fac6fcf 100644 --- a/host/lib/usrp/usrp2/clock_ctrl.cpp +++ b/host/lib/usrp/usrp2/clock_ctrl.cpp @@ -18,6 +18,7 @@  #include "clock_ctrl.hpp"  #include "ad9510_regs.hpp"  #include "usrp2_regs.hpp" //spi slave constants +#include <uhd/utils/assert.hpp>  #include <boost/cstdint.hpp>  using namespace uhd; @@ -60,7 +61,9 @@ public:          this->enable_external_ref(false);          this->enable_rx_dboard_clock(false); +        this->set_rate_rx_dboard_clock(get_rates_rx_dboard_clock().at(0));          this->enable_tx_dboard_clock(false); +        this->set_rate_tx_dboard_clock(get_rates_tx_dboard_clock().at(0));          /* private clock enables, must be set here */          this->enable_dac_clock(true); @@ -79,23 +82,63 @@ public:          _ad9510_regs.power_down_lvds_cmos_out7 = enb? 0 : 1;          _ad9510_regs.lvds_cmos_select_out7 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT7_CMOS;          _ad9510_regs.output_level_lvds_out7 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT7_1_75MA; -        _ad9510_regs.bypass_divider_out7 = 1;          this->write_reg(0x43); +        this->update_regs(); +    } + +    void set_rate_rx_dboard_clock(double rate){ +        assert_has(get_rates_rx_dboard_clock(), rate, "rx dboard clock rate"); +        size_t divider = size_t(rate/get_master_clock_rate()); +        //bypass when the divider ratio is one +        _ad9510_regs.bypass_divider_out7 = (divider == 1)? 1 : 0; +        //calculate the low and high dividers +        size_t high = divider/2; +        size_t low = divider - high; +        //set the registers (divider - 1) +        _ad9510_regs.divider_low_cycles_out7 = low - 1; +        _ad9510_regs.divider_high_cycles_out7 = high - 1; +        //write the registers +        this->write_reg(0x56);          this->write_reg(0x57);          this->update_regs();      } +    std::vector<double> get_rates_rx_dboard_clock(void){ +        std::vector<double> rates; +        for (size_t i = 1; i <= 16+16; i++) rates.push_back(get_master_clock_rate()/i); +        return rates; +    } +      //uses output clock 6 (cmos)      void enable_tx_dboard_clock(bool enb){          _ad9510_regs.power_down_lvds_cmos_out6 = enb? 0 : 1;          _ad9510_regs.lvds_cmos_select_out6 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT6_CMOS;          _ad9510_regs.output_level_lvds_out6 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT6_1_75MA; -        _ad9510_regs.bypass_divider_out6 = 1;          this->write_reg(0x42); +        this->update_regs(); +    } + +    void set_rate_tx_dboard_clock(double rate){ +        assert_has(get_rates_tx_dboard_clock(), rate, "tx dboard clock rate"); +        size_t divider = size_t(rate/get_master_clock_rate()); +        //bypass when the divider ratio is one +        _ad9510_regs.bypass_divider_out6 = (divider == 1)? 1 : 0; +        //calculate the low and high dividers +        size_t high = divider/2; +        size_t low = divider - high; +        //set the registers (divider - 1) +        _ad9510_regs.divider_low_cycles_out6 = low - 1; +        _ad9510_regs.divider_high_cycles_out6 = high - 1; +        //write the registers +        this->write_reg(0x54);          this->write_reg(0x55);          this->update_regs();      } +    std::vector<double> get_rates_tx_dboard_clock(void){ +        return get_rates_rx_dboard_clock(); //same master clock, same dividers... +    } +      /*!       * If we are to use an external reference, enable the charge pump.       * \param enb true to enable the CP diff --git a/host/lib/usrp/usrp2/clock_ctrl.hpp b/host/lib/usrp/usrp2/clock_ctrl.hpp index 0ad8d9532..70a104a81 100644 --- a/host/lib/usrp/usrp2/clock_ctrl.hpp +++ b/host/lib/usrp/usrp2/clock_ctrl.hpp @@ -21,6 +21,7 @@  #include "usrp2_iface.hpp"  #include <boost/shared_ptr.hpp>  #include <boost/utility.hpp> +#include <vector>  class usrp2_clock_ctrl : boost::noncopyable{  public: @@ -46,12 +47,38 @@ public:      virtual void enable_rx_dboard_clock(bool enb) = 0;      /*! +     * Set the clock rate on the rx dboard clock. +     * \param rate the new clock rate +     * \throw exception when rate invalid +     */ +    virtual void set_rate_rx_dboard_clock(double rate) = 0; + +    /*! +     * Get a list of possible rx dboard clock rates. +     * \return a list of clock rates in Hz +     */ +    virtual std::vector<double> get_rates_rx_dboard_clock(void) = 0; + +    /*!       * Enable/disable the tx dboard clock.       * \param enb true to enable       */      virtual void enable_tx_dboard_clock(bool enb) = 0;      /*! +     * Set the clock rate on the tx dboard clock. +     * \param rate the new clock rate +     * \throw exception when rate invalid +     */ +    virtual void set_rate_tx_dboard_clock(double rate) = 0; + +    /*! +     * Get a list of possible tx dboard clock rates. +     * \return a list of clock rates in Hz +     */ +    virtual std::vector<double> get_rates_tx_dboard_clock(void) = 0; + +    /*!       * Enable/disable external reference.       * \param enb true to enable       */ diff --git a/host/lib/usrp/usrp2/dboard_iface.cpp b/host/lib/usrp/usrp2/dboard_iface.cpp index 114f83f41..ec6c98186 100644 --- a/host/lib/usrp/usrp2/dboard_iface.cpp +++ b/host/lib/usrp/usrp2/dboard_iface.cpp @@ -36,8 +36,8 @@ public:      usrp2_dboard_iface(usrp2_iface::sptr iface, usrp2_clock_ctrl::sptr clock_ctrl);      ~usrp2_dboard_iface(void); -    void write_aux_dac(unit_t, int, float); -    float read_aux_adc(unit_t, int); +    void write_aux_dac(unit_t, aux_dac_t, float); +    float read_aux_adc(unit_t, aux_adc_t);      void set_pin_ctrl(unit_t, boost::uint16_t);      void set_atr_reg(unit_t, atr_reg_t, boost::uint16_t); @@ -48,9 +48,10 @@ public:      void write_i2c(boost::uint8_t, const byte_vector_t &);      byte_vector_t read_i2c(boost::uint8_t, size_t); +    void set_clock_rate(unit_t, double);      double get_clock_rate(unit_t); +    std::vector<double> get_clock_rates(unit_t);      void set_clock_enabled(unit_t, bool); -    bool get_clock_enabled(unit_t);      void write_spi(          unit_t unit, @@ -73,6 +74,7 @@ private:      boost::uint32_t _gpio_shadow;      uhd::dict<unit_t, ad5623_regs_t> _dac_regs; +    uhd::dict<unit_t, double> _clock_rates;      void _write_aux_dac(unit_t);  }; @@ -116,8 +118,24 @@ usrp2_dboard_iface::~usrp2_dboard_iface(void){  /***********************************************************************   * Clocks   **********************************************************************/ -double usrp2_dboard_iface::get_clock_rate(unit_t){ -    return _clock_ctrl->get_master_clock_rate(); +void usrp2_dboard_iface::set_clock_rate(unit_t unit, double rate){ +    _clock_rates[unit] = rate; //set to shadow +    switch(unit){ +    case UNIT_RX: _clock_ctrl->set_rate_rx_dboard_clock(rate); return; +    case UNIT_TX: _clock_ctrl->set_rate_tx_dboard_clock(rate); return; +    } +} + +double usrp2_dboard_iface::get_clock_rate(unit_t unit){ +    return _clock_rates[unit]; //get from shadow +} + +std::vector<double> usrp2_dboard_iface::get_clock_rates(unit_t unit){ +    switch(unit){ +    case UNIT_RX: return _clock_ctrl->get_rates_rx_dboard_clock(); +    case UNIT_TX: return _clock_ctrl->get_rates_tx_dboard_clock(); +    default: UHD_THROW_INVALID_CODE_PATH(); +    }  }  void usrp2_dboard_iface::set_clock_enabled(unit_t unit, bool enb){ @@ -240,31 +258,30 @@ void usrp2_dboard_iface::_write_aux_dac(unit_t unit){      );  } -void usrp2_dboard_iface::write_aux_dac(unit_t unit, int which, float value){ +void usrp2_dboard_iface::write_aux_dac(unit_t unit, aux_dac_t which, float value){      _dac_regs[unit].data = boost::math::iround(4095*value/3.3);      _dac_regs[unit].cmd = ad5623_regs_t::CMD_WR_UP_DAC_CHAN_N; -    //standardize on USRP1 interface, A=0, B=1, C=2, D=3 -    static const uhd::dict< -        unit_t, uhd::dict<int, ad5623_regs_t::addr_t> -    > unit_to_which_to_addr = map_list_of + +    typedef uhd::dict<aux_dac_t, ad5623_regs_t::addr_t> aux_dac_to_addr; +    static const uhd::dict<unit_t, aux_dac_to_addr> unit_to_which_to_addr = map_list_of          (UNIT_RX, map_list_of -            (0, ad5623_regs_t::ADDR_DAC_B) -            (1, ad5623_regs_t::ADDR_DAC_A) -            (2, ad5623_regs_t::ADDR_DAC_A) -            (3, ad5623_regs_t::ADDR_DAC_B) +            (AUX_DAC_A, ad5623_regs_t::ADDR_DAC_B) +            (AUX_DAC_B, ad5623_regs_t::ADDR_DAC_A) +            (AUX_DAC_C, ad5623_regs_t::ADDR_DAC_A) +            (AUX_DAC_D, ad5623_regs_t::ADDR_DAC_B)          )          (UNIT_TX, map_list_of -            (0, ad5623_regs_t::ADDR_DAC_A) -            (1, ad5623_regs_t::ADDR_DAC_B) -            (2, ad5623_regs_t::ADDR_DAC_B) -            (3, ad5623_regs_t::ADDR_DAC_A) +            (AUX_DAC_A, ad5623_regs_t::ADDR_DAC_A) +            (AUX_DAC_B, ad5623_regs_t::ADDR_DAC_B) +            (AUX_DAC_C, ad5623_regs_t::ADDR_DAC_B) +            (AUX_DAC_D, ad5623_regs_t::ADDR_DAC_A)          )      ;      _dac_regs[unit].addr = unit_to_which_to_addr[unit][which];      this->_write_aux_dac(unit);  } -float usrp2_dboard_iface::read_aux_adc(unit_t unit, int which){ +float usrp2_dboard_iface::read_aux_adc(unit_t unit, aux_adc_t which){      static const uhd::dict<unit_t, int> unit_to_spi_adc = map_list_of          (UNIT_RX, SPI_SS_RX_ADC)          (UNIT_TX, SPI_SS_TX_ADC) @@ -277,8 +294,10 @@ float usrp2_dboard_iface::read_aux_adc(unit_t unit, int which){      //setup the spi registers      ad7922_regs_t ad7922_regs; -    ad7922_regs.mod = which; //normal mode: mod == chn -    ad7922_regs.chn = which; +    switch(which){ +    case AUX_ADC_A: ad7922_regs.mod = 0; break; +    case AUX_ADC_B: ad7922_regs.mod = 1; break; +    } ad7922_regs.chn = ad7922_regs.mod; //normal mode: mod == chn      //write and read spi      _iface->transact_spi( diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h index 75f5b1779..242d268ec 100644 --- a/host/lib/usrp/usrp2/fw_common.h +++ b/host/lib/usrp/usrp2/fw_common.h @@ -32,9 +32,13 @@ extern "C" {  #define _SINS_  #endif +// define limits on bytes per udp packet +#define USRP2_MTU_BYTES 1500 +#define USRP2_UDP_BYTES ((USRP2_MTU_BYTES) - (2 + 14 + 20 + 8)) //size of headers (pad, eth, ip, udp) +  //defines the protocol version in this shared header  //increment this value when the protocol is changed -#define USRP2_PROTO_VERSION 3 +#define USRP2_PROTO_VERSION 4  //used to differentiate control packets over data port  #define USRP2_INVALID_VRT_HEADER 0 @@ -102,7 +106,7 @@ typedef struct{          struct {              _SINS_ uint8_t addr;              _SINS_ uint8_t bytes; -            _SINS_ uint8_t data[sizeof(_SINS_ uint32_t)]; +            _SINS_ uint8_t data[20];          } i2c_args;          struct {              _SINS_ uint32_t addr; diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index 6cb2a735b..aa0f63321 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -18,6 +18,7 @@  #include "../../transport/vrt_packet_handler.hpp"  #include "usrp2_impl.hpp"  #include "usrp2_regs.hpp" +#include <uhd/utils/thread_priority.hpp>  #include <uhd/transport/convert_types.hpp>  #include <uhd/transport/bounded_buffer.hpp>  #include <boost/format.hpp> @@ -78,6 +79,7 @@ managed_recv_buffer::sptr usrp2_impl::io_impl::get_recv_buff(void){  }  void usrp2_impl::io_impl::recv_pirate_loop(zero_copy_if::sptr zc_if){ +    set_thread_priority_safe();      recv_pirate_running = true;      while(recv_pirate_running){          managed_recv_buffer::sptr buff = zc_if->get_recv_buff(); diff --git a/host/lib/usrp/usrp2/usrp2_iface.cpp b/host/lib/usrp/usrp2/usrp2_iface.cpp index 6e0d3266a..83e98904e 100644 --- a/host/lib/usrp/usrp2/usrp2_iface.cpp +++ b/host/lib/usrp/usrp2/usrp2_iface.cpp @@ -146,7 +146,7 @@ public:          _ctrl_transport->send(boost::asio::buffer(&out_copy, sizeof(usrp2_ctrl_data_t)));          //loop until we get the packet or timeout -        boost::uint8_t usrp2_ctrl_data_in_mem[1500]; //allocate MTU bytes for recv +        boost::uint8_t usrp2_ctrl_data_in_mem[USRP2_UDP_BYTES]; //allocate max bytes for recv          usrp2_ctrl_data_t *ctrl_data_in = reinterpret_cast<usrp2_ctrl_data_t *>(usrp2_ctrl_data_in_mem);          while(true){              size_t len = _ctrl_transport->recv(boost::asio::buffer(usrp2_ctrl_data_in_mem)); diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index 0837f4ac4..36c264c3c 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -79,12 +79,12 @@ uhd::device_addrs_t usrp2::find(const device_addr_t &hint){      udp_transport->send(boost::asio::buffer(&ctrl_data_out, sizeof(ctrl_data_out)));      //loop and recieve until the timeout -    boost::uint8_t usrp2_ctrl_data_in_mem[1500]; //allocate MTU bytes for recv +    boost::uint8_t usrp2_ctrl_data_in_mem[USRP2_UDP_BYTES]; //allocate max bytes for recv      usrp2_ctrl_data_t *ctrl_data_in = reinterpret_cast<usrp2_ctrl_data_t *>(usrp2_ctrl_data_in_mem);      while(true){          size_t len = udp_transport->recv(asio::buffer(usrp2_ctrl_data_in_mem));          //std::cout << len << "\n"; -        if (len >= sizeof(usrp2_ctrl_data_t)){ +        if (len > offsetof(usrp2_ctrl_data_t, data)){              //handle the received data              switch(ntohl(ctrl_data_in->id)){              case USRP2_CTRL_ID_WAZZUP_DUDE: diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index ccc09003e..2126b9565 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -141,15 +141,13 @@ private:      /*******************************************************************       * Deal with the rx and tx packet sizes       ******************************************************************/ -    static const size_t _mtu = 1500; //FIXME we have no idea -    static const size_t _hdrs = (2 + 14 + 20 + 8); //size of headers (pad, eth, ip, udp)      static const size_t _max_rx_bytes_per_packet = -        _mtu - _hdrs - +        USRP2_UDP_BYTES -          USRP2_HOST_RX_VRT_HEADER_WORDS32*sizeof(boost::uint32_t) -          USRP2_HOST_RX_VRT_TRAILER_WORDS32*sizeof(boost::uint32_t)      ;      static const size_t _max_tx_bytes_per_packet = -        _mtu - _hdrs - +        USRP2_UDP_BYTES -          uhd::transport::vrt::max_header_words32*sizeof(boost::uint32_t)      ;  | 
