diff options
Diffstat (limited to 'host')
| -rw-r--r-- | host/apps/discover_usrps.cpp | 2 | ||||
| -rw-r--r-- | host/include/uhd/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | host/include/uhd/props.hpp | 20 | ||||
| -rw-r--r-- | host/include/uhd/simple_device.hpp | 111 | ||||
| -rw-r--r-- | host/include/uhd/time_spec.hpp | 19 | ||||
| -rw-r--r-- | host/include/uhd/utils.hpp | 105 | ||||
| -rw-r--r-- | host/lib/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | host/lib/simple_device.cpp | 303 | ||||
| -rw-r--r-- | host/lib/time_spec.cpp | 40 | ||||
| -rw-r--r-- | host/lib/usrp/usrp2/dboard_impl.cpp | 9 | ||||
| -rw-r--r-- | host/lib/usrp/usrp2/dsp_impl.cpp | 21 | ||||
| -rw-r--r-- | host/lib/usrp/usrp2/fw_common.h | 8 | ||||
| -rw-r--r-- | host/lib/usrp/usrp2/mboard_impl.cpp | 35 | ||||
| -rw-r--r-- | host/lib/usrp/usrp2/usrp2_impl.hpp | 1 | 
14 files changed, 581 insertions, 96 deletions
| diff --git a/host/apps/discover_usrps.cpp b/host/apps/discover_usrps.cpp index 448095726..d670d1651 100644 --- a/host/apps/discover_usrps.cpp +++ b/host/apps/discover_usrps.cpp @@ -63,7 +63,7 @@ int main(int argc, char *argv[]){          std::cout << "-- USRP Device " << i << std::endl;          std::cout << "--------------------------------------------------" << std::endl;          std::cout << device_addrs[i] << std::endl << std::endl; -        //uhd::device::make(device_addrs[i]); //test make +        uhd::device::make(device_addrs[i]); //test make      }      return 0; diff --git a/host/include/uhd/CMakeLists.txt b/host/include/uhd/CMakeLists.txt index f4fb96786..522f43afd 100644 --- a/host/include/uhd/CMakeLists.txt +++ b/host/include/uhd/CMakeLists.txt @@ -26,6 +26,7 @@ INSTALL(FILES      gain_handler.hpp      metadata.hpp      props.hpp +    simple_device.hpp      time_spec.hpp      utils.hpp      wax.hpp diff --git a/host/include/uhd/props.hpp b/host/include/uhd/props.hpp index cf301d4bd..dea2baf52 100644 --- a/host/include/uhd/props.hpp +++ b/host/include/uhd/props.hpp @@ -116,16 +116,16 @@ namespace uhd{      enum dboard_prop_t{          DBOARD_PROP_NAME,              //ro, std::string          DBOARD_PROP_SUBDEV,            //ro, wax::obj -        DBOARD_PROP_SUBDEV_NAMES,      //ro, prop_names_t -        DBOARD_PROP_CODEC              //ro, wax::obj -    }; +        DBOARD_PROP_SUBDEV_NAMES       //ro, prop_names_t +        //DBOARD_PROP_CODEC              //ro, wax::obj //----> not sure, dont have to deal with yet +    };  -    /*! +    /*! ------ not dealing with yet, commented out ------------      * Possible device codec properties:      *   A codec is expected to have a rate and gain elements.      *   Other properties can be discovered through the others prop.      */ -    enum codec_prop_t{ +    /*enum codec_prop_t{          CODEC_PROP_NAME,               //ro, std::string          CODEC_PROP_OTHERS,             //ro, prop_names_t          CODEC_PROP_GAIN,               //rw, gain_t @@ -133,8 +133,8 @@ namespace uhd{          CODEC_PROP_GAIN_MIN,           //ro, gain_t          CODEC_PROP_GAIN_STEP,          //ro, gain_t          CODEC_PROP_GAIN_NAMES,         //ro, prop_names_t -        CODEC_PROP_CLOCK_RATE          //ro, freq_t -    }; +        //CODEC_PROP_CLOCK_RATE          //ro, freq_t //----> not sure we care to know +    };*/      /*!      * Possible device subdev properties @@ -156,9 +156,9 @@ namespace uhd{          SUBDEV_PROP_QUADRATURE,        //ro, bool          SUBDEV_PROP_IQ_SWAPPED,        //ro, bool          SUBDEV_PROP_SPECTRUM_INVERTED, //ro, bool -        SUBDEV_PROP_IS_TX,             //ro, bool -        SUBDEV_PROP_RSSI,              //ro, gain_t -        SUBDEV_PROP_BANDWIDTH          //rw, freq_t +        SUBDEV_PROP_LO_INTERFERES      //ro, bool +        //SUBDEV_PROP_RSSI,              //ro, gain_t //----> not on all boards, use named prop +        //SUBDEV_PROP_BANDWIDTH          //rw, freq_t //----> not on all boards, use named prop      };  } //namespace uhd diff --git a/host/include/uhd/simple_device.hpp b/host/include/uhd/simple_device.hpp new file mode 100644 index 000000000..64ec85a5c --- /dev/null +++ b/host/include/uhd/simple_device.hpp @@ -0,0 +1,111 @@ +// +// 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 <boost/shared_ptr.hpp> +#include <boost/utility.hpp> +#include <uhd/device.hpp> +#include <vector> + +#ifndef INCLUDED_UHD_SIMPLE_DEVICE_HPP +#define INCLUDED_UHD_SIMPLE_DEVICE_HPP + +namespace uhd{ + +/*! + * The tune result struct holds result of a 2-phase tuning: + * The struct hold the result of tuning the dboard as + * the target and actual intermediate frequency. + * The struct hold the result of tuning the DDC/DUC as + * the target and actual digital converter frequency. + * It also tell us weather or not the spectrum is inverted. + */ +struct tune_result_t{ +    double target_inter_freq; +    double actual_inter_freq; +    double target_dxc_freq; +    double actual_dxc_freq; +    bool spectrum_inverted; +    tune_result_t(void); +}; + +/*! + * The simple UHD device class: + * A simple device facilitates ease-of-use for most use-case scenarios. + * The wrapper provides convenience functions to tune the devices + * as well as to set the dboard gains, antennas, and other properties. + */ +class simple_device : boost::noncopyable{ +public: +    typedef boost::shared_ptr<simple_device> sptr; +    static sptr make(const std::string &args); + +    virtual device::sptr get_device(void) = 0; + +    virtual std::string get_name(void) = 0; + +    /******************************************************************* +     * Streaming +     ******************************************************************/ +    virtual void set_streaming(bool enb) = 0; +    virtual bool get_streaming(void) = 0; + +    /******************************************************************* +     * RX methods +     ******************************************************************/ +    virtual void set_rx_rate(double rate) = 0; +    virtual double get_rx_rate(void) = 0; +    virtual std::vector<double> get_rx_rates(void) = 0; + +    virtual tune_result_t set_rx_freq(double target_freq, double lo_offset) = 0; +    virtual double get_rx_freq_min(void) = 0; +    virtual double get_rx_freq_max(void) = 0; + +    virtual void set_rx_gain(float gain) = 0; +    virtual float get_rx_gain(void) = 0; +    virtual float get_rx_gain_min(void) = 0; +    virtual float get_rx_gain_max(void) = 0; +    virtual float get_rx_gain_step(void) = 0; + +    virtual void set_rx_antenna(const std::string &ant) = 0; +    virtual std::string get_rx_antenna(void) = 0; +    virtual std::vector<std::string> get_rx_antennas(void) = 0; + +    /******************************************************************* +     * TX methods +     ******************************************************************/ +    virtual void set_tx_rate(double rate) = 0; +    virtual double get_tx_rate(void) = 0; +    virtual std::vector<double> get_tx_rates(void) = 0; + +    virtual tune_result_t set_tx_freq(double target_freq, double lo_offset) = 0; +    virtual double get_tx_freq_min(void) = 0; +    virtual double get_tx_freq_max(void) = 0; + +    virtual void set_tx_gain(float gain) = 0; +    virtual float get_tx_gain(void) = 0; +    virtual float get_tx_gain_min(void) = 0; +    virtual float get_tx_gain_max(void) = 0; +    virtual float get_tx_gain_step(void) = 0; + +    virtual void set_tx_antenna(const std::string &ant) = 0; +    virtual std::string get_tx_antenna(void) = 0; +    virtual std::vector<std::string> get_tx_antennas(void) = 0; +}; + +} //namespace uhd + +#endif /* INCLUDED_UHD_SIMPLE_DEVICE_HPP */ diff --git a/host/include/uhd/time_spec.hpp b/host/include/uhd/time_spec.hpp index e5657e555..7e182236b 100644 --- a/host/include/uhd/time_spec.hpp +++ b/host/include/uhd/time_spec.hpp @@ -15,6 +15,7 @@  // along with this program.  If not, see <http://www.gnu.org/licenses/>.  // +#include <boost/date_time/posix_time/posix_time.hpp>  #include <stdint.h>  #ifndef INCLUDED_UHD_TIME_SPEC_HPP @@ -36,20 +37,22 @@ namespace uhd{           * Create a time_spec_t that holds a wildcard time.           * This will have implementation-specific meaning.           */ -        time_spec_t(void){ -            secs = ~0; -            ticks = ~0; -        } +        time_spec_t(void);          /*!           * Create a time_spec_t from seconds and ticks.           * \param new_secs the new seconds           * \param new_ticks the new ticks (default = 0)           */ -        time_spec_t(uint32_t new_secs, uint32_t new_ticks = 0){ -            secs = new_secs; -            ticks = new_ticks; -        } +        time_spec_t(uint32_t new_secs, uint32_t new_ticks = 0); + +        /*! +         * Create a time_spec_t from boost posix time. +         * \param time fine-grained boost posix time +         * \param tick_rate the rate of ticks per second +         */ +        time_spec_t(boost::posix_time::ptime time, double tick_rate); +      };  } //namespace uhd diff --git a/host/include/uhd/utils.hpp b/host/include/uhd/utils.hpp index 9bbdc83c9..25a7b5abd 100644 --- a/host/include/uhd/utils.hpp +++ b/host/include/uhd/utils.hpp @@ -15,18 +15,14 @@  // along with this program.  If not, see <http://www.gnu.org/licenses/>.  // -#include <uhd/wax.hpp> -#include <boost/foreach.hpp> -#include <boost/format.hpp> -#include <boost/function.hpp> -#include <stdexcept> -#include <algorithm> -#include <vector> -#include <map> -  #ifndef INCLUDED_UHD_UTILS_HPP  #define INCLUDED_UHD_UTILS_HPP +#include <stdexcept> +#include <algorithm> +#include <boost/format.hpp> +#include <boost/current_function.hpp> +  /*!   * Useful templated functions and classes that I like to pretend are part of stl   */ @@ -40,7 +36,9 @@ namespace std{      };      #define ASSERT_THROW(_x) if (not (_x)) { \ -        throw std::assert_error("Assertion Failed: " + std::string(#_x)); \ +        throw std::assert_error(str(boost::format( \ +            "Assertion Failed:\n  %s:%d\n  %s\n  __/ %s __/" \ +        ) % __FILE__ % __LINE__ % BOOST_CURRENT_FUNCTION % std::string(#_x))); \      }      template<class T, class InputIterator, class Function> @@ -57,9 +55,9 @@ namespace std{          return last != std::find(first, last, elem);      } -    template<class T, class V> -    bool has(const V &vector, const T &elem){ -        return has(vector.begin(), vector.end(), elem); +    template<class T, class Iterable> +    bool has(const Iterable &iterable, const T &elem){ +        return has(iterable.begin(), iterable.end(), elem);      }      template<class T> @@ -75,52 +73,43 @@ namespace std{  }//namespace std -/*namespace uhd{ - -inline void tune( -    freq_t target_freq, -    freq_t lo_offset, -    wax::obj subdev_freq_proxy, -    bool subdev_quadrature, -    bool subdev_spectrum_inverted, -    bool subdev_is_tx, -    wax::obj dsp_freq_proxy, -    freq_t dsp_sample_rate -){ -    // Ask the d'board to tune as closely as it can to target_freq+lo_offset -    subdev_freq_proxy = target_freq + lo_offset; -    freq_t inter_freq = wax::cast<freq_t>(subdev_freq_proxy); - -    // Calculate the DDC setting that will downconvert the baseband from the -    // daughterboard to our target frequency. -    freq_t delta_freq = target_freq - inter_freq; -    freq_t delta_sign = std::signum(delta_freq); -    delta_freq *= delta_sign; -    delta_freq = fmod(delta_freq, dsp_sample_rate); -    bool inverted = delta_freq > dsp_sample_rate/2.0; -    freq_t dxc_freq = inverted? (delta_freq - dsp_sample_rate) : (-delta_freq); -    dxc_freq *= delta_sign; - -    // If the spectrum is inverted, and the daughterboard doesn't do -    // quadrature downconversion, we can fix the inversion by flipping the -    // sign of the dxc_freq...  (This only happens using the basic_rx board) -    if (subdev_spectrum_inverted){ -        inverted = not inverted; -    } -    if (inverted and not subdev_quadrature){ -        dxc_freq = -dxc_freq; -        inverted = not inverted; -    } -    if (subdev_is_tx){ -        dxc_freq = -dxc_freq;	// down conversion versus up conversion +#include <boost/format.hpp> +#include <boost/foreach.hpp> +#include <boost/lexical_cast.hpp> + +namespace uhd{ + +    /*! +     * Check that an element is found in a container. +     * If not, throw a meaningful assertion error. +     * The "what" in the error will show what is +     * being set and a list of known good values. +     * +     * \param iterable a list of possible settings +     * \param elem an element that may be in the list +     * \param what a description of what is being set +     * \throw assertion_error when elem not in list +     */ +    template<class T, class Iterable> void assert_has( +        const Iterable &iterable, +        const T &elem, +        const std::string &what = "unknown" +    ){ +        if (std::has(iterable, elem)) return; +        std::string possible_values = ""; +        BOOST_FOREACH(T e, iterable){ +            if (e != iterable.begin()[0]) possible_values += ", "; +            possible_values += boost::lexical_cast<std::string>(e); +        } +        throw std::assert_error(str(boost::format( +                "Error: %s is not a valid %s. " +                "Possible values are: [%s]." +            ) +            % boost::lexical_cast<std::string>(elem) +            % what % possible_values +        ));      } -    dsp_freq_proxy = dxc_freq; -    //freq_t actual_dxc_freq = wax::cast<freq_t>(dsp_freq_proxy); - -    //return some kind of tune result tuple/struct -} - -} //namespace uhd*/ +}//namespace uhd  #endif /* INCLUDED_UHD_UTILS_HPP */ diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt index b1daf22d1..b141d67bb 100644 --- a/host/lib/CMakeLists.txt +++ b/host/lib/CMakeLists.txt @@ -23,6 +23,8 @@ SET(libuhd_sources      device_addr.cpp      gain_handler.cpp      metadata.cpp +    simple_device.cpp +    time_spec.cpp      wax.cpp      transport/udp_simple.cpp      transport/vrt.cpp diff --git a/host/lib/simple_device.cpp b/host/lib/simple_device.cpp new file mode 100644 index 000000000..63a17c52d --- /dev/null +++ b/host/lib/simple_device.cpp @@ -0,0 +1,303 @@ +// +// 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/simple_device.hpp> +#include <uhd/device.hpp> +#include <uhd/utils.hpp> +#include <uhd/props.hpp> +#include <boost/algorithm/string.hpp> +#include <boost/algorithm/string/trim.hpp> +#include <boost/foreach.hpp> +#include <boost/format.hpp> +#include <stdexcept> + +using namespace uhd; + +tune_result_t::tune_result_t(void){ +    /* NOP */ +} + +/*********************************************************************** + * Tune Helper Function + **********************************************************************/ +static tune_result_t tune( +    double target_freq, +    double lo_offset, +    wax::obj subdev, +    wax::obj dxc, +    bool is_tx +){ +    wax::obj subdev_freq_proxy = subdev[SUBDEV_PROP_FREQ]; +    bool subdev_quadrature = wax::cast<bool>(subdev[SUBDEV_PROP_QUADRATURE]); +    bool subdev_spectrum_inverted = wax::cast<bool>(subdev[SUBDEV_PROP_SPECTRUM_INVERTED]); +    wax::obj dxc_freq_proxy = dxc[std::string("freq")]; +    double dxc_sample_rate = wax::cast<double>(dxc[std::string("rate")]); + +    // 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 = wax::cast<double>(subdev_freq_proxy); + +    // Calculate the DDC setting that will downconvert the baseband from the +    // daughterboard to our target frequency. +    double delta_freq = target_freq - actual_inter_freq; +    double delta_sign = std::signum(delta_freq); +    delta_freq *= delta_sign; +    delta_freq = fmod(delta_freq, dxc_sample_rate); +    bool inverted = delta_freq > dxc_sample_rate/2.0; +    double target_dxc_freq = inverted? (delta_freq - dxc_sample_rate) : (-delta_freq); +    target_dxc_freq *= delta_sign; + +    // If the spectrum is inverted, and the daughterboard doesn't do +    // quadrature downconversion, we can fix the inversion by flipping the +    // sign of the dxc_freq...  (This only happens using the basic_rx board) +    if (subdev_spectrum_inverted){ +        inverted = not inverted; +    } +    if (inverted and not subdev_quadrature){ +        target_dxc_freq *= -1.0; +        inverted = not inverted; +    } +    // down conversion versus up conversion, fight! +    // your mother is ugly and your going down... +    target_dxc_freq *= (is_tx)? -1.0 : +1.0; + +    dxc_freq_proxy = target_dxc_freq; +    double actual_dxc_freq = wax::cast<double>(dxc_freq_proxy); + +    //return some kind of tune result tuple/struct +    tune_result_t tune_result; +    tune_result.target_inter_freq = target_inter_freq; +    tune_result.actual_inter_freq = actual_inter_freq; +    tune_result.target_dxc_freq = target_dxc_freq; +    tune_result.actual_dxc_freq = actual_dxc_freq; +    tune_result.spectrum_inverted = inverted; +    return tune_result; +} + +/*********************************************************************** + * Helper Functions + **********************************************************************/ +static std::string trim(const std::string &in){ +    return boost::algorithm::trim_copy(in); +} + +device_addr_t args_to_device_addr(const std::string &args){ +    device_addr_t addr; + +    //split the args at the semi-colons +    std::vector<std::string> pairs; +    boost::split(pairs, args, boost::is_any_of(";")); +    BOOST_FOREACH(std::string pair, pairs){ +        if (trim(pair) == "") continue; + +        //split the key value pairs at the equals +        std::vector<std::string> key_val; +        boost::split(key_val, pair, boost::is_any_of("=")); +        if (key_val.size() != 2) throw std::runtime_error("invalid args string: "+args); +        addr[trim(key_val[0])] = trim(key_val[1]); +    } + +    return addr; +} + +static std::vector<double> get_xx_rates(wax::obj decerps, wax::obj rate){ +    std::vector<double> rates; +    BOOST_FOREACH(size_t decerp, wax::cast<std::vector<size_t> >(decerps)){ +        rates.push_back(wax::cast<double>(rate)/decerp); +    } +    return rates; +} + +/*********************************************************************** + * Simple Device Implementation + **********************************************************************/ +class simple_device_impl : public simple_device{ +public: +    simple_device_impl(const device_addr_t &addr){ +        _dev = device::make(addr); +        _mboard = (*_dev)[DEVICE_PROP_MBOARD]; +        _rx_ddc = _mboard[named_prop_t(MBOARD_PROP_RX_DSP, "ddc0")]; +        _tx_duc = _mboard[named_prop_t(MBOARD_PROP_TX_DSP, "duc0")]; +        _rx_subdev = _mboard[MBOARD_PROP_RX_DBOARD][DBOARD_PROP_SUBDEV]; +        _tx_subdev = _mboard[MBOARD_PROP_TX_DBOARD][DBOARD_PROP_SUBDEV]; +    } + +    ~simple_device_impl(void){ +        /* NOP */ +    } + +    device::sptr get_device(void){ +        return _dev; +    } + +    std::string get_name(void){ +        return wax::cast<std::string>(_mboard[MBOARD_PROP_NAME]); +    } + +    /******************************************************************* +     * Streaming +     ******************************************************************/ +    void set_streaming(bool enb){ +        _rx_ddc[std::string("enabled")] = enb; +    } + +    bool get_streaming(void){ +        return wax::cast<bool>(_rx_ddc[std::string("enabled")]); +    } + +    /******************************************************************* +     * RX methods +     ******************************************************************/ +    void set_rx_rate(double rate){ +        double samp_rate = wax::cast<double>(_rx_ddc[std::string("rate")]); +        assert_has(get_rx_rates(), rate, "simple device rx rate"); +        _rx_ddc[std::string("decim")] = size_t(samp_rate/rate); +    } + +    double get_rx_rate(void){ +        double samp_rate = wax::cast<double>(_rx_ddc[std::string("rate")]); +        size_t decim = wax::cast<size_t>(_rx_ddc[std::string("decim")]); +        return samp_rate/decim; +    } + +    std::vector<double> get_rx_rates(void){ +        return get_xx_rates(_rx_ddc[std::string("decims")], _rx_ddc[std::string("rate")]); +    } + +    tune_result_t set_rx_freq(double target_freq, double lo_offset){ +        return tune(target_freq, lo_offset, _rx_subdev, _rx_ddc, false/* not tx */); +    } + +    double get_rx_freq_min(void){ +        return wax::cast<double>(_rx_subdev[SUBDEV_PROP_FREQ_MIN]); +    } + +    double get_rx_freq_max(void){ +        return wax::cast<double>(_rx_subdev[SUBDEV_PROP_FREQ_MAX]); +    } + +    void set_rx_gain(float gain){ +        _rx_subdev[SUBDEV_PROP_GAIN] = gain; +    } + +    float get_rx_gain(void){ +        return wax::cast<float>(_rx_subdev[SUBDEV_PROP_GAIN]); +    } + +    float get_rx_gain_min(void){ +        return wax::cast<float>(_rx_subdev[SUBDEV_PROP_GAIN_MIN]); +    } + +    float get_rx_gain_max(void){ +        return wax::cast<float>(_rx_subdev[SUBDEV_PROP_GAIN_MAX]); +    } + +    float get_rx_gain_step(void){ +        return wax::cast<float>(_rx_subdev[SUBDEV_PROP_GAIN_STEP]); +    } + +    void set_rx_antenna(const std::string &ant){ +        _rx_subdev[SUBDEV_PROP_ANTENNA] = ant; +    } + +    std::string get_rx_antenna(void){ +        return wax::cast<std::string>(_rx_subdev[SUBDEV_PROP_ANTENNA]); +    } + +    std::vector<std::string> get_rx_antennas(void){ +        return wax::cast<std::vector<std::string> >(_rx_subdev[SUBDEV_PROP_ANTENNA_NAMES]); +    } + +    /******************************************************************* +     * TX methods +     ******************************************************************/ +    void set_tx_rate(double rate){ +        double samp_rate = wax::cast<double>(_tx_duc[std::string("rate")]); +        assert_has(get_tx_rates(), rate, "simple device tx rate"); +        _tx_duc[std::string("interp")] = size_t(samp_rate/rate); +    } + +    double get_tx_rate(void){ +        double samp_rate = wax::cast<double>(_tx_duc[std::string("rate")]); +        size_t interp = wax::cast<size_t>(_tx_duc[std::string("interp")]); +        return samp_rate/interp; +    } + +    std::vector<double> get_tx_rates(void){ +        return get_xx_rates(_tx_duc[std::string("interps")], _tx_duc[std::string("rate")]); +    } + +    tune_result_t set_tx_freq(double target_freq, double lo_offset){ +        return tune(target_freq, lo_offset, _tx_subdev, _tx_duc, true/* is tx */); +    } + +    double get_tx_freq_min(void){ +        return wax::cast<double>(_tx_subdev[SUBDEV_PROP_FREQ_MIN]); +    } + +    double get_tx_freq_max(void){ +        return wax::cast<double>(_tx_subdev[SUBDEV_PROP_FREQ_MAX]); +    } + +    void set_tx_gain(float gain){ +        _tx_subdev[SUBDEV_PROP_GAIN] = gain; +    } + +    float get_tx_gain(void){ +        return wax::cast<float>(_tx_subdev[SUBDEV_PROP_GAIN]); +    } + +    float get_tx_gain_min(void){ +        return wax::cast<float>(_tx_subdev[SUBDEV_PROP_GAIN_MIN]); +    } + +    float get_tx_gain_max(void){ +        return wax::cast<float>(_tx_subdev[SUBDEV_PROP_GAIN_MAX]); +    } + +    float get_tx_gain_step(void){ +        return wax::cast<float>(_tx_subdev[SUBDEV_PROP_GAIN_STEP]); +    } + +    void set_tx_antenna(const std::string &ant){ +        _tx_subdev[SUBDEV_PROP_ANTENNA] = ant; +    } + +    std::string get_tx_antenna(void){ +        return wax::cast<std::string>(_tx_subdev[SUBDEV_PROP_ANTENNA]); +    } + +    std::vector<std::string> get_tx_antennas(void){ +        return wax::cast<std::vector<std::string> >(_tx_subdev[SUBDEV_PROP_ANTENNA_NAMES]); +    } + +private: +    device::sptr _dev; +    wax::obj _mboard; +    wax::obj _rx_ddc; +    wax::obj _tx_duc; +    wax::obj _rx_subdev; +    wax::obj _tx_subdev; +}; + +/*********************************************************************** + * The Make Function + **********************************************************************/ +simple_device::sptr simple_device::make(const std::string &args){ +    return sptr(new simple_device_impl(args_to_device_addr(args))); +} diff --git a/host/lib/time_spec.cpp b/host/lib/time_spec.cpp new file mode 100644 index 000000000..193441342 --- /dev/null +++ b/host/lib/time_spec.cpp @@ -0,0 +1,40 @@ +// +// 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/time_spec.hpp> + +using namespace uhd; + +time_spec_t::time_spec_t(void){ +    secs = ~0; +    ticks = ~0; +} + +time_spec_t::time_spec_t(uint32_t new_secs, uint32_t new_ticks){ +    secs = new_secs; +    ticks = new_ticks; +} + +static const boost::posix_time::ptime epoch(boost::gregorian::date(1970,1,1)); +static double time_tick_rate(boost::posix_time::time_duration::ticks_per_second()); + +time_spec_t::time_spec_t(boost::posix_time::ptime time, double tick_rate){ +    boost::posix_time::time_duration td = time - epoch; +    secs = td.total_seconds(); +    double time_ticks_per_device_ticks = time_tick_rate/tick_rate; +    ticks = td.fractional_seconds()/time_ticks_per_device_ticks; +} diff --git a/host/lib/usrp/usrp2/dboard_impl.cpp b/host/lib/usrp/usrp2/dboard_impl.cpp index 32c64f541..da05c3241 100644 --- a/host/lib/usrp/usrp2/dboard_impl.cpp +++ b/host/lib/usrp/usrp2/dboard_impl.cpp @@ -16,6 +16,7 @@  //  #include <uhd/utils.hpp> +#include <boost/format.hpp>  #include "usrp2_impl.hpp"  #include "dboard_interface.hpp" @@ -83,8 +84,8 @@ void usrp2_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val){          val = _dboard_manager->get_rx_subdev_names();          return; -    case DBOARD_PROP_CODEC: -        throw std::runtime_error("unhandled prop in usrp2 dboard"); +    //case DBOARD_PROP_CODEC: +    //    throw std::runtime_error("unhandled prop in usrp2 dboard");      }  } @@ -113,8 +114,8 @@ void usrp2_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val){          val = _dboard_manager->get_tx_subdev_names();          return; -    case DBOARD_PROP_CODEC: -        throw std::runtime_error("unhandled prop in usrp2 dboard"); +    //case DBOARD_PROP_CODEC: +    //    throw std::runtime_error("unhandled prop in usrp2 dboard");      }  } diff --git a/host/lib/usrp/usrp2/dsp_impl.cpp b/host/lib/usrp/usrp2/dsp_impl.cpp index 7831b7667..cb7f58ec8 100644 --- a/host/lib/usrp/usrp2/dsp_impl.cpp +++ b/host/lib/usrp/usrp2/dsp_impl.cpp @@ -16,6 +16,7 @@  //  #include <uhd/utils.hpp> +#include <boost/format.hpp>  #include <boost/assign/list_of.hpp>  #include "usrp2_impl.hpp" @@ -110,7 +111,7 @@ void usrp2_impl::ddc_get(const wax::obj &key, wax::obj &val){                  prop_names_t others = boost::assign::list_of                      ("rate")                      ("decim") -                    ("decim_rates") +                    ("decims")                      ("freq")                      ("enabled")                      ("stream_at") @@ -131,7 +132,7 @@ void usrp2_impl::ddc_get(const wax::obj &key, wax::obj &val){          val = _ddc_decim;          return;      } -    else if (key_name == "decim_rates"){ +    else if (key_name == "decims"){          val = _allowed_decim_and_interp_rates;          return;      } @@ -154,10 +155,10 @@ void usrp2_impl::ddc_set(const wax::obj &key, const wax::obj &val){      std::string key_name = wax::cast<std::string>(key);      if (key_name == "decim"){          size_t new_decim = wax::cast<size_t>(val); -        ASSERT_THROW(std::has( +        assert_has(              _allowed_decim_and_interp_rates, -            new_decim -        )); +            new_decim, "usrp2 decimation" +        );          _ddc_decim = new_decim; //shadow          update_ddc_config();          return; @@ -244,7 +245,7 @@ void usrp2_impl::duc_get(const wax::obj &key, wax::obj &val){                  prop_names_t others = boost::assign::list_of                      ("rate")                      ("interp") -                    ("interp_rates") +                    ("interps")                      ("freq")                  ;                  val = others; @@ -263,7 +264,7 @@ void usrp2_impl::duc_get(const wax::obj &key, wax::obj &val){          val = _duc_interp;          return;      } -    else if (key_name == "interp_rates"){ +    else if (key_name == "interps"){          val = _allowed_decim_and_interp_rates;          return;      } @@ -282,10 +283,10 @@ void usrp2_impl::duc_set(const wax::obj &key, const wax::obj &val){      std::string key_name = wax::cast<std::string>(key);      if (key_name == "interp"){          size_t new_interp = wax::cast<size_t>(val); -        ASSERT_THROW(std::has( +        assert_has(              _allowed_decim_and_interp_rates, -            new_interp -        )); +            new_interp, "usrp2 interpolation" +        );          _duc_interp = new_interp; //shadow          update_duc_config();          return; diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h index 8e4b2ba35..10c1ef8cf 100644 --- a/host/lib/usrp/usrp2/fw_common.h +++ b/host/lib/usrp/usrp2/fw_common.h @@ -91,6 +91,9 @@ typedef enum{      USRP2_CTRL_ID_SETUP_THIS_DUC_FOR_ME_BRO,      USRP2_CTRL_ID_TOTALLY_SETUP_THE_DUC_DUDE, +    USRP2_CTRL_ID_GOT_A_NEW_TIME_FOR_YOU_BRO, +    USRP2_CTRL_ID_SWEET_I_GOT_THAT_TIME_DUDE, +      USRP2_CTRL_ID_PEACE_OUT  } usrp2_ctrl_id_t; @@ -186,6 +189,11 @@ typedef struct{              uint32_t interp;              uint32_t scale_iq;          } duc_args; +        struct { +            uint32_t secs; +            uint32_t ticks; +            uint8_t now; +        } time_args;      } data;  } usrp2_ctrl_data_t; diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index 8e682a675..47e22c473 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -28,6 +28,10 @@ void usrp2_impl::mboard_init(void){          boost::bind(&usrp2_impl::mboard_get, this, _1, _2),          boost::bind(&usrp2_impl::mboard_set, this, _1, _2)      ); + +    //set the time on the usrp2 as close as possible to the system utc time +    boost::posix_time::ptime now(boost::posix_time::microsec_clock::universal_time()); +    set_time_spec(time_spec_t(now, get_master_clock_freq()), true);  }  void usrp2_impl::init_clock_config(void){ @@ -64,6 +68,19 @@ void usrp2_impl::update_clock_config(void){      ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_GOT_THE_NEW_CLOCK_CONFIG_DUDE);  } +void usrp2_impl::set_time_spec(const time_spec_t &time_spec, bool now){ +    //setup the out data +    usrp2_ctrl_data_t out_data; +    out_data.id = htonl(USRP2_CTRL_ID_GOT_A_NEW_TIME_FOR_YOU_BRO); +    out_data.data.time_args.secs  = htonl(time_spec.secs); +    out_data.data.time_args.ticks = htonl(time_spec.ticks); +    out_data.data.time_args.now   = (now)? 1 : 0; + +    //send and recv +    usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data); +    ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_SWEET_I_GOT_THAT_TIME_DUDE); +} +  /***********************************************************************   * MBoard Get Properties   **********************************************************************/ @@ -157,7 +174,7 @@ void usrp2_impl::mboard_set(const wax::obj &key, const wax::obj &val){      case MBOARD_PROP_PPS_SOURCE:{              std::string name = wax::cast<std::string>(val); -            ASSERT_THROW(_pps_source_dict.has_key(name)); +            assert_has(_pps_source_dict.get_keys(), name, "usrp2 pps source");              _pps_source = name; //shadow              update_clock_config();          } @@ -165,7 +182,7 @@ void usrp2_impl::mboard_set(const wax::obj &key, const wax::obj &val){      case MBOARD_PROP_PPS_POLARITY:{              std::string name = wax::cast<std::string>(val); -            ASSERT_THROW(_pps_polarity_dict.has_key(name)); +            assert_has(_pps_polarity_dict.get_keys(), name, "usrp2 pps polarity");              _pps_polarity = name; //shadow              update_clock_config();          } @@ -173,12 +190,22 @@ void usrp2_impl::mboard_set(const wax::obj &key, const wax::obj &val){      case MBOARD_PROP_REF_SOURCE:{              std::string name = wax::cast<std::string>(val); -            ASSERT_THROW(_ref_source_dict.has_key(name)); +            assert_has(_ref_source_dict.get_keys(), name, "usrp2 reference source");              _ref_source = name; //shadow              update_clock_config();          }          return; +    case MBOARD_PROP_TIME_NOW:{ +        set_time_spec(wax::cast<time_spec_t>(val), true); +        return; +    } + +    case MBOARD_PROP_TIME_NEXT_PPS:{ +        set_time_spec(wax::cast<time_spec_t>(val), false); +        return; +    } +      case MBOARD_PROP_NAME:      case MBOARD_PROP_OTHERS:      case MBOARD_PROP_CLOCK_RATE: @@ -192,8 +219,6 @@ void usrp2_impl::mboard_set(const wax::obj &key, const wax::obj &val){      case MBOARD_PROP_TX_DBOARD_NAMES:      case MBOARD_PROP_PPS_SOURCE_NAMES:      case MBOARD_PROP_REF_SOURCE_NAMES: -    case MBOARD_PROP_TIME_NOW: -    case MBOARD_PROP_TIME_NEXT_PPS:          throw std::runtime_error("Error: trying to set read-only property on usrp2 mboard");      } diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index f4e6054bd..fc713c2bf 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -135,6 +135,7 @@ private:      std::string _pps_source, _pps_polarity, _ref_source;      void init_clock_config(void);      void update_clock_config(void); +    void set_time_spec(const uhd::time_spec_t &time_spec, bool now);      //mappings from clock config strings to over the wire enums      uhd::dict<std::string, usrp2_pps_source_t>   _pps_source_dict; | 
