diff options
Diffstat (limited to 'host')
26 files changed, 738 insertions, 446 deletions
| diff --git a/host/include/uhd/usrp/CMakeLists.txt b/host/include/uhd/usrp/CMakeLists.txt index ef0696700..76ee24e5f 100644 --- a/host/include/uhd/usrp/CMakeLists.txt +++ b/host/include/uhd/usrp/CMakeLists.txt @@ -18,6 +18,7 @@  INSTALL(FILES      #### props headers ### +    codec_props.hpp      dboard_props.hpp      device_props.hpp      dsp_props.hpp diff --git a/host/include/uhd/usrp/codec_props.hpp b/host/include/uhd/usrp/codec_props.hpp new file mode 100644 index 000000000..ab09b1703 --- /dev/null +++ b/host/include/uhd/usrp/codec_props.hpp @@ -0,0 +1,42 @@ +// +// 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_USRP_CODEC_PROPS_HPP +#define INCLUDED_UHD_USRP_CODEC_PROPS_HPP + +#include <uhd/utils/props.hpp> + +namespace uhd{ namespace usrp{ + +    /*! +    * 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{ +        CODEC_PROP_NAME           = 'n', //ro, std::string +        CODEC_PROP_OTHERS         = 'o', //ro, prop_names_t +        CODEC_PROP_GAIN_I         = 'i', //rw, float +        CODEC_PROP_GAIN_Q         = 'q', //rw, float +        CODEC_PROP_GAIN_RANGE     = 'r', //ro, gain_range_t +        CODEC_PROP_GAIN_NAMES     = 'G'  //ro, prop_names_t +    }; + + +}} //namespace + +#endif /* INCLUDED_UHD_USRP_CODEC_PROPS_HPP */ diff --git a/host/include/uhd/usrp/dboard_props.hpp b/host/include/uhd/usrp/dboard_props.hpp index 8a6ef9129..aab6c31ce 100644 --- a/host/include/uhd/usrp/dboard_props.hpp +++ b/host/include/uhd/usrp/dboard_props.hpp @@ -23,15 +23,18 @@  namespace uhd{ namespace usrp{      /*! -     * Possible device dboard properties +     * Possible device dboard properties: +     *    A dboard has an id, one or more subdevices, and a codec. +     *    A dboard is considered to be unidirectional (RX or TX).       */      enum dboard_prop_t{          DBOARD_PROP_NAME         = 'n', //ro, std::string          DBOARD_PROP_SUBDEV       = 's', //ro, wax::obj          DBOARD_PROP_SUBDEV_NAMES = 'S', //ro, prop_names_t          DBOARD_PROP_DBOARD_ID    = 'i', //rw, dboard_id_t -        DBOARD_PROP_DBOARD_IFACE = 'f'  //ro, dboard_iface::sptr -        //DBOARD_PROP_CODEC              //ro, wax::obj //----> not sure, dont have to deal with yet +        DBOARD_PROP_DBOARD_IFACE = 'f', //ro, dboard_iface::sptr +        DBOARD_PROP_CODEC        = 'c', //ro, wax::obj +        DBOARD_PROP_GAIN_GROUP   = 'g'  //ro, gain_group      };   }} //namespace diff --git a/host/include/uhd/usrp/device_props.hpp b/host/include/uhd/usrp/device_props.hpp index 983bcb672..346eec179 100644 --- a/host/include/uhd/usrp/device_props.hpp +++ b/host/include/uhd/usrp/device_props.hpp @@ -34,22 +34,6 @@ namespace uhd{ namespace usrp{          DEVICE_PROP_MBOARD_NAMES   = 'M'  //ro, prop_names_t      }; -    //////////////////////////////////////////////////////////////////////// -    /*! ------ 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{ -        CODEC_PROP_NAME,               //ro, std::string -        CODEC_PROP_OTHERS,             //ro, prop_names_t -        CODEC_PROP_GAIN,               //rw, gain_t -        CODEC_PROP_GAIN_RANGE,         //ro, gain_range_t -        CODEC_PROP_GAIN_NAMES,         //ro, prop_names_t -        //CODEC_PROP_CLOCK_RATE          //ro, freq_t //----> not sure we care to know -    };*/ - -  }} //namespace  #endif /* INCLUDED_UHD_USRP_DEVICE_PROPS_HPP */ diff --git a/host/include/uhd/usrp/subdev_props.hpp b/host/include/uhd/usrp/subdev_props.hpp index f7bdcd161..cd07cb7a8 100644 --- a/host/include/uhd/usrp/subdev_props.hpp +++ b/host/include/uhd/usrp/subdev_props.hpp @@ -53,8 +53,6 @@ namespace uhd{ namespace usrp{          SUBDEV_PROP_ANTENNA_NAMES     = 'A', //ro, prop_names_t          SUBDEV_PROP_LO_LOCKED         = 'L', //ro, bool          SUBDEV_PROP_CONNECTION        = 'c', //ro, subdev_conn_t -        //SUBDEV_PROP_QUADRATURE        = 'q', //ro, bool -        //SUBDEV_PROP_IQ_SWAPPED        = 'i', //ro, bool          SUBDEV_PROP_USE_LO_OFFSET     = 'l', //ro, bool          SUBDEV_PROP_RSSI              = 'R', //ro, float          SUBDEV_PROP_BANDWIDTH         = 'B'  //rw, double diff --git a/host/include/uhd/utils/CMakeLists.txt b/host/include/uhd/utils/CMakeLists.txt index aa7842094..ef8e64ce0 100644 --- a/host/include/uhd/utils/CMakeLists.txt +++ b/host/include/uhd/utils/CMakeLists.txt @@ -22,7 +22,7 @@ INSTALL(FILES      byteswap.hpp      byteswap.ipp      exception.hpp -    gain_handler.hpp +    gain_group.hpp      pimpl.hpp      props.hpp      safe_main.hpp diff --git a/host/include/uhd/utils/gain_group.hpp b/host/include/uhd/utils/gain_group.hpp new file mode 100644 index 000000000..3955dfa9a --- /dev/null +++ b/host/include/uhd/utils/gain_group.hpp @@ -0,0 +1,85 @@ +// +// 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_GAIN_GROUP_HPP +#define INCLUDED_UHD_UTILS_GAIN_GROUP_HPP + +#include <uhd/config.hpp> +#include <uhd/types/ranges.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/function.hpp> +#include <boost/utility.hpp> + +namespace uhd{ + +/*! + * A set of function to control a gain element. + */ +struct UHD_API gain_fcns_t{ +    boost::function<gain_range_t(void)> get_range; +    boost::function<float(void)>        get_value; +    boost::function<void(float)>        set_value; +}; + +class UHD_API gain_group : boost::noncopyable{ +public: +    typedef boost::shared_ptr<gain_group> sptr; + +    /*! +     * Get the overall gain range for this group. +     * Overall step is defined as the minimum step size. +     * \return a gain range with overall min, max, step +     */ +    virtual gain_range_t get_range(void) = 0; + +    /*! +     * Get the overall gain value for this group. +     * \return a summation of all the gain values +     */ +    virtual float get_value(void) = 0; + +    /*! +     * Set the overall gain value for this group. +     * The power will be distributed across individual gain elements. +     * The semantics of how to do this are determined by the priority. +     * \param gain the gain to set across the group +     */ +    virtual void set_value(float gain) = 0; + +    /*! +     * Register a set of gain functions into this group. +     * Priority determines how power will be distributed +     * with higher priorities getting the power first, +     * and lower priorities getting the remainder power. +     * \param gain_fcns the set of gain functions +     * \param priority the priority of the gain element +     */ +    virtual void register_fcns( +        const gain_fcns_t &gain_fcns, size_t priority = 0 +    ) = 0; + +    /*! +     * Make a new empty gain group. +     * \return a gain group object. +     */ +    static sptr make(void); +}; + +} //namespace uhd + +#endif /* INCLUDED_UHD_UTILS_GAIN_GROUP_HPP */ + diff --git a/host/include/uhd/utils/gain_handler.hpp b/host/include/uhd/utils/gain_handler.hpp deleted file mode 100644 index f4629e6a7..000000000 --- a/host/include/uhd/utils/gain_handler.hpp +++ /dev/null @@ -1,90 +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/>. -// - -#ifndef INCLUDED_UHD_UTILS_GAIN_HANDLER_HPP -#define INCLUDED_UHD_UTILS_GAIN_HANDLER_HPP - -#include <uhd/config.hpp> -#include <uhd/wax.hpp> -#include <boost/shared_ptr.hpp> -#include <boost/function.hpp> - -namespace uhd{ - -class UHD_API gain_handler{ -public: -    typedef boost::shared_ptr<gain_handler> sptr; -    typedef boost::function<bool(const wax::obj &, const wax::obj &)> is_equal_t; - -    /*! -     * A set of properties for dealing with gains. -     */ -    struct UHD_API props_t{ -        wax::obj value, range, names; -        props_t(void); //default constructor -    }; - -    /*! -     * Make a new gain handler. -     * The construction arguments are agnostic to the property type. -     * It is up to the caller to provide an "is_equal" function that -     * can tell weather two properties (in a wax obj) are equal. -     * \param link a link to the wax obj with properties -     * \param props a struct of properties keys -     * \param is_equal the function that tests for equal properties -     */ -    static sptr make( -        const wax::obj &link, -        const props_t &props, -        is_equal_t is_equal -    ); - -    /*! -     * Intercept gets for overall gain, min, max, step. -     * Ensures that the gain name is valid. -     * \return true for handled, false to pass on -     */ -    virtual bool intercept_get(const wax::obj &key, wax::obj &val) = 0; - -    /*! -     * Intercept sets for overall gain. -     * Ensures that the gain name is valid. -     * Ensures that the new gain is within range. -     * \return true for handled, false to pass on -     */ -    virtual bool intercept_set(const wax::obj &key, const wax::obj &val) = 0; - -    /*! -     * Function template to test if two wax types are equal: -     * The constructor will bind an instance of this for a specific type. -     * This bound equals functions allows the intercept methods to be non-templated. -     */ -    template <class T> static bool is_equal(const wax::obj &a, const wax::obj &b){ -        try{ -            return a.as<T>() == b.as<T>(); -        } -        catch(const wax::bad_cast &){ -            return false; -        } -    } - -}; - -} //namespace uhd - -#endif /* INCLUDED_UHD_UTILS_GAIN_HANDLER_HPP */ - diff --git a/host/lib/usrp/CMakeLists.txt b/host/lib/usrp/CMakeLists.txt index a403296fa..d951ab412 100644 --- a/host/lib/usrp/CMakeLists.txt +++ b/host/lib/usrp/CMakeLists.txt @@ -24,6 +24,8 @@ LIBUHD_APPEND_SOURCES(      ${CMAKE_SOURCE_DIR}/lib/usrp/dboard_manager.cpp      ${CMAKE_SOURCE_DIR}/lib/usrp/dsp_utils.hpp      ${CMAKE_SOURCE_DIR}/lib/usrp/mimo_usrp.cpp +    ${CMAKE_SOURCE_DIR}/lib/usrp/misc_utils.cpp +    ${CMAKE_SOURCE_DIR}/lib/usrp/misc_utils.hpp      ${CMAKE_SOURCE_DIR}/lib/usrp/simple_usrp.cpp      ${CMAKE_SOURCE_DIR}/lib/usrp/subdev_spec.cpp      ${CMAKE_SOURCE_DIR}/lib/usrp/tune_helper.cpp diff --git a/host/lib/usrp/dboard_manager.cpp b/host/lib/usrp/dboard_manager.cpp index bfaaf0969..ab80875f5 100644 --- a/host/lib/usrp/dboard_manager.cpp +++ b/host/lib/usrp/dboard_manager.cpp @@ -18,7 +18,6 @@  #include "dboard_ctor_args.hpp"  #include <uhd/usrp/dboard_manager.hpp>  #include <uhd/usrp/subdev_props.hpp> -#include <uhd/utils/gain_handler.hpp>  #include <uhd/utils/static.hpp>  #include <uhd/utils/assert.hpp>  #include <uhd/types/dict.hpp> @@ -98,33 +97,18 @@ public:      enum type_t{RX_TYPE, TX_TYPE};      //structors -    subdev_proxy(dboard_base::sptr subdev, type_t type) -    : _subdev(subdev), _type(type){ -        //initialize gain props struct -        gain_handler::props_t gain_props; -        gain_props.value = SUBDEV_PROP_GAIN; -        gain_props.range = SUBDEV_PROP_GAIN_RANGE; -        gain_props.names = SUBDEV_PROP_GAIN_NAMES; - -        //make a new gain handler -        _gain_handler = gain_handler::make( -            this->get_link(), gain_props, -            boost::bind(&gain_handler::is_equal<subdev_prop_t>, _1, _2) -        ); -    } - -    ~subdev_proxy(void){ +    subdev_proxy(dboard_base::sptr subdev, type_t type): +        _subdev(subdev), _type(type) +    {          /* NOP */      }  private: -    gain_handler::sptr   _gain_handler;      dboard_base::sptr   _subdev;      type_t              _type;      //forward the get calls to the rx or tx      void get(const wax::obj &key, wax::obj &val){ -        if (_gain_handler->intercept_get(key, val)) return;          switch(_type){          case RX_TYPE: return _subdev->rx_get(key, val);          case TX_TYPE: return _subdev->tx_get(key, val); @@ -133,7 +117,6 @@ private:      //forward the set calls to the rx or tx      void set(const wax::obj &key, const wax::obj &val){ -        if (_gain_handler->intercept_set(key, val)) return;          switch(_type){          case RX_TYPE: return _subdev->rx_set(key, val);          case TX_TYPE: return _subdev->tx_set(key, val); diff --git a/host/lib/usrp/mimo_usrp.cpp b/host/lib/usrp/mimo_usrp.cpp index 34dee42b8..7965e4016 100644 --- a/host/lib/usrp/mimo_usrp.cpp +++ b/host/lib/usrp/mimo_usrp.cpp @@ -18,6 +18,7 @@  #include <uhd/usrp/mimo_usrp.hpp>  #include <uhd/usrp/tune_helper.hpp>  #include <uhd/utils/assert.hpp> +#include <uhd/utils/gain_group.hpp>  #include <uhd/utils/algorithm.hpp>  #include <uhd/utils/warning.hpp>  #include <uhd/usrp/subdev_props.hpp> @@ -190,15 +191,15 @@ public:      }      void set_rx_gain(size_t chan, float gain){ -        _rx_subdev(chan)[SUBDEV_PROP_GAIN] = gain; +        return _rx_gain_group(chan)->set_value(gain);      }      float get_rx_gain(size_t chan){ -        return _rx_subdev(chan)[SUBDEV_PROP_GAIN].as<float>(); +        return _rx_gain_group(chan)->get_value();      }      gain_range_t get_rx_gain_range(size_t chan){ -        return _rx_subdev(chan)[SUBDEV_PROP_GAIN_RANGE].as<gain_range_t>(); +        return _rx_gain_group(chan)->get_range();      }      void set_rx_antenna(size_t chan, const std::string &ant){ @@ -262,15 +263,15 @@ public:      }      void set_tx_gain(size_t chan, float gain){ -        _tx_subdev(chan)[SUBDEV_PROP_GAIN] = gain; +        return _tx_gain_group(chan)->set_value(gain);      }      float get_tx_gain(size_t chan){ -        return _tx_subdev(chan)[SUBDEV_PROP_GAIN].as<float>(); +        return _tx_gain_group(chan)->get_value();      }      gain_range_t get_tx_gain_range(size_t chan){ -        return _tx_subdev(chan)[SUBDEV_PROP_GAIN_RANGE].as<gain_range_t>(); +        return _tx_gain_group(chan)->get_range();      }      void set_tx_antenna(size_t chan, const std::string &ant){ @@ -317,6 +318,14 @@ private:          std::string sd_name = _mboard(chan)[MBOARD_PROP_TX_SUBDEV_SPEC].as<subdev_spec_t>().front().sd_name;          return _tx_dboard(chan)[named_prop_t(DBOARD_PROP_SUBDEV, sd_name)];      } +    gain_group::sptr _rx_gain_group(size_t chan){ +        std::string sd_name = _mboard(chan)[MBOARD_PROP_RX_SUBDEV_SPEC].as<subdev_spec_t>().front().sd_name; +        return _rx_dboard(chan)[named_prop_t(DBOARD_PROP_GAIN_GROUP, sd_name)].as<gain_group::sptr>(); +    } +    gain_group::sptr _tx_gain_group(size_t chan){ +        std::string sd_name = _mboard(chan)[MBOARD_PROP_TX_SUBDEV_SPEC].as<subdev_spec_t>().front().sd_name; +        return _tx_dboard(chan)[named_prop_t(DBOARD_PROP_GAIN_GROUP, sd_name)].as<gain_group::sptr>(); +    }      //shadows      double _rx_rate, _tx_rate; diff --git a/host/lib/usrp/misc_utils.cpp b/host/lib/usrp/misc_utils.cpp new file mode 100644 index 000000000..0aa03a6cc --- /dev/null +++ b/host/lib/usrp/misc_utils.cpp @@ -0,0 +1,114 @@ +// +// 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 "misc_utils.hpp" +#include <uhd/utils/gain_group.hpp> +#include <uhd/usrp/subdev_props.hpp> +#include <uhd/usrp/codec_props.hpp> +#include <boost/bind.hpp> +#include <boost/foreach.hpp> + +using namespace uhd; +using namespace uhd::usrp; + +static const size_t subdev_gain_priority = 1; //higher, closer to the antenna +static const size_t codec_gain_priority = 0; + +/*********************************************************************** + * codec gain group helper functions: + *    do this so we dont have to bind a templated function + **********************************************************************/ +static gain_range_t get_codec_gain_range(wax::obj codec, const std::string &name){ +    return codec[named_prop_t(CODEC_PROP_GAIN_RANGE, name)].as<gain_range_t>(); +} + +static float get_codec_gain_i(wax::obj codec, const std::string &name){ +    return codec[named_prop_t(CODEC_PROP_GAIN_I, name)].as<float>(); +} + +static float get_codec_gain_q(wax::obj codec, const std::string &name){ +    return codec[named_prop_t(CODEC_PROP_GAIN_Q, name)].as<float>(); +} + +static void set_codec_gain_both(wax::obj codec, const std::string &name, float gain){ +    codec[named_prop_t(CODEC_PROP_GAIN_I, name)] = gain; +    codec[named_prop_t(CODEC_PROP_GAIN_Q, name)] = gain; +} + +static void set_codec_gain_i(wax::obj codec, const std::string &name, float gain){ +    codec[named_prop_t(CODEC_PROP_GAIN_I, name)] = gain; +} + +static void set_codec_gain_q(wax::obj codec, const std::string &name, float gain){ +    codec[named_prop_t(CODEC_PROP_GAIN_Q, name)] = gain; +} + +/*********************************************************************** + * subdev gain group helper functions: + *    do this so we dont have to bind a templated function + **********************************************************************/ +static float get_subdev_gain(wax::obj subdev, const std::string &name){ +    return subdev[named_prop_t(SUBDEV_PROP_GAIN, name)].as<float>(); +} + +static gain_range_t get_subdev_gain_range(wax::obj subdev, const std::string &name){ +    return subdev[named_prop_t(SUBDEV_PROP_GAIN_RANGE, name)].as<gain_range_t>(); +} + +static void set_subdev_gain(wax::obj subdev, const std::string &name, float gain){ +    subdev[named_prop_t(SUBDEV_PROP_GAIN, name)] = gain; +} + +/*********************************************************************** + * gain group factory function for usrp + **********************************************************************/ +gain_group::sptr usrp::make_gain_group(wax::obj subdev, wax::obj codec){ +    gain_group::sptr gg = gain_group::make(); +    gain_fcns_t fcns; +    //add all the subdev gains first (antenna to dsp order) +    BOOST_FOREACH(const std::string &name, subdev[SUBDEV_PROP_GAIN_NAMES].as<prop_names_t>()){ +        fcns.get_range = boost::bind(&get_subdev_gain_range, subdev, name); +        fcns.get_value = boost::bind(&get_subdev_gain, subdev, name); +        fcns.set_value = boost::bind(&set_subdev_gain, subdev, name, _1); +        gg->register_fcns(fcns, subdev_gain_priority); +    } +    //add all the codec gains last (antenna to dsp order) +    BOOST_FOREACH(const std::string &name, codec[CODEC_PROP_GAIN_NAMES].as<prop_names_t>()){ +        fcns.get_range = boost::bind(&get_codec_gain_range, codec, name); + +        //register the value functions depending upon the connection type +        switch(subdev[SUBDEV_PROP_CONNECTION].as<subdev_conn_t>()){ +        case SUBDEV_CONN_COMPLEX_IQ: +        case SUBDEV_CONN_COMPLEX_QI: +            fcns.get_value = boost::bind(&get_codec_gain_i, codec, name); //same as Q +            fcns.set_value = boost::bind(&set_codec_gain_both, codec, name, _1); //sets both +            break; + +        case SUBDEV_CONN_REAL_I: +            fcns.get_value = boost::bind(&get_codec_gain_i, codec, name); +            fcns.set_value = boost::bind(&set_codec_gain_i, codec, name, _1); +            break; + +        case SUBDEV_CONN_REAL_Q: +            fcns.get_value = boost::bind(&get_codec_gain_q, codec, name); +            fcns.set_value = boost::bind(&set_codec_gain_q, codec, name, _1); +            break; +        } +        gg->register_fcns(fcns, codec_gain_priority); +    } +    return gg; +} diff --git a/host/lib/usrp/misc_utils.hpp b/host/lib/usrp/misc_utils.hpp new file mode 100644 index 000000000..7fe3c899d --- /dev/null +++ b/host/lib/usrp/misc_utils.hpp @@ -0,0 +1,35 @@ +// +// 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_LIBUHD_USRP_MISC_UTILS_HPP +#define INCLUDED_LIBUHD_USRP_MISC_UTILS_HPP + +#include <uhd/config.hpp> +#include <uhd/wax.hpp> +#include <uhd/utils/gain_group.hpp> + +namespace uhd{ namespace usrp{ + +    /*! +     * Create a gain group that represents the subdevice and its codec. +     */ +    gain_group::sptr make_gain_group(wax::obj subdev, wax::obj codec); + +}} //namespace + +#endif /* INCLUDED_LIBUHD_USRP_MISC_UTILS_HPP */ + diff --git a/host/lib/usrp/simple_usrp.cpp b/host/lib/usrp/simple_usrp.cpp index ebba5e137..40b71d355 100644 --- a/host/lib/usrp/simple_usrp.cpp +++ b/host/lib/usrp/simple_usrp.cpp @@ -18,6 +18,7 @@  #include <uhd/usrp/simple_usrp.hpp>  #include <uhd/usrp/tune_helper.hpp>  #include <uhd/utils/assert.hpp> +#include <uhd/utils/gain_group.hpp>  #include <uhd/usrp/subdev_props.hpp>  #include <uhd/usrp/mboard_props.hpp>  #include <uhd/usrp/device_props.hpp> @@ -132,15 +133,15 @@ public:      }      void set_rx_gain(float gain){ -        _rx_subdev()[SUBDEV_PROP_GAIN] = gain; +        return _rx_gain_group()->set_value(gain);      }      float get_rx_gain(void){ -        return _rx_subdev()[SUBDEV_PROP_GAIN].as<float>(); +        return _rx_gain_group()->get_value();      }      gain_range_t get_rx_gain_range(void){ -        return _rx_subdev()[SUBDEV_PROP_GAIN_RANGE].as<gain_range_t>(); +        return _rx_gain_group()->get_range();      }      void set_rx_antenna(const std::string &ant){ @@ -196,15 +197,15 @@ public:      }      void set_tx_gain(float gain){ -        _tx_subdev()[SUBDEV_PROP_GAIN] = gain; +        return _tx_gain_group()->set_value(gain);      }      float get_tx_gain(void){ -        return _tx_subdev()[SUBDEV_PROP_GAIN].as<float>(); +        return _tx_gain_group()->get_value();      }      gain_range_t get_tx_gain_range(void){ -        return _tx_subdev()[SUBDEV_PROP_GAIN_RANGE].as<gain_range_t>(); +        return _tx_gain_group()->get_range();      }      void set_tx_antenna(const std::string &ant){ @@ -250,6 +251,14 @@ private:          std::string sd_name = _mboard()[MBOARD_PROP_TX_SUBDEV_SPEC].as<subdev_spec_t>().front().sd_name;          return _tx_dboard()[named_prop_t(DBOARD_PROP_SUBDEV, sd_name)];      } +    gain_group::sptr _rx_gain_group(void){ +        std::string sd_name = _mboard()[MBOARD_PROP_RX_SUBDEV_SPEC].as<subdev_spec_t>().front().sd_name; +        return _rx_dboard()[named_prop_t(DBOARD_PROP_GAIN_GROUP, sd_name)].as<gain_group::sptr>(); +    } +    gain_group::sptr _tx_gain_group(void){ +        std::string sd_name = _mboard()[MBOARD_PROP_TX_SUBDEV_SPEC].as<subdev_spec_t>().front().sd_name; +        return _tx_dboard()[named_prop_t(DBOARD_PROP_GAIN_GROUP, sd_name)].as<gain_group::sptr>(); +    }  };  /*********************************************************************** diff --git a/host/lib/usrp/usrp2/CMakeLists.txt b/host/lib/usrp/usrp2/CMakeLists.txt index 99d0b8bdd..796126d07 100644 --- a/host/lib/usrp/usrp2/CMakeLists.txt +++ b/host/lib/usrp/usrp2/CMakeLists.txt @@ -22,6 +22,7 @@ LIBUHD_APPEND_SOURCES(      ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/clock_ctrl.hpp      ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/codec_ctrl.cpp      ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/codec_ctrl.hpp +    ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/codec_impl.cpp      ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/dboard_impl.cpp      ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/dboard_iface.cpp      ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/dsp_impl.cpp diff --git a/host/lib/usrp/usrp2/codec_impl.cpp b/host/lib/usrp/usrp2/codec_impl.cpp new file mode 100644 index 000000000..b9d51abf5 --- /dev/null +++ b/host/lib/usrp/usrp2/codec_impl.cpp @@ -0,0 +1,96 @@ +// +// 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 "usrp2_impl.hpp" +#include <uhd/usrp/codec_props.hpp> +#include <boost/bind.hpp> + +using namespace uhd; +using namespace uhd::usrp; + +/*********************************************************************** + * Helper Methods + **********************************************************************/ +void usrp2_mboard_impl::codec_init(void){ +    //make proxies +    _rx_codec_proxy = wax_obj_proxy::make( +        boost::bind(&usrp2_mboard_impl::rx_codec_get, this, _1, _2), +        boost::bind(&usrp2_mboard_impl::rx_codec_set, this, _1, _2) +    ); +    _tx_codec_proxy = wax_obj_proxy::make( +        boost::bind(&usrp2_mboard_impl::tx_codec_get, this, _1, _2), +        boost::bind(&usrp2_mboard_impl::tx_codec_set, this, _1, _2) +    ); +} + +/*********************************************************************** + * RX Codec Properties + **********************************************************************/ +void usrp2_mboard_impl::rx_codec_get(const wax::obj &key_, wax::obj &val){ +    wax::obj key; std::string name; +    boost::tie(key, name) = extract_named_prop(key_); + +    //handle the get request conditioned on the key +    switch(key.as<codec_prop_t>()){ +    case CODEC_PROP_NAME: +        val = std::string("usrp2 adc"); +        return; + +    case CODEC_PROP_OTHERS: +        val = prop_names_t(); +        return; + +    case CODEC_PROP_GAIN_NAMES: +        val = prop_names_t(); //no gain elements to be controlled +        return; + +    default: UHD_THROW_PROP_GET_ERROR(); +    } +} + +void usrp2_mboard_impl::rx_codec_set(const wax::obj &, const wax::obj &){ +    UHD_THROW_PROP_SET_ERROR(); +} + +/*********************************************************************** + * TX Codec Properties + **********************************************************************/ +void usrp2_mboard_impl::tx_codec_get(const wax::obj &key_, wax::obj &val){ +    wax::obj key; std::string name; +    boost::tie(key, name) = extract_named_prop(key_); + +    //handle the get request conditioned on the key +    switch(key.as<codec_prop_t>()){ +    case CODEC_PROP_NAME: +        val = std::string("usrp2 dac - ad9777"); +        return; + +    case CODEC_PROP_OTHERS: +        val = prop_names_t(); +        return; + +    case CODEC_PROP_GAIN_NAMES: +        val = prop_names_t(); //no gain elements to be controlled +        return; + +    default: UHD_THROW_PROP_GET_ERROR(); +    } +} + +void usrp2_mboard_impl::tx_codec_set(const wax::obj &, const wax::obj &){ +    UHD_THROW_PROP_SET_ERROR(); +} diff --git a/host/lib/usrp/usrp2/dboard_impl.cpp b/host/lib/usrp/usrp2/dboard_impl.cpp index 8f6182fb5..075f22388 100644 --- a/host/lib/usrp/usrp2/dboard_impl.cpp +++ b/host/lib/usrp/usrp2/dboard_impl.cpp @@ -15,10 +15,10 @@  // along with this program.  If not, see <http://www.gnu.org/licenses/>.  // -  #include "usrp2_impl.hpp"  #include "usrp2_regs.hpp"  #include "../dsp_utils.hpp" +#include "../misc_utils.hpp"  #include <uhd/usrp/subdev_props.hpp>  #include <uhd/usrp/dboard_props.hpp>  #include <uhd/utils/assert.hpp> @@ -84,6 +84,16 @@ void usrp2_mboard_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val){          val = _dboard_iface;          return; +    case DBOARD_PROP_CODEC: +        val = _rx_codec_proxy->get_link(); +        return; + +    case DBOARD_PROP_GAIN_GROUP: +        val = make_gain_group( +            _dboard_manager->get_rx_subdev(name), _rx_codec_proxy->get_link() +        ); +        return; +      default: UHD_THROW_PROP_GET_ERROR();      }  } @@ -129,6 +139,16 @@ void usrp2_mboard_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val){          val = _dboard_iface;          return; +    case DBOARD_PROP_CODEC: +        val = _tx_codec_proxy->get_link(); +        return; + +    case DBOARD_PROP_GAIN_GROUP: +        val = make_gain_group( +            _dboard_manager->get_tx_subdev(name), _tx_codec_proxy->get_link() +        ); +        return; +      default: UHD_THROW_PROP_GET_ERROR();      }  } diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index 92a87150a..610aade14 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -96,6 +96,9 @@ usrp2_mboard_impl::usrp2_mboard_impl(      //initialize the clock configuration      init_clock_config(); +    //init the codec before the dboard +    codec_init(); +      //init the tx and rx dboards (do last)      dboard_init(); diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index e7e560469..157d17057 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -163,6 +163,15 @@ private:      void update_clock_config(void);      void set_time_spec(const uhd::time_spec_t &time_spec, bool now); +    //properties interface for the codec +    void codec_init(void); +    void rx_codec_get(const wax::obj &, wax::obj &); +    void rx_codec_set(const wax::obj &, const wax::obj &); +    void tx_codec_get(const wax::obj &, wax::obj &); +    void tx_codec_set(const wax::obj &, const wax::obj &); +    wax_obj_proxy::sptr _rx_codec_proxy; +    wax_obj_proxy::sptr _tx_codec_proxy; +      //properties interface for rx dboard      void rx_dboard_get(const wax::obj &, wax::obj &);      void rx_dboard_set(const wax::obj &, const wax::obj &); diff --git a/host/lib/utils/CMakeLists.txt b/host/lib/utils/CMakeLists.txt index 07e3b71b3..d6ec44193 100644 --- a/host/lib/utils/CMakeLists.txt +++ b/host/lib/utils/CMakeLists.txt @@ -19,7 +19,7 @@  LIBUHD_APPEND_SOURCES(      ${CMAKE_SOURCE_DIR}/lib/utils/assert.cpp -    ${CMAKE_SOURCE_DIR}/lib/utils/gain_handler.cpp +    ${CMAKE_SOURCE_DIR}/lib/utils/gain_group.cpp      ${CMAKE_SOURCE_DIR}/lib/utils/load_modules.cpp      ${CMAKE_SOURCE_DIR}/lib/utils/props.cpp      ${CMAKE_SOURCE_DIR}/lib/utils/thread_priority.cpp diff --git a/host/lib/utils/gain_group.cpp b/host/lib/utils/gain_group.cpp new file mode 100644 index 000000000..1be09dee2 --- /dev/null +++ b/host/lib/utils/gain_group.cpp @@ -0,0 +1,149 @@ +// +// 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/gain_group.hpp> +#include <uhd/types/dict.hpp> +#include <uhd/utils/algorithm.hpp> +#include <uhd/utils/assert.hpp> +#include <boost/foreach.hpp> +#include <boost/bind.hpp> +#include <algorithm> +#include <vector> +#include <iostream> + +using namespace uhd; + +static const bool verbose = false; + +static bool compare_by_step_size( +    const size_t &rhs, const size_t &lhs, std::vector<gain_fcns_t> &fcns +){ +    return fcns.at(rhs).get_range().step > fcns.at(lhs).get_range().step; +} + +/*********************************************************************** + * gain group implementation + **********************************************************************/ +class gain_group_impl : public gain_group{ +public: +    gain_group_impl(void){ +        /*NOP*/ +    } + +    gain_range_t get_range(void){ +        float overall_min = 0, overall_max = 0, overall_step = 0; +        BOOST_FOREACH(const gain_fcns_t &fcns, get_all_fcns()){ +            const gain_range_t range = fcns.get_range(); +            overall_min += range.min; +            overall_max += range.max; +            //the overall step is the min (zero is invalid, first run) +            if (overall_step == 0) overall_step = range.step; +            overall_step = std::min(overall_step, range.step); +        } +        return gain_range_t(overall_min, overall_max, overall_step); +    } + +    float get_value(void){ +        float overall_gain = 0; +        BOOST_FOREACH(const gain_fcns_t &fcns, get_all_fcns()){ +            overall_gain += fcns.get_value(); +        } +        return overall_gain; +    } + +    void set_value(float gain){ +        std::vector<gain_fcns_t> all_fcns = get_all_fcns(); +        if (all_fcns.size() == 0) return; //nothing to set! + +        //get the max step size among the gains +        float max_step = 0; +        BOOST_FOREACH(const gain_fcns_t &fcns, all_fcns){ +            max_step = std::max(max_step, fcns.get_range().step); +        } + +        //create gain bucket to distribute power +        std::vector<float> gain_bucket; + +        //distribute power according to priority (round to max step) +        float gain_left_to_distribute = gain; +        BOOST_FOREACH(const gain_fcns_t &fcns, all_fcns){ +            const gain_range_t range = fcns.get_range(); +            gain_bucket.push_back( +                max_step*int(std::clip(gain_left_to_distribute, range.min, range.max)/max_step) +            ); +            gain_left_to_distribute -= gain_bucket.back(); +        } + +        //get a list of indexes sorted by step size large to small +        std::vector<size_t> indexes_step_size_dec; +        for (size_t i = 0; i < all_fcns.size(); i++){ +            indexes_step_size_dec.push_back(i); +        } +        std::sort( +            indexes_step_size_dec.begin(), indexes_step_size_dec.end(), +            boost::bind(&compare_by_step_size, _1, _2, all_fcns) +        ); +        UHD_ASSERT_THROW( +            all_fcns.at(indexes_step_size_dec.front()).get_range().step >= +            all_fcns.at(indexes_step_size_dec.back()).get_range().step +        ); + +        //distribute the remainder (less than max step) +        //fill in the largest step sizes first that are less than the remainder +        BOOST_FOREACH(size_t i, indexes_step_size_dec){ +            const gain_range_t range = all_fcns.at(i).get_range(); +            float additional_gain = range.step*int( +                std::clip(gain_bucket.at(i) + gain_left_to_distribute, range.min, range.max +            )/range.step) - gain_bucket.at(i); +            gain_bucket.at(i) += additional_gain; +            gain_left_to_distribute -= additional_gain; +        } +        if (verbose) std::cout << "gain_left_to_distribute " << gain_left_to_distribute << std::endl; + +        //now write the bucket out to the individual gain values +        for (size_t i = 0; i < gain_bucket.size(); i++){ +            if (verbose) std::cout << gain_bucket.at(i) << std::endl; +            all_fcns.at(i).set_value(gain_bucket.at(i)); +        } +    } + +    void register_fcns( +        const gain_fcns_t &gain_fcns, size_t priority +    ){ +        _registry[priority].push_back(gain_fcns); +    } + +private: +    //! get the gain function sets in order (highest priority first) +    std::vector<gain_fcns_t> get_all_fcns(void){ +        std::vector<gain_fcns_t> all_fcns; +        BOOST_FOREACH(ssize_t key, std::sorted(_registry.keys())){ +            const std::vector<gain_fcns_t> &fcns = _registry[key]; +            all_fcns.insert(all_fcns.begin(), fcns.begin(), fcns.end()); +        } +        return all_fcns; +    } + +    uhd::dict<size_t, std::vector<gain_fcns_t> > _registry; +}; + +/*********************************************************************** + * gain group factory function + **********************************************************************/ +gain_group::sptr gain_group::make(void){ +    return sptr(new gain_group_impl()); +} diff --git a/host/lib/utils/gain_handler.cpp b/host/lib/utils/gain_handler.cpp deleted file mode 100644 index 36e2e8ed3..000000000 --- a/host/lib/utils/gain_handler.cpp +++ /dev/null @@ -1,177 +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/gain_handler.hpp> -#include <uhd/utils/assert.hpp> -#include <uhd/types/ranges.hpp> -#include <uhd/utils/props.hpp> -#include <boost/assign/list_of.hpp> -#include <boost/foreach.hpp> -#include <boost/format.hpp> -#include <cmath> -#include <vector> - -using namespace uhd; - -/*********************************************************************** - * gain handler implementation interface - **********************************************************************/ -class gain_handler_impl : public gain_handler{ -public: -    gain_handler_impl( -        const wax::obj &link, -        const props_t &props, -        is_equal_t is_equal -    ); -    ~gain_handler_impl(void); -    bool intercept_get(const wax::obj &key, wax::obj &val); -    bool intercept_set(const wax::obj &key, const wax::obj &val); - -private: -    wax::obj     _link; -    props_t _props; -    is_equal_t   _is_equal; - -    prop_names_t get_gain_names(void); -    float get_overall_gain_val(void); -    gain_range_t get_overall_gain_range(void); -    template <class T> T get_named_prop(const wax::obj &prop, const std::string &name){ -        return _link[named_prop_t(prop, name)].as<T>(); -    } -}; - -/*********************************************************************** - * the make function - **********************************************************************/ -gain_handler::sptr gain_handler::make( -    const wax::obj &link, -    const props_t &props, -    is_equal_t is_equal -){ -    return sptr(new gain_handler_impl(link, props, is_equal)); -} - -/*********************************************************************** - * gain handler implementation methods - **********************************************************************/ -gain_handler::props_t::props_t(void){ -    /* NOP */ -} - -gain_handler_impl::gain_handler_impl( -    const wax::obj &link, -    const props_t &props, -    is_equal_t is_equal -){ -    _link = link; -    _props = props; -    _is_equal = is_equal; -} - -gain_handler_impl::~gain_handler_impl(void){ -    /* NOP */ -} - -prop_names_t gain_handler_impl::get_gain_names(void){ -    return _link[_props.names].as<prop_names_t>(); -} - -float gain_handler_impl::get_overall_gain_val(void){ -    float gain_val = 0; -    BOOST_FOREACH(std::string name, get_gain_names()){ -        gain_val += get_named_prop<float>(_props.value, name); -    } -    return gain_val; -} - -gain_range_t gain_handler_impl::get_overall_gain_range(void){ -    float gain_min = 0, gain_max = 0, gain_step = 0; -    BOOST_FOREACH(std::string name, get_gain_names()){ -        gain_range_t floatmp = get_named_prop<gain_range_t>(_props.range, name); -        gain_min += floatmp.min; -        gain_max += floatmp.max; -        gain_step = std::max(gain_step, floatmp.step); -    } -    return gain_range_t(gain_min, gain_max, gain_step); -} - -/*********************************************************************** - * gain handler implementation get method - **********************************************************************/ -bool gain_handler_impl::intercept_get(const wax::obj &key_, wax::obj &val){ -    wax::obj key; std::string name; -    boost::tie(key, name) = extract_named_prop(key_); - -    //not a wildcard... dont handle (but check name) -    if (name != ""){ -        assert_has(get_gain_names(), name, "gain name"); -        return false; -    } - -    if (_is_equal(key, _props.value)){ -        val = get_overall_gain_val(); -        return true; -    } - -    if (_is_equal(key, _props.range)){ -        val = get_overall_gain_range(); -        return true; -    } - -    return false; //not handled -} - -/*********************************************************************** - * gain handler implementation set method - **********************************************************************/ -bool gain_handler_impl::intercept_set(const wax::obj &key_, const wax::obj &val){ -    wax::obj key; std::string name; -    boost::tie(key, name) = extract_named_prop(key_); - -    //not a gain value key... dont handle -    if (not _is_equal(key, _props.value)) return false; - -    float gain_val = val.as<float>(); - -    //not a wildcard... dont handle (but check name and range) -    if (name != ""){ -        assert_has(get_gain_names(), name, "gain name"); -        gain_range_t gain = get_named_prop<gain_range_t>(_props.range, name); -        if (gain_val > gain.max or gain_val < gain.min) throw std::range_error(str( -            boost::format("A value of %f for gain %s is out of range of (%f, %f)") -            % gain_val % name % gain.min % gain.max -        )); -        return false; -    } - -    //set the overall gain -    BOOST_FOREACH(std::string name, get_gain_names()){ -        //get the min, max, step for this gain name -        gain_range_t gain = get_named_prop<gain_range_t>(_props.range, name); - -        //clip g to be within the allowed range -        float g = std::min(std::max(gain_val, gain.min), gain.max); -        //set g to be a multiple of the step size -        g -= std::fmod(g, gain.step); -        //set g to be the new gain -        _link[named_prop_t(_props.value, name)] = g; -        //subtract g out of the total gain left to apply -        gain_val -= g; -    } - -    return true; -} diff --git a/host/test/CMakeLists.txt b/host/test/CMakeLists.txt index 1b909aa39..c620fd641 100644 --- a/host/test/CMakeLists.txt +++ b/host/test/CMakeLists.txt @@ -26,7 +26,7 @@ ADD_EXECUTABLE(main_test      convert_types_test.cpp      dict_test.cpp      error_test.cpp -    gain_handler_test.cpp +    gain_group_test.cpp      subdev_spec_test.cpp      tune_helper_test.cpp      vrt_test.cpp diff --git a/host/test/gain_group_test.cpp b/host/test/gain_group_test.cpp new file mode 100644 index 000000000..6a6af8eb2 --- /dev/null +++ b/host/test/gain_group_test.cpp @@ -0,0 +1,122 @@ +// +// 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/test/unit_test.hpp> +#include <uhd/utils/gain_group.hpp> +#include <boost/bind.hpp> +#include <boost/math/special_functions/round.hpp> +#include <iostream> + +#define rint(x) boost::math::iround(x) + +using namespace uhd; + +/*********************************************************************** + * Define gain element classes with needed functions + **********************************************************************/ +class gain_element1{ +public: + +    gain_range_t get_range(void){ +        return gain_range_t(0, 90, 1); +    } + +    float get_value(void){ +        return _gain; +    } + +    void set_value(float gain){ +        float step = get_range().step; +        _gain = step*rint(gain/step); +    } + +private: +    float _gain; +}; + +class gain_element2{ +public: + +    gain_range_t get_range(void){ +        return gain_range_t(-20, 10, 0.1); +    } + +    float get_value(void){ +        return _gain; +    } + +    void set_value(float gain){ +        float step = get_range().step; +        _gain = step*rint(gain/step); +    } + +private: +    float _gain; +}; + +//create static instances of gain elements to be shared by the tests +static gain_element1 g1; +static gain_element2 g2; + +static gain_group::sptr get_gain_group(size_t pri1 = 0, size_t pri2 = 0){ +    //create instance of gain group +    gain_fcns_t gain_fcns; +    gain_group::sptr gg(gain_group::make()); + +    //load gain group with function sets +    gain_fcns.get_range = boost::bind(&gain_element1::get_range, &g1); +    gain_fcns.get_value = boost::bind(&gain_element1::get_value, &g1); +    gain_fcns.set_value = boost::bind(&gain_element1::set_value, &g1, _1); +    gg->register_fcns(gain_fcns, pri1); + +    gain_fcns.get_range = boost::bind(&gain_element2::get_range, &g2); +    gain_fcns.get_value = boost::bind(&gain_element2::get_value, &g2); +    gain_fcns.set_value = boost::bind(&gain_element2::set_value, &g2, _1); +    gg->register_fcns(gain_fcns, pri2); + +    return gg; +} + +/*********************************************************************** + * Test cases + **********************************************************************/ +static const double tolerance = 0.001; + +BOOST_AUTO_TEST_CASE(test_gain_group_overall){ +    gain_group::sptr gg = get_gain_group(); + +    //test the overall stuff +    gg->set_value(80); +    BOOST_CHECK_CLOSE(gg->get_value(), float(80), tolerance); +    BOOST_CHECK_CLOSE(gg->get_range().min, float(-20), tolerance); +    BOOST_CHECK_CLOSE(gg->get_range().max, float(100), tolerance); +    BOOST_CHECK_CLOSE(gg->get_range().step, float(0.1), tolerance); +} + +BOOST_AUTO_TEST_CASE(test_gain_group_priority){ +    gain_group::sptr gg = get_gain_group(0, 1); + +    //test the overall stuff +    gg->set_value(80); +    BOOST_CHECK_CLOSE(gg->get_value(), float(80), tolerance); +    BOOST_CHECK_CLOSE(gg->get_range().min, float(-20), tolerance); +    BOOST_CHECK_CLOSE(gg->get_range().max, float(100), tolerance); +    BOOST_CHECK_CLOSE(gg->get_range().step, float(0.1), tolerance); + +    //test the the higher priority gain got filled first (gain 2) +    BOOST_CHECK_CLOSE(g2.get_value(), g2.get_range().max, tolerance); +} diff --git a/host/test/gain_handler_test.cpp b/host/test/gain_handler_test.cpp deleted file mode 100644 index 5a9f2b714..000000000 --- a/host/test/gain_handler_test.cpp +++ /dev/null @@ -1,121 +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 <boost/test/unit_test.hpp> -#include <uhd/utils/gain_handler.hpp> -#include <uhd/types/ranges.hpp> -#include <uhd/types/dict.hpp> -#include <uhd/utils/props.hpp> -#include <boost/bind.hpp> -#include <iostream> - -using namespace uhd; - -enum prop_t{ -    PROP_GAIN_VALUE, -    PROP_GAIN_RANGE, -    PROP_GAIN_NAMES -}; - -class gainful_obj : public wax::obj{ -public: -    gainful_obj(void){ -        //initialize gain props struct -        gain_handler::props_t gain_props; -        gain_props.value = PROP_GAIN_VALUE; -        gain_props.range = PROP_GAIN_RANGE; -        gain_props.names = PROP_GAIN_NAMES; -        //make a new gain handler -        _gain_handler = gain_handler::make( -            this->get_link(), gain_props, -            boost::bind(&gain_handler::is_equal<prop_t>, _1, _2) -        ); -        _gain_values["g0"] = 0; -        _gain_values["g1"] = 0; -        _gain_ranges["g0"] = gain_range_t(-10, 0, float(.1)); -        _gain_ranges["g1"] = gain_range_t(0, 100, float(1.5)); -    } - -    ~gainful_obj(void){} - -private: -    void get(const wax::obj &key_, wax::obj &val){ -        if (_gain_handler->intercept_get(key_, val)) return; - -        wax::obj key; std::string name; -        boost::tie(key, name) = extract_named_prop(key_); - -        //handle the get request conditioned on the key -        switch(key.as<prop_t>()){ -        case PROP_GAIN_VALUE: -            val = _gain_values[name]; -            return; - -        case PROP_GAIN_RANGE: -            val = _gain_ranges[name]; -            return; - -        case PROP_GAIN_NAMES: -            val = _gain_values.keys(); -            return; - -        default: UHD_THROW_PROP_GET_ERROR(); -        } -    } - -    void set(const wax::obj &key_, const wax::obj &val){ -        if (_gain_handler->intercept_set(key_, val)) return; - -        wax::obj key; std::string name; -        boost::tie(key, name) = extract_named_prop(key_); - -        //handle the get request conditioned on the key -        switch(key.as<prop_t>()){ -        case PROP_GAIN_VALUE: -            _gain_values[name] = val.as<float>(); -            return; - -        default: UHD_THROW_PROP_SET_ERROR(); -        } -    } - -    gain_handler::sptr _gain_handler; -    uhd::dict<std::string, float> _gain_values; -    uhd::dict<std::string, gain_range_t> _gain_ranges; - -}; - -BOOST_AUTO_TEST_CASE(test_gain_handler){ -    std::cout << "Testing the gain handler..." << std::endl; -    gainful_obj go0; - -    BOOST_CHECK_THROW( -        go0[named_prop_t(PROP_GAIN_VALUE, "fail")].as<float>(), -        std::exception -    ); - -    std::cout << "verifying the overall min, max, step" << std::endl; -    gain_range_t gain = go0[PROP_GAIN_RANGE].as<gain_range_t>(); -    BOOST_CHECK_EQUAL(gain.min, float(-10)); -    BOOST_CHECK_EQUAL(gain.max, float(100)); -    BOOST_CHECK_EQUAL(gain.step, float(1.5)); - -    std::cout << "verifying the overall gain" << std::endl; -    go0[named_prop_t(PROP_GAIN_VALUE, "g0")] = float(-5); -    go0[named_prop_t(PROP_GAIN_VALUE, "g1")] = float(30); -    BOOST_CHECK_EQUAL(go0[PROP_GAIN_VALUE].as<float>(), float(25)); -} diff --git a/host/utils/uhd_usrp_probe.cpp b/host/utils/uhd_usrp_probe.cpp index 1b73b5788..097317516 100644 --- a/host/utils/uhd_usrp_probe.cpp +++ b/host/utils/uhd_usrp_probe.cpp @@ -21,6 +21,7 @@  #include <uhd/usrp/device_props.hpp>  #include <uhd/usrp/mboard_props.hpp>  #include <uhd/usrp/dboard_props.hpp> +#include <uhd/usrp/codec_props.hpp>  #include <uhd/usrp/dsp_props.hpp>  #include <uhd/usrp/subdev_props.hpp>  #include <uhd/usrp/dboard_id.hpp> @@ -88,12 +89,25 @@ static std::string get_subdev_pp_string(const std::string &type, wax::obj subdev          ss << boost::format("Gain range %s: %.1f to %.1f step %.1f dB") % gain_name % gain_range.min % gain_range.max % gain_range.step << std::endl;      } -    ss << boost::format("Connection Type: %c") % (subdev[usrp::SUBDEV_PROP_CONNECTION].as<usrp::subdev_conn_t>()) << std::endl; +    ss << boost::format("Connection Type: %c") % char(subdev[usrp::SUBDEV_PROP_CONNECTION].as<usrp::subdev_conn_t>()) << std::endl;      ss << boost::format("Uses LO offset: %s") % (subdev[usrp::SUBDEV_PROP_USE_LO_OFFSET].as<bool>()? "Yes" : "No") << std::endl;      return ss.str();  } +static std::string get_codec_pp_string(const std::string &type, wax::obj codec){ +    std::stringstream ss; +    ss << boost::format("%s Codec: %s") % type % codec[usrp::CODEC_PROP_NAME].as<std::string>() << std::endl; +    //ss << std::endl; +    prop_names_t gain_names(codec[usrp::CODEC_PROP_GAIN_NAMES].as<prop_names_t>()); +    if (gain_names.size() == 0) ss << "Gain Elements: None" << std::endl; +    BOOST_FOREACH(const std::string &gain_name, gain_names){ +        gain_range_t gain_range(codec[named_prop_t(usrp::CODEC_PROP_GAIN_RANGE, gain_name)].as<gain_range_t>()); +        ss << boost::format("Gain range %s: %.1f to %.1f step %.1f dB") % gain_name % gain_range.min % gain_range.max % gain_range.step << std::endl; +    } +    return ss.str(); +} +  static std::string get_dboard_pp_string(const std::string &type, wax::obj dboard){      std::stringstream ss;      ss << boost::format("%s Dboard: %s") % type % dboard[usrp::DBOARD_PROP_NAME].as<std::string>() << std::endl; @@ -101,6 +115,7 @@ static std::string get_dboard_pp_string(const std::string &type, wax::obj dboard      BOOST_FOREACH(const std::string &subdev_name, dboard[usrp::DBOARD_PROP_SUBDEV_NAMES].as<prop_names_t>()){          ss << make_border(get_subdev_pp_string(type, dboard[named_prop_t(usrp::DBOARD_PROP_SUBDEV, subdev_name)]));      } +    ss << make_border(get_codec_pp_string(type, dboard[usrp::DBOARD_PROP_CODEC]));      return ss.str();  } | 
