diff options
Diffstat (limited to 'host/lib')
27 files changed, 1442 insertions, 592 deletions
| diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt index 46cce729e..323b69b14 100644 --- a/host/lib/CMakeLists.txt +++ b/host/lib/CMakeLists.txt @@ -20,14 +20,13 @@  ########################################################################  SET(libuhd_sources      device.cpp -    device_addr.cpp      gain_handler.cpp      load_modules.cpp -    metadata.cpp      simple_device.cpp -    time_spec.cpp +    tune_helper.cpp      types.cpp      wax.cpp +    transport/if_addrs.cpp      transport/udp_simple.cpp      transport/vrt.cpp      usrp/dboard/basic.cpp @@ -83,22 +82,42 @@ ENDIF(HAS_USRP1E_REQUIRED_HEADERS)  ########################################################################  # Setup defines for module loading  ######################################################################## -INCLUDE(CheckIncludeFileCXX) +MESSAGE(STATUS "Configuring module loading...") +INCLUDE(CheckIncludeFileCXX)  CHECK_INCLUDE_FILE_CXX(dlfcn.h HAVE_DLFCN_H) -CHECK_INCLUDE_FILE_CXX(Winbase.h HAVE_WINBASE_H) +CHECK_INCLUDE_FILE_CXX(windows.h HAVE_WINDOWS_H)  IF(HAVE_DLFCN_H) -    MESSAGE(STATUS "Module loading supported through dlopen...") +    MESSAGE(STATUS "  Module loading supported through dlopen.")      ADD_DEFINITIONS(-DHAVE_DLFCN_H) -ELSEIF(HAVE_WINBASE_H) -    MESSAGE(STATUS "Module loading supported through LoadLibrary...") -    ADD_DEFINITIONS(-DHAVE_WINBASE_H) +ELSEIF(HAVE_WINDOWS_H) +    MESSAGE(STATUS "  Module loading supported through LoadLibrary.") +    ADD_DEFINITIONS(-DHAVE_WINDOWS_H)  ELSE(HAVE_DLFCN_H) -    MESSAGE(STATUS "Module loading not supported...") +    MESSAGE(STATUS "  Module loading not supported.")  ENDIF(HAVE_DLFCN_H)  ######################################################################## +# Setup defines for interface address discovery +######################################################################## +MESSAGE(STATUS "Configuring interface address discovery...") + +INCLUDE(CheckIncludeFileCXX) +CHECK_INCLUDE_FILE_CXX(ifaddrs.h HAVE_IFADDRS_H) +CHECK_INCLUDE_FILE_CXX(winsock2.h HAVE_WINSOCK2_H) + +IF(HAVE_IFADDRS_H) +    MESSAGE(STATUS "  Interface address discovery supported through getifaddrs.") +    ADD_DEFINITIONS(-DHAVE_IFADDRS_H) +ELSEIF(HAVE_WINSOCK2_H) +    MESSAGE(STATUS "  Interface address discovery supported through SIO_GET_INTERFACE_LIST.") +    ADD_DEFINITIONS(-DHAVE_WINSOCK2_H) +ELSE(HAVE_IFADDRS_H) +    MESSAGE(STATUS "  Interface address discovery not supported.") +ENDIF(HAVE_IFADDRS_H) + +########################################################################  # Setup libuhd library  ########################################################################  ADD_LIBRARY(uhd SHARED ${libuhd_sources}) diff --git a/host/lib/device.cpp b/host/lib/device.cpp index cd8a01ab4..27a365d34 100644 --- a/host/lib/device.cpp +++ b/host/lib/device.cpp @@ -16,8 +16,9 @@  //  #include <uhd/device.hpp> -#include <uhd/dict.hpp> -#include <uhd/utils.hpp> +#include <uhd/types/dict.hpp> +#include <uhd/utils/assert.hpp> +#include <uhd/utils/static.hpp>  #include <boost/foreach.hpp>  #include <boost/format.hpp>  #include <boost/weak_ptr.hpp> @@ -46,7 +47,7 @@ static size_t hash_device_addr(      //combine the hashes of sorted keys/value pairs      size_t hash = 0; -    BOOST_FOREACH(std::string key, keys){ +    BOOST_FOREACH(const std::string &key, keys){          boost::hash_combine(hash, key);          boost::hash_combine(hash, dev_addr[key]);      } @@ -56,26 +57,26 @@ static size_t hash_device_addr(  /***********************************************************************   * Registration   **********************************************************************/ -typedef boost::tuple<device::discover_t, device::make_t> dev_fcn_reg_t; +typedef boost::tuple<device::find_t, device::make_t> dev_fcn_reg_t;  // instantiate the device function registry container -STATIC_INSTANCE(std::vector<dev_fcn_reg_t>, get_dev_fcn_regs) +UHD_SINGLETON_FCN(std::vector<dev_fcn_reg_t>, get_dev_fcn_regs)  void device::register_device( -    const discover_t &discover, +    const find_t &find,      const make_t &make  ){      //std::cout << "registering device" << std::endl; -    get_dev_fcn_regs().push_back(dev_fcn_reg_t(discover, make)); +    get_dev_fcn_regs().push_back(dev_fcn_reg_t(find, make));  }  /***********************************************************************   * Discover   **********************************************************************/ -device_addrs_t device::discover(const device_addr_t &hint){ +device_addrs_t device::find(const device_addr_t &hint){      device_addrs_t device_addrs; -    BOOST_FOREACH(dev_fcn_reg_t fcn, get_dev_fcn_regs()){ +    BOOST_FOREACH(const dev_fcn_reg_t &fcn, get_dev_fcn_regs()){          device_addrs_t discovered_addrs = fcn.get<0>()(hint);          device_addrs.insert(              device_addrs.begin(), @@ -94,11 +95,11 @@ device::sptr device::make(const device_addr_t &hint, size_t which){      typedef boost::tuple<device_addr_t, make_t> dev_addr_make_t;      std::vector<dev_addr_make_t> dev_addr_makers; -    BOOST_FOREACH(dev_fcn_reg_t fcn, get_dev_fcn_regs()){ +    BOOST_FOREACH(const dev_fcn_reg_t &fcn, get_dev_fcn_regs()){          BOOST_FOREACH(device_addr_t dev_addr, fcn.get<0>()(hint)){              //copy keys that were in hint but not in dev_addr              //this way, we can pass additional transport arguments -            BOOST_FOREACH(std::string key, hint.get_keys()){ +            BOOST_FOREACH(const std::string &key, hint.get_keys()){                  if (not dev_addr.has_key(key)) dev_addr[key] = hint[key];              }              //append the discovered address and its factory function @@ -109,14 +110,14 @@ device::sptr device::make(const device_addr_t &hint, size_t which){      //check that we found any devices      if (dev_addr_makers.size() == 0){          throw std::runtime_error(str( -            boost::format("No devices found for ----->\n%s") % device_addr::to_string(hint) +            boost::format("No devices found for ----->\n%s") % hint.to_string()          ));      }      //check that the which index is valid      if (dev_addr_makers.size() <= which){          throw std::runtime_error(str( -            boost::format("No device at index %d for ----->\n%s") % which % device_addr::to_string(hint) +            boost::format("No device at index %d for ----->\n%s") % which % hint.to_string()          ));      } @@ -136,7 +137,7 @@ device::sptr device::make(const device_addr_t &hint, size_t which){          return hash_to_device[dev_hash].lock();      }      //create and register a new device -    catch(const std::assert_error &){ +    catch(const uhd::assert_error &){          device::sptr dev = maker(dev_addr);          hash_to_device[dev_hash] = dev;          return dev; diff --git a/host/lib/device_addr.cpp b/host/lib/device_addr.cpp deleted file mode 100644 index d26bb4b9d..000000000 --- a/host/lib/device_addr.cpp +++ /dev/null @@ -1,86 +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/device_addr.hpp> -#include <sstream> -#include <cstring> -#include <stdexcept> -#include <boost/format.hpp> -#include <boost/algorithm/string.hpp> -#include <boost/foreach.hpp> - -//----------------------- u2 mac addr wrapper ------------------------// -uhd::mac_addr_t::mac_addr_t(const std::string &mac_addr_str_){ -    std::string mac_addr_str = (mac_addr_str_ == "")? "ff:ff:ff:ff:ff:ff" : mac_addr_str_; - -    //ether_aton_r(str.c_str(), &mac_addr); -    boost::uint8_t p[6] = {0x00, 0x50, 0xC2, 0x85, 0x30, 0x00}; // Matt's IAB - -    try{ -        //only allow patterns of xx:xx or xx:xx:xx:xx:xx:xx -        //the IAB above will fill in for the shorter pattern -        if (mac_addr_str.size() != 5 and mac_addr_str.size() != 17) -            throw std::runtime_error("expected exactly 5 or 17 characters"); - -        //split the mac addr hex string at the colons -        std::vector<std::string> hex_strs; -        boost::split(hex_strs, mac_addr_str, boost::is_any_of(":")); -        for (size_t i = 0; i < hex_strs.size(); i++){ -            int hex_num; -            std::istringstream iss(hex_strs[i]); -            iss >> std::hex >> hex_num; -            p[i] = boost::uint8_t(hex_num); -        } - -    } -    catch(std::exception const& e){ -        throw std::runtime_error(str( -            boost::format("Invalid mac address: %s\n\t%s") % mac_addr_str % e.what() -        )); -    } - -    memcpy(&mac_addr, p, sizeof(mac_addr)); -} - -std::string uhd::mac_addr_t::to_string(void) const{ -    //ether_ntoa_r(&mac_addr, addr_buf); -    const boost::uint8_t *p = reinterpret_cast<const boost::uint8_t *>(&mac_addr); -    return str( -        boost::format("%02x:%02x:%02x:%02x:%02x:%02x") -        % int(p[0]) % int(p[1]) % int(p[2]) -        % int(p[3]) % int(p[4]) % int(p[5]) -    ); -} - -std::ostream& operator<<(std::ostream &os, const uhd::mac_addr_t &x){ -    os << x.to_string(); -    return os; -} - -//----------------------- usrp device_addr_t wrapper -------------------------// -std::string uhd::device_addr::to_string(const uhd::device_addr_t &device_addr){ -    std::stringstream ss; -    BOOST_FOREACH(std::string key, device_addr.get_keys()){ -        ss << boost::format("%s: %s") % key % device_addr[key] << std::endl; -    } -    return ss.str(); -} - -std::ostream& operator<<(std::ostream &os, const uhd::device_addr_t &device_addr){ -    os << uhd::device_addr::to_string(device_addr); -    return os; -} diff --git a/host/lib/gain_handler.cpp b/host/lib/gain_handler.cpp index 7dd1547cb..daf629f0b 100644 --- a/host/lib/gain_handler.cpp +++ b/host/lib/gain_handler.cpp @@ -15,9 +15,9 @@  // along with this program.  If not, see <http://www.gnu.org/licenses/>.  // -#include <uhd/gain_handler.hpp> -#include <uhd/utils.hpp> -#include <uhd/types.hpp> +#include <uhd/utils/gain_handler.hpp> +#include <uhd/utils/assert.hpp> +#include <uhd/types/ranges.hpp>  #include <uhd/props.hpp>  #include <boost/assign/list_of.hpp>  #include <boost/foreach.hpp> @@ -47,7 +47,7 @@ private:      is_equal_t   _is_equal;      prop_names_t get_gain_names(void); -    gain_t get_overall_gain_val(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>(); @@ -90,21 +90,21 @@ prop_names_t gain_handler_impl::get_gain_names(void){      return _link[_props.names].as<prop_names_t>();  } -gain_t gain_handler_impl::get_overall_gain_val(void){ -    gain_t gain_val = 0; +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<gain_t>(_props.value, name); +        gain_val += get_named_prop<float>(_props.value, name);      }      return gain_val;  }  gain_range_t gain_handler_impl::get_overall_gain_range(void){ -    gain_t gain_min = 0, gain_max = 0, gain_step = 0; +    float gain_min = 0, gain_max = 0, gain_step = 0;      BOOST_FOREACH(std::string name, get_gain_names()){ -        gain_range_t gain_tmp = get_named_prop<gain_range_t>(_props.range, name); -        gain_min += gain_tmp.min; -        gain_max += gain_tmp.max; -        gain_step = std::max(gain_step, gain_tmp.step); +        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);  } @@ -145,7 +145,7 @@ bool gain_handler_impl::intercept_set(const wax::obj &key_, const wax::obj &val)      //not a gain value key... dont handle      if (not _is_equal(key, _props.value)) return false; -    gain_t gain_val = val.as<gain_t>(); +    float gain_val = val.as<float>();      //not a wildcard... dont handle (but check name and range)      if (name != ""){ @@ -164,7 +164,7 @@ bool gain_handler_impl::intercept_set(const wax::obj &key_, const wax::obj &val)          gain_range_t gain = get_named_prop<gain_range_t>(_props.range, name);          //clip g to be within the allowed range -        gain_t g = std::min(std::max(gain_val, gain.min), gain.max); +        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 diff --git a/host/lib/load_modules.cpp b/host/lib/load_modules.cpp index 700afcd3f..babff1ca5 100644 --- a/host/lib/load_modules.cpp +++ b/host/lib/load_modules.cpp @@ -15,7 +15,7 @@  // along with this program.  If not, see <http://www.gnu.org/licenses/>.  // -#include <uhd/utils.hpp> +#include <uhd/utils/static.hpp>  #include <boost/format.hpp>  #include <boost/foreach.hpp>  #include <boost/algorithm/string.hpp> @@ -40,8 +40,8 @@ static void load_module(const std::string &file_name){      }  } -#elif HAVE_WINBASE_H -#include <Winbase.h> +#elif HAVE_WINDOWS_H +#include <windows.h>  static void load_module(const std::string &file_name){      if (LoadLibrary(file_name.c_str()) == NULL){ @@ -101,7 +101,7 @@ static void load_path(const fs::path &path){   * Load all the modules given by the module path enviroment variable.   * The path variable may be several paths split by path separators.   */ -STATIC_BLOCK(load_modules){ +UHD_STATIC_BLOCK(load_modules){      //get the environment variable module path      char *env_module_path = std::getenv("UHD_MODULE_PATH");      if (env_module_path == NULL) return; diff --git a/host/lib/metadata.cpp b/host/lib/metadata.cpp deleted file mode 100644 index 40fdb7c73..000000000 --- a/host/lib/metadata.cpp +++ /dev/null @@ -1,37 +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/metadata.hpp> - -using namespace uhd; - -rx_metadata_t::rx_metadata_t(void){ -    stream_id = 0; -    has_stream_id = false; -    time_spec = time_spec_t(); -    has_time_spec = false; -    is_fragment = false; -} - -tx_metadata_t::tx_metadata_t(void){ -    stream_id = 0; -    has_stream_id = false; -    time_spec = time_spec_t(); -    has_time_spec = false; -    start_of_burst = false; -    end_of_burst = false; -} diff --git a/host/lib/simple_device.cpp b/host/lib/simple_device.cpp index ba1966e0d..25beb45a9 100644 --- a/host/lib/simple_device.cpp +++ b/host/lib/simple_device.cpp @@ -16,11 +16,9 @@  //  #include <uhd/simple_device.hpp> -#include <uhd/device.hpp> -#include <uhd/utils.hpp> +#include <uhd/utils/tune_helper.hpp> +#include <uhd/utils/assert.hpp>  #include <uhd/props.hpp> -#include <uhd/types.hpp> -#include <boost/algorithm/string.hpp>  #include <boost/foreach.hpp>  #include <boost/format.hpp>  #include <stdexcept> @@ -28,89 +26,8 @@  using namespace uhd;  /*********************************************************************** - * 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 = subdev[SUBDEV_PROP_QUADRATURE].as<bool>(); -    bool subdev_spectrum_inverted = subdev[SUBDEV_PROP_SPECTRUM_INVERTED].as<bool>(); -    wax::obj dxc_freq_proxy = dxc[std::string("freq")]; -    double dxc_sample_rate = dxc[std::string("rate")].as<double>(); - -    // Ask the d'board to tune as closely as it can to target_freq+lo_offset -    double target_inter_freq = target_freq + lo_offset; -    subdev_freq_proxy = target_inter_freq; -    double actual_inter_freq = subdev_freq_proxy.as<double>(); - -    // 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 = dxc_freq_proxy.as<double>(); - -    //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, decerps.as<std::vector<size_t> >()){ @@ -154,42 +71,42 @@ public:      }      /******************************************************************* -     * Streaming +     * Timing       ******************************************************************/ -    void set_streaming(bool enb){ -        _rx_ddc[std::string("enabled")] = enb; +    void set_time_now(const time_spec_t &time_spec){ +        _mboard[MBOARD_PROP_TIME_NOW] = time_spec;      } -    bool get_streaming(void){ -        return _rx_ddc[std::string("enabled")].as<bool>(); +    void set_time_next_pps(const time_spec_t &time_spec){ +        _mboard[MBOARD_PROP_TIME_NEXT_PPS] = time_spec; +    } + +    /******************************************************************* +     * Streaming +     ******************************************************************/ +    void issue_stream_cmd(const stream_cmd_t &stream_cmd){ +        _rx_ddc[std::string("stream_cmd")] = stream_cmd;      }      /*******************************************************************       * RX methods       ******************************************************************/      void set_rx_rate(double rate){ -        double samp_rate = _rx_ddc[std::string("rate")].as<double>(); +        double samp_rate = _rx_ddc[std::string("if_rate")].as<double>();          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 = _rx_ddc[std::string("rate")].as<double>(); -        size_t decim = _rx_ddc[std::string("decim")].as<size_t>(); -        return samp_rate/decim; +        return _rx_ddc[std::string("bb_rate")].as<double>();      }      std::vector<double> get_rx_rates(void){ -        return get_xx_rates(_rx_ddc[std::string("decims")], _rx_ddc[std::string("rate")]); +        return get_xx_rates(_rx_ddc[std::string("decims")], _rx_ddc[std::string("if_rate")]);      }      tune_result_t set_rx_freq(double target_freq){ -        double lo_offset = 0.0; -        //if the local oscillator will be in the passband, use an offset -        if (_rx_subdev[SUBDEV_PROP_LO_INTERFERES].as<bool>()){ -            lo_offset = get_rx_rate()*2.0; -        } -        return tune(target_freq, lo_offset, _rx_subdev, _rx_ddc, false/* not tx */); +        return tune_rx_subdev_and_ddc(_rx_subdev, _rx_ddc, target_freq);      }      freq_range_t get_rx_freq_range(void){ @@ -201,7 +118,7 @@ public:      }      float get_rx_gain(void){ -        return _rx_subdev[SUBDEV_PROP_GAIN].as<gain_t>(); +        return _rx_subdev[SUBDEV_PROP_GAIN].as<float>();      }      gain_range_t get_rx_gain_range(void){ @@ -224,28 +141,21 @@ public:       * TX methods       ******************************************************************/      void set_tx_rate(double rate){ -        double samp_rate = _tx_duc[std::string("rate")].as<double>(); +        double samp_rate = _tx_duc[std::string("if_rate")].as<double>();          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 = _tx_duc[std::string("rate")].as<double>(); -        size_t interp = _tx_duc[std::string("interp")].as<size_t>(); -        return samp_rate/interp; +        return _tx_duc[std::string("bb_rate")].as<double>();      }      std::vector<double> get_tx_rates(void){ -        return get_xx_rates(_tx_duc[std::string("interps")], _tx_duc[std::string("rate")]); +        return get_xx_rates(_tx_duc[std::string("interps")], _tx_duc[std::string("if_rate")]);      }      tune_result_t set_tx_freq(double target_freq){ -        double lo_offset = 0.0; -        //if the local oscillator will be in the passband, use an offset -        if (_tx_subdev[SUBDEV_PROP_LO_INTERFERES].as<bool>()){ -            lo_offset = get_tx_rate()*2.0; -        } -        return tune(target_freq, lo_offset, _tx_subdev, _tx_duc, true/* is tx */); +        return tune_tx_subdev_and_duc(_tx_subdev, _tx_duc, target_freq);      }      freq_range_t get_tx_freq_range(void){ @@ -257,7 +167,7 @@ public:      }      float get_tx_gain(void){ -        return _tx_subdev[SUBDEV_PROP_GAIN].as<gain_t>(); +        return _tx_subdev[SUBDEV_PROP_GAIN].as<float>();      }      gain_range_t get_tx_gain_range(void){ @@ -289,5 +199,5 @@ private:   * The Make Function   **********************************************************************/  simple_device::sptr simple_device::make(const std::string &args){ -    return sptr(new simple_device_impl(args_to_device_addr(args))); +    return sptr(new simple_device_impl(device_addr_t::from_args_str(args)));  } diff --git a/host/lib/time_spec.cpp b/host/lib/time_spec.cpp deleted file mode 100644 index 210010394..000000000 --- a/host/lib/time_spec.cpp +++ /dev/null @@ -1,40 +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/time_spec.hpp> - -using namespace uhd; - -time_spec_t::time_spec_t(void){ -    secs = ~0; -    ticks = ~0; -} - -time_spec_t::time_spec_t(boost::uint32_t new_secs, boost::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 = double(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 = boost::uint32_t(td.total_seconds()); -    double time_ticks_per_device_ticks = time_tick_rate/tick_rate; -    ticks = boost::uint32_t(td.fractional_seconds()/time_ticks_per_device_ticks); -} diff --git a/host/lib/transport/gen_vrt.py b/host/lib/transport/gen_vrt.py new file mode 100755 index 000000000..918de3ad7 --- /dev/null +++ b/host/lib/transport/gen_vrt.py @@ -0,0 +1,206 @@ +#!/usr/bin/env python +# +# 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/>. +# + +""" +The vrt packer/unpacker code generator: + +This script will generate the pack and unpack routines that convert +metatdata into vrt headers and vrt headers into metadata. + +The generated code infers jump tables to speed-up the parsing time. +""" + +TMPL_TEXT = """ +#import time + +######################################################################## +## setup predicates +######################################################################## +#set $sid_p = 0b00001 +#set $cid_p = 0b00010 +#set $tsi_p = 0b00100 +#set $tsf_p = 0b01000 +#set $tlr_p = 0b10000 + +/*********************************************************************** + * This file was generated by $file on $time.strftime("%c") + **********************************************************************/ + +\#include <uhd/transport/vrt.hpp> +\#include <boost/asio.hpp> //endianness conversion +\#include <stdexcept> + +using namespace uhd; +using namespace uhd::transport; + +void vrt::pack( +    const tx_metadata_t &metadata, //input +    boost::uint32_t *header_buff,  //output +    size_t &num_header_words32,    //output +    size_t num_payload_words32,    //input +    size_t &num_packet_words32,    //output +    size_t packet_count            //input +){ +    boost::uint32_t vrt_hdr_flags; + +    boost::uint8_t pred = 0; +    if (metadata.has_stream_id) pred |= $hex($sid_p); +    if (metadata.has_time_spec) pred |= $hex($tsi_p | $tsf_p); + +    switch(pred){ +    #for $pred in range(2**5) +    case $pred: +        #set $num_header_words = 1 +        #set $flags = 0 +        ########## Stream ID ########## +        #if $pred & $sid_p +            header_buff[$num_header_words] = htonl(metadata.stream_id); +            #set $num_header_words += 1 +            #set $flags |= (0x1 << 28); +        #end if +        ########## Class ID ########## +        #if $pred & $cid_p +            header_buff[$num_header_words] = htonl(0); +            #set $num_header_words += 1 +            header_buff[$num_header_words] = htonl(0); +            #set $num_header_words += 1 +            #set $flags |= (0x1 << 27); +        #end if +        ########## Integer Time ########## +        #if $pred & $tsi_p +            header_buff[$num_header_words] = htonl(metadata.time_spec.secs); +            #set $num_header_words += 1 +            #set $flags |= (0x3 << 22); +        #end if +        ########## Fractional Time ########## +        #if $pred & $tsf_p +            header_buff[$num_header_words] = htonl(0); +            #set $num_header_words += 1 +            header_buff[$num_header_words] = htonl(metadata.time_spec.ticks); +            #set $num_header_words += 1 +            #set $flags |= (0x1 << 20); +        #end if +        ########## Trailer ########## +        #if $pred & $tlr_p +            #set $flags |= (0x1 << 26); +            #set $num_trailer_words = 1; +        #else +            #set $num_trailer_words = 0; +        #end if +        ########## Variables ########## +            num_header_words32 = $num_header_words; +            num_packet_words32 = $($num_header_words + $num_trailer_words) + num_payload_words32; +            vrt_hdr_flags = $hex($flags); +        break; +    #end for +    } + +    //set the burst flags +    if (metadata.start_of_burst) vrt_hdr_flags |= $hex(0x1 << 25); +    if (metadata.end_of_burst)   vrt_hdr_flags |= $hex(0x1 << 24); + +    //fill in complete header word +    header_buff[0] = htonl(vrt_hdr_flags | +        ((packet_count & 0xf) << 16) | +        (num_packet_words32 & 0xffff) +    ); +} + +void vrt::unpack( +    rx_metadata_t &metadata,            //output +    const boost::uint32_t *header_buff, //input +    size_t &num_header_words32,         //output +    size_t &num_payload_words32,        //output +    size_t num_packet_words32,          //input +    size_t &packet_count                //output +){ +    //clear the metadata +    metadata = rx_metadata_t(); + +    //extract vrt header +    boost::uint32_t vrt_hdr_word = ntohl(header_buff[0]); +    size_t packet_words32 = vrt_hdr_word & 0xffff; +    packet_count = (vrt_hdr_word >> 16) & 0xf; + +    //failure cases +    if (packet_words32 == 0 or num_packet_words32 < packet_words32) +        throw std::runtime_error("bad vrt header or packet fragment"); +    if (vrt_hdr_word & (0x7 << 29)) +        throw std::runtime_error("unsupported vrt packet type"); + +    boost::uint8_t pred = 0; +    if(vrt_hdr_word & $hex(0x1 << 28)) pred |= $hex($sid_p); +    if(vrt_hdr_word & $hex(0x1 << 27)) pred |= $hex($cid_p); +    if(vrt_hdr_word & $hex(0x3 << 22)) pred |= $hex($tsi_p); +    if(vrt_hdr_word & $hex(0x3 << 20)) pred |= $hex($tsf_p); +    if(vrt_hdr_word & $hex(0x1 << 26)) pred |= $hex($tlr_p); + +    switch(pred){ +    #for $pred in range(2**5) +    case $pred: +        #set $set_has_time_spec = False +        #set $num_header_words = 1 +        ########## Stream ID ########## +        #if $pred & $sid_p +            metadata.has_stream_id = true; +            metadata.stream_id = ntohl(header_buff[$num_header_words]); +            #set $num_header_words += 1 +        #end if +        ########## Class ID ########## +        #if $pred & $cid_p +            #set $num_header_words += 1 +            #set $num_header_words += 1 +        #end if +        ########## Integer Time ########## +        #if $pred & $tsi_p +            metadata.has_time_spec = true; +            #set $set_has_time_spec = True +            metadata.time_spec.secs = ntohl(header_buff[$num_header_words]); +            #set $num_header_words += 1 +        #end if +        ########## Fractional Time ########## +        #if $pred & $tsf_p +            #if not $set_has_time_spec +            metadata.has_time_spec = true; +                #set $set_has_time_spec = True +            #end if +            #set $num_header_words += 1 +            metadata.time_spec.ticks = ntohl(header_buff[$num_header_words]); +            #set $num_header_words += 1 +        #end if +        ########## Trailer ########## +        #if $pred & $tlr_p +            #set $num_trailer_words = 1; +        #else +            #set $num_trailer_words = 0; +        #end if +        ########## Variables ########## +            num_header_words32 = $num_header_words; +            num_payload_words32 = packet_words32 - $($num_header_words + $num_trailer_words); +        break; +    #end for +    } +} +""" + +from Cheetah import Template +def parse_str(_tmpl_text, **kwargs): return str(Template.Template(_tmpl_text, kwargs)) + +if __name__ == '__main__': +    from Cheetah import Template +    print parse_str(TMPL_TEXT, file=__file__) diff --git a/host/lib/transport/if_addrs.cpp b/host/lib/transport/if_addrs.cpp new file mode 100644 index 000000000..5c8c8a176 --- /dev/null +++ b/host/lib/transport/if_addrs.cpp @@ -0,0 +1,109 @@ +// +// 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/transport/if_addrs.hpp> +#include <boost/asio/ip/address_v4.hpp> +#include <boost/cstdint.hpp> +#include <iostream> + +uhd::transport::if_addrs_t::if_addrs_t(void){ +    /* NOP */ +} + +/*********************************************************************** + * Interface address discovery through ifaddrs api + **********************************************************************/ +#ifdef HAVE_IFADDRS_H +#include <ifaddrs.h> + +static boost::asio::ip::address_v4 sockaddr_to_ip_addr(sockaddr *addr){ +    return boost::asio::ip::address_v4(ntohl( +        reinterpret_cast<sockaddr_in*>(addr)->sin_addr.s_addr +    )); +} + +std::vector<uhd::transport::if_addrs_t> uhd::transport::get_if_addrs(void){ +    std::vector<if_addrs_t> if_addrs; +    struct ifaddrs *ifap; +    if (getifaddrs(&ifap) == 0){ +        for (struct ifaddrs *iter = ifap; iter != NULL; iter = iter->ifa_next){ +            //ensure that the entries are valid +            if (iter->ifa_addr->sa_family != AF_INET) continue; +            if (iter->ifa_netmask->sa_family != AF_INET) continue; +            if (iter->ifa_broadaddr->sa_family != AF_INET) continue; + +            //append a new set of interface addresses +            if_addrs_t if_addr; +            if_addr.inet = sockaddr_to_ip_addr(iter->ifa_addr).to_string(); +            if_addr.mask = sockaddr_to_ip_addr(iter->ifa_netmask).to_string(); +            if_addr.bcast = sockaddr_to_ip_addr(iter->ifa_broadaddr).to_string(); +            if_addrs.push_back(if_addr); +        } +        freeifaddrs(ifap); +    } +    return if_addrs; +} + +/*********************************************************************** + * Interface address discovery through windows api (TODO) + **********************************************************************/ +#elif HAVE_WINSOCK2_H +#include <winsock2.h> + +std::vector<uhd::transport::if_addrs_t> uhd::transport::get_if_addrs(void){ +    std::vector<if_addrs_t> if_addrs; +    SOCKET sd = WSASocket(AF_INET, SOCK_DGRAM, 0, 0, 0, 0); +    if (sd == SOCKET_ERROR) { +        std::cerr << "Failed to get a socket. Error " << WSAGetLastError() << +            std::endl; return if_addrs; +    } + +    INTERFACE_INFO InterfaceList[20]; +    unsigned long nBytesReturned; +    if (WSAIoctl(sd, SIO_GET_INTERFACE_LIST, 0, 0, &InterfaceList, +			sizeof(InterfaceList), &nBytesReturned, 0, 0) == SOCKET_ERROR) { +        std::cerr << "Failed calling WSAIoctl: error " << WSAGetLastError() << +				std::endl; +		return if_addrs; +    } + +    int nNumInterfaces = nBytesReturned / sizeof(INTERFACE_INFO); +    for (int i = 0; i < nNumInterfaces; ++i) { +        boost::uint32_t iiAddress = ntohl(reinterpret_cast<sockaddr_in&>(InterfaceList[i].iiAddress).sin_addr.s_addr); +        boost::uint32_t iiNetmask = ntohl(reinterpret_cast<sockaddr_in&>(InterfaceList[i].iiNetmask).sin_addr.s_addr); +        boost::uint32_t iiBroadcastAddress = (iiAddress & iiNetmask) | ~iiNetmask; + +        if_addrs_t if_addr; +        if_addr.inet = boost::asio::ip::address_v4(iiAddress).to_string(); +        if_addr.mask = boost::asio::ip::address_v4(iiNetmask).to_string(); +        if_addr.bcast = boost::asio::ip::address_v4(iiBroadcastAddress).to_string(); +        if_addrs.push_back(if_addr); +    } + +    return if_addrs; +} + +/*********************************************************************** + * Interface address discovery not included + **********************************************************************/ +#else /* HAVE_IFADDRS_H */ + +std::vector<uhd::transport::if_addrs_t> uhd::transport::get_if_addrs(void){ +    return std::vector<if_addrs_t>(); +} + +#endif /* HAVE_IFADDRS_H */ diff --git a/host/lib/transport/udp_simple.cpp b/host/lib/transport/udp_simple.cpp index 3c8ecb70d..f339127ad 100644 --- a/host/lib/transport/udp_simple.cpp +++ b/host/lib/transport/udp_simple.cpp @@ -16,6 +16,7 @@  //  #include <uhd/transport/udp_simple.hpp> +#include <boost/asio.hpp>  #include <boost/thread.hpp>  #include <boost/format.hpp>  #include <iostream> diff --git a/host/lib/transport/udp_zero_copy_asio.cpp b/host/lib/transport/udp_zero_copy_asio.cpp index 219ae8720..1fc8ce14a 100644 --- a/host/lib/transport/udp_zero_copy_asio.cpp +++ b/host/lib/transport/udp_zero_copy_asio.cpp @@ -17,6 +17,7 @@  #include <uhd/transport/udp_zero_copy.hpp>  #include <boost/cstdint.hpp> +#include <boost/asio.hpp>  #include <boost/thread.hpp>  #include <boost/format.hpp>  #include <iostream> @@ -115,7 +116,7 @@ smart_buffer::sptr udp_zero_copy_impl::recv(void){      //implement timeout through polling and sleeping      boost::asio::deadline_timer timer(_socket->get_io_service()); -    timer.expires_from_now(boost::posix_time::milliseconds(50)); +    timer.expires_from_now(boost::posix_time::milliseconds(100));      while (not ((available = _socket->available()) or timer.expires_from_now().is_negative())){          boost::this_thread::sleep(boost::posix_time::milliseconds(1));      } diff --git a/host/lib/transport/vrt.cpp b/host/lib/transport/vrt.cpp index a06b5bf21..bebca5db9 100644 --- a/host/lib/transport/vrt.cpp +++ b/host/lib/transport/vrt.cpp @@ -1,19 +1,9 @@ -// -// 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/>. -// + + + +/*********************************************************************** + * This file was generated by ./gen_vrt.py on Fri Mar 26 15:33:00 2010 + **********************************************************************/  #include <uhd/transport/vrt.hpp>  #include <boost/asio.hpp> //endianness conversion @@ -30,26 +20,274 @@ void vrt::pack(      size_t &num_packet_words32,    //output      size_t packet_count            //input  ){ -    boost::uint32_t vrt_hdr_flags = 0; -    num_header_words32 = 1; +    boost::uint32_t vrt_hdr_flags; -    //load the vrt header and flags -    if(metadata.has_stream_id){ -        vrt_hdr_flags |= (0x1 << 28); //IF Data packet with Stream Identifier -        header_buff[num_header_words32++] = htonl(metadata.stream_id); -    } +    boost::uint8_t pred = 0; +    if (metadata.has_stream_id) pred |= 0x1; +    if (metadata.has_time_spec) pred |= 0xc; -    if(metadata.has_time_spec){ -        vrt_hdr_flags |= (0x3 << 22) | (0x1 << 20); //TSI: Other, TSF: Sample Count Timestamp -        header_buff[num_header_words32++] = htonl(metadata.time_spec.secs); -        header_buff[num_header_words32++] = htonl(metadata.time_spec.ticks); -        header_buff[num_header_words32++] = 0; //unused part of fractional seconds +    switch(pred){ +    case 0: +            num_header_words32 = 1; +            num_packet_words32 = 1 + num_payload_words32; +            vrt_hdr_flags = 0x0; +        break; +    case 1: +            header_buff[1] = htonl(metadata.stream_id); +            num_header_words32 = 2; +            num_packet_words32 = 2 + num_payload_words32; +            vrt_hdr_flags = 0x10000000; +        break; +    case 2: +            header_buff[1] = htonl(0); +            header_buff[2] = htonl(0); +            num_header_words32 = 3; +            num_packet_words32 = 3 + num_payload_words32; +            vrt_hdr_flags = 0x8000000; +        break; +    case 3: +            header_buff[1] = htonl(metadata.stream_id); +            header_buff[2] = htonl(0); +            header_buff[3] = htonl(0); +            num_header_words32 = 4; +            num_packet_words32 = 4 + num_payload_words32; +            vrt_hdr_flags = 0x18000000; +        break; +    case 4: +            header_buff[1] = htonl(metadata.time_spec.secs); +            num_header_words32 = 2; +            num_packet_words32 = 2 + num_payload_words32; +            vrt_hdr_flags = 0xc00000; +        break; +    case 5: +            header_buff[1] = htonl(metadata.stream_id); +            header_buff[2] = htonl(metadata.time_spec.secs); +            num_header_words32 = 3; +            num_packet_words32 = 3 + num_payload_words32; +            vrt_hdr_flags = 0x10c00000; +        break; +    case 6: +            header_buff[1] = htonl(0); +            header_buff[2] = htonl(0); +            header_buff[3] = htonl(metadata.time_spec.secs); +            num_header_words32 = 4; +            num_packet_words32 = 4 + num_payload_words32; +            vrt_hdr_flags = 0x8c00000; +        break; +    case 7: +            header_buff[1] = htonl(metadata.stream_id); +            header_buff[2] = htonl(0); +            header_buff[3] = htonl(0); +            header_buff[4] = htonl(metadata.time_spec.secs); +            num_header_words32 = 5; +            num_packet_words32 = 5 + num_payload_words32; +            vrt_hdr_flags = 0x18c00000; +        break; +    case 8: +            header_buff[1] = htonl(0); +            header_buff[2] = htonl(metadata.time_spec.ticks); +            num_header_words32 = 3; +            num_packet_words32 = 3 + num_payload_words32; +            vrt_hdr_flags = 0x100000; +        break; +    case 9: +            header_buff[1] = htonl(metadata.stream_id); +            header_buff[2] = htonl(0); +            header_buff[3] = htonl(metadata.time_spec.ticks); +            num_header_words32 = 4; +            num_packet_words32 = 4 + num_payload_words32; +            vrt_hdr_flags = 0x10100000; +        break; +    case 10: +            header_buff[1] = htonl(0); +            header_buff[2] = htonl(0); +            header_buff[3] = htonl(0); +            header_buff[4] = htonl(metadata.time_spec.ticks); +            num_header_words32 = 5; +            num_packet_words32 = 5 + num_payload_words32; +            vrt_hdr_flags = 0x8100000; +        break; +    case 11: +            header_buff[1] = htonl(metadata.stream_id); +            header_buff[2] = htonl(0); +            header_buff[3] = htonl(0); +            header_buff[4] = htonl(0); +            header_buff[5] = htonl(metadata.time_spec.ticks); +            num_header_words32 = 6; +            num_packet_words32 = 6 + num_payload_words32; +            vrt_hdr_flags = 0x18100000; +        break; +    case 12: +            header_buff[1] = htonl(metadata.time_spec.secs); +            header_buff[2] = htonl(0); +            header_buff[3] = htonl(metadata.time_spec.ticks); +            num_header_words32 = 4; +            num_packet_words32 = 4 + num_payload_words32; +            vrt_hdr_flags = 0xd00000; +        break; +    case 13: +            header_buff[1] = htonl(metadata.stream_id); +            header_buff[2] = htonl(metadata.time_spec.secs); +            header_buff[3] = htonl(0); +            header_buff[4] = htonl(metadata.time_spec.ticks); +            num_header_words32 = 5; +            num_packet_words32 = 5 + num_payload_words32; +            vrt_hdr_flags = 0x10d00000; +        break; +    case 14: +            header_buff[1] = htonl(0); +            header_buff[2] = htonl(0); +            header_buff[3] = htonl(metadata.time_spec.secs); +            header_buff[4] = htonl(0); +            header_buff[5] = htonl(metadata.time_spec.ticks); +            num_header_words32 = 6; +            num_packet_words32 = 6 + num_payload_words32; +            vrt_hdr_flags = 0x8d00000; +        break; +    case 15: +            header_buff[1] = htonl(metadata.stream_id); +            header_buff[2] = htonl(0); +            header_buff[3] = htonl(0); +            header_buff[4] = htonl(metadata.time_spec.secs); +            header_buff[5] = htonl(0); +            header_buff[6] = htonl(metadata.time_spec.ticks); +            num_header_words32 = 7; +            num_packet_words32 = 7 + num_payload_words32; +            vrt_hdr_flags = 0x18d00000; +        break; +    case 16: +            num_header_words32 = 1; +            num_packet_words32 = 2 + num_payload_words32; +            vrt_hdr_flags = 0x4000000; +        break; +    case 17: +            header_buff[1] = htonl(metadata.stream_id); +            num_header_words32 = 2; +            num_packet_words32 = 3 + num_payload_words32; +            vrt_hdr_flags = 0x14000000; +        break; +    case 18: +            header_buff[1] = htonl(0); +            header_buff[2] = htonl(0); +            num_header_words32 = 3; +            num_packet_words32 = 4 + num_payload_words32; +            vrt_hdr_flags = 0xc000000; +        break; +    case 19: +            header_buff[1] = htonl(metadata.stream_id); +            header_buff[2] = htonl(0); +            header_buff[3] = htonl(0); +            num_header_words32 = 4; +            num_packet_words32 = 5 + num_payload_words32; +            vrt_hdr_flags = 0x1c000000; +        break; +    case 20: +            header_buff[1] = htonl(metadata.time_spec.secs); +            num_header_words32 = 2; +            num_packet_words32 = 3 + num_payload_words32; +            vrt_hdr_flags = 0x4c00000; +        break; +    case 21: +            header_buff[1] = htonl(metadata.stream_id); +            header_buff[2] = htonl(metadata.time_spec.secs); +            num_header_words32 = 3; +            num_packet_words32 = 4 + num_payload_words32; +            vrt_hdr_flags = 0x14c00000; +        break; +    case 22: +            header_buff[1] = htonl(0); +            header_buff[2] = htonl(0); +            header_buff[3] = htonl(metadata.time_spec.secs); +            num_header_words32 = 4; +            num_packet_words32 = 5 + num_payload_words32; +            vrt_hdr_flags = 0xcc00000; +        break; +    case 23: +            header_buff[1] = htonl(metadata.stream_id); +            header_buff[2] = htonl(0); +            header_buff[3] = htonl(0); +            header_buff[4] = htonl(metadata.time_spec.secs); +            num_header_words32 = 5; +            num_packet_words32 = 6 + num_payload_words32; +            vrt_hdr_flags = 0x1cc00000; +        break; +    case 24: +            header_buff[1] = htonl(0); +            header_buff[2] = htonl(metadata.time_spec.ticks); +            num_header_words32 = 3; +            num_packet_words32 = 4 + num_payload_words32; +            vrt_hdr_flags = 0x4100000; +        break; +    case 25: +            header_buff[1] = htonl(metadata.stream_id); +            header_buff[2] = htonl(0); +            header_buff[3] = htonl(metadata.time_spec.ticks); +            num_header_words32 = 4; +            num_packet_words32 = 5 + num_payload_words32; +            vrt_hdr_flags = 0x14100000; +        break; +    case 26: +            header_buff[1] = htonl(0); +            header_buff[2] = htonl(0); +            header_buff[3] = htonl(0); +            header_buff[4] = htonl(metadata.time_spec.ticks); +            num_header_words32 = 5; +            num_packet_words32 = 6 + num_payload_words32; +            vrt_hdr_flags = 0xc100000; +        break; +    case 27: +            header_buff[1] = htonl(metadata.stream_id); +            header_buff[2] = htonl(0); +            header_buff[3] = htonl(0); +            header_buff[4] = htonl(0); +            header_buff[5] = htonl(metadata.time_spec.ticks); +            num_header_words32 = 6; +            num_packet_words32 = 7 + num_payload_words32; +            vrt_hdr_flags = 0x1c100000; +        break; +    case 28: +            header_buff[1] = htonl(metadata.time_spec.secs); +            header_buff[2] = htonl(0); +            header_buff[3] = htonl(metadata.time_spec.ticks); +            num_header_words32 = 4; +            num_packet_words32 = 5 + num_payload_words32; +            vrt_hdr_flags = 0x4d00000; +        break; +    case 29: +            header_buff[1] = htonl(metadata.stream_id); +            header_buff[2] = htonl(metadata.time_spec.secs); +            header_buff[3] = htonl(0); +            header_buff[4] = htonl(metadata.time_spec.ticks); +            num_header_words32 = 5; +            num_packet_words32 = 6 + num_payload_words32; +            vrt_hdr_flags = 0x14d00000; +        break; +    case 30: +            header_buff[1] = htonl(0); +            header_buff[2] = htonl(0); +            header_buff[3] = htonl(metadata.time_spec.secs); +            header_buff[4] = htonl(0); +            header_buff[5] = htonl(metadata.time_spec.ticks); +            num_header_words32 = 6; +            num_packet_words32 = 7 + num_payload_words32; +            vrt_hdr_flags = 0xcd00000; +        break; +    case 31: +            header_buff[1] = htonl(metadata.stream_id); +            header_buff[2] = htonl(0); +            header_buff[3] = htonl(0); +            header_buff[4] = htonl(metadata.time_spec.secs); +            header_buff[5] = htonl(0); +            header_buff[6] = htonl(metadata.time_spec.ticks); +            num_header_words32 = 7; +            num_packet_words32 = 8 + num_payload_words32; +            vrt_hdr_flags = 0x1cd00000; +        break;      } -    vrt_hdr_flags |= (metadata.start_of_burst)? (0x1 << 25) : 0; -    vrt_hdr_flags |= (metadata.end_of_burst)?   (0x1 << 24) : 0; - -    num_packet_words32 = num_header_words32 + num_payload_words32; +    //set the burst flags +    if (metadata.start_of_burst) vrt_hdr_flags |= 0x2000000; +    if (metadata.end_of_burst)   vrt_hdr_flags |= 0x1000000;      //fill in complete header word      header_buff[0] = htonl(vrt_hdr_flags | @@ -80,30 +318,230 @@ void vrt::unpack(      if (vrt_hdr_word & (0x7 << 29))          throw std::runtime_error("unsupported vrt packet type"); -    //parse the header flags -    num_header_words32 = 1; - -    if (vrt_hdr_word & (0x1 << 28)){ //stream id -        metadata.has_stream_id = true; -        metadata.stream_id = ntohl(header_buff[num_header_words32++]); -    } - -    if (vrt_hdr_word & (0x1 << 27)){ //class id (we dont use) -        num_header_words32 += 2; -    } - -    if (vrt_hdr_word & (0x3 << 22)){ //integer time -        metadata.has_time_spec = true; -        metadata.time_spec.secs = ntohl(header_buff[num_header_words32++]); -    } +    boost::uint8_t pred = 0; +    if(vrt_hdr_word & 0x10000000) pred |= 0x1; +    if(vrt_hdr_word & 0x8000000) pred |= 0x2; +    if(vrt_hdr_word & 0xc00000) pred |= 0x4; +    if(vrt_hdr_word & 0x300000) pred |= 0x8; +    if(vrt_hdr_word & 0x4000000) pred |= 0x10; -    if (vrt_hdr_word & (0x3 << 20)){ //fractional time -        metadata.has_time_spec = true; -        metadata.time_spec.ticks = ntohl(header_buff[num_header_words32++]); -        num_header_words32++; //unused part of fractional seconds +    switch(pred){ +    case 0: +            num_header_words32 = 1; +            num_payload_words32 = packet_words32 - 1; +        break; +    case 1: +            metadata.has_stream_id = true; +            metadata.stream_id = ntohl(header_buff[1]); +            num_header_words32 = 2; +            num_payload_words32 = packet_words32 - 2; +        break; +    case 2: +            num_header_words32 = 3; +            num_payload_words32 = packet_words32 - 3; +        break; +    case 3: +            metadata.has_stream_id = true; +            metadata.stream_id = ntohl(header_buff[1]); +            num_header_words32 = 4; +            num_payload_words32 = packet_words32 - 4; +        break; +    case 4: +            metadata.has_time_spec = true; +            metadata.time_spec.secs = ntohl(header_buff[1]); +            num_header_words32 = 2; +            num_payload_words32 = packet_words32 - 2; +        break; +    case 5: +            metadata.has_stream_id = true; +            metadata.stream_id = ntohl(header_buff[1]); +            metadata.has_time_spec = true; +            metadata.time_spec.secs = ntohl(header_buff[2]); +            num_header_words32 = 3; +            num_payload_words32 = packet_words32 - 3; +        break; +    case 6: +            metadata.has_time_spec = true; +            metadata.time_spec.secs = ntohl(header_buff[3]); +            num_header_words32 = 4; +            num_payload_words32 = packet_words32 - 4; +        break; +    case 7: +            metadata.has_stream_id = true; +            metadata.stream_id = ntohl(header_buff[1]); +            metadata.has_time_spec = true; +            metadata.time_spec.secs = ntohl(header_buff[4]); +            num_header_words32 = 5; +            num_payload_words32 = packet_words32 - 5; +        break; +    case 8: +            metadata.has_time_spec = true; +            metadata.time_spec.ticks = ntohl(header_buff[2]); +            num_header_words32 = 3; +            num_payload_words32 = packet_words32 - 3; +        break; +    case 9: +            metadata.has_stream_id = true; +            metadata.stream_id = ntohl(header_buff[1]); +            metadata.has_time_spec = true; +            metadata.time_spec.ticks = ntohl(header_buff[3]); +            num_header_words32 = 4; +            num_payload_words32 = packet_words32 - 4; +        break; +    case 10: +            metadata.has_time_spec = true; +            metadata.time_spec.ticks = ntohl(header_buff[4]); +            num_header_words32 = 5; +            num_payload_words32 = packet_words32 - 5; +        break; +    case 11: +            metadata.has_stream_id = true; +            metadata.stream_id = ntohl(header_buff[1]); +            metadata.has_time_spec = true; +            metadata.time_spec.ticks = ntohl(header_buff[5]); +            num_header_words32 = 6; +            num_payload_words32 = packet_words32 - 6; +        break; +    case 12: +            metadata.has_time_spec = true; +            metadata.time_spec.secs = ntohl(header_buff[1]); +            metadata.time_spec.ticks = ntohl(header_buff[3]); +            num_header_words32 = 4; +            num_payload_words32 = packet_words32 - 4; +        break; +    case 13: +            metadata.has_stream_id = true; +            metadata.stream_id = ntohl(header_buff[1]); +            metadata.has_time_spec = true; +            metadata.time_spec.secs = ntohl(header_buff[2]); +            metadata.time_spec.ticks = ntohl(header_buff[4]); +            num_header_words32 = 5; +            num_payload_words32 = packet_words32 - 5; +        break; +    case 14: +            metadata.has_time_spec = true; +            metadata.time_spec.secs = ntohl(header_buff[3]); +            metadata.time_spec.ticks = ntohl(header_buff[5]); +            num_header_words32 = 6; +            num_payload_words32 = packet_words32 - 6; +        break; +    case 15: +            metadata.has_stream_id = true; +            metadata.stream_id = ntohl(header_buff[1]); +            metadata.has_time_spec = true; +            metadata.time_spec.secs = ntohl(header_buff[4]); +            metadata.time_spec.ticks = ntohl(header_buff[6]); +            num_header_words32 = 7; +            num_payload_words32 = packet_words32 - 7; +        break; +    case 16: +            num_header_words32 = 1; +            num_payload_words32 = packet_words32 - 2; +        break; +    case 17: +            metadata.has_stream_id = true; +            metadata.stream_id = ntohl(header_buff[1]); +            num_header_words32 = 2; +            num_payload_words32 = packet_words32 - 3; +        break; +    case 18: +            num_header_words32 = 3; +            num_payload_words32 = packet_words32 - 4; +        break; +    case 19: +            metadata.has_stream_id = true; +            metadata.stream_id = ntohl(header_buff[1]); +            num_header_words32 = 4; +            num_payload_words32 = packet_words32 - 5; +        break; +    case 20: +            metadata.has_time_spec = true; +            metadata.time_spec.secs = ntohl(header_buff[1]); +            num_header_words32 = 2; +            num_payload_words32 = packet_words32 - 3; +        break; +    case 21: +            metadata.has_stream_id = true; +            metadata.stream_id = ntohl(header_buff[1]); +            metadata.has_time_spec = true; +            metadata.time_spec.secs = ntohl(header_buff[2]); +            num_header_words32 = 3; +            num_payload_words32 = packet_words32 - 4; +        break; +    case 22: +            metadata.has_time_spec = true; +            metadata.time_spec.secs = ntohl(header_buff[3]); +            num_header_words32 = 4; +            num_payload_words32 = packet_words32 - 5; +        break; +    case 23: +            metadata.has_stream_id = true; +            metadata.stream_id = ntohl(header_buff[1]); +            metadata.has_time_spec = true; +            metadata.time_spec.secs = ntohl(header_buff[4]); +            num_header_words32 = 5; +            num_payload_words32 = packet_words32 - 6; +        break; +    case 24: +            metadata.has_time_spec = true; +            metadata.time_spec.ticks = ntohl(header_buff[2]); +            num_header_words32 = 3; +            num_payload_words32 = packet_words32 - 4; +        break; +    case 25: +            metadata.has_stream_id = true; +            metadata.stream_id = ntohl(header_buff[1]); +            metadata.has_time_spec = true; +            metadata.time_spec.ticks = ntohl(header_buff[3]); +            num_header_words32 = 4; +            num_payload_words32 = packet_words32 - 5; +        break; +    case 26: +            metadata.has_time_spec = true; +            metadata.time_spec.ticks = ntohl(header_buff[4]); +            num_header_words32 = 5; +            num_payload_words32 = packet_words32 - 6; +        break; +    case 27: +            metadata.has_stream_id = true; +            metadata.stream_id = ntohl(header_buff[1]); +            metadata.has_time_spec = true; +            metadata.time_spec.ticks = ntohl(header_buff[5]); +            num_header_words32 = 6; +            num_payload_words32 = packet_words32 - 7; +        break; +    case 28: +            metadata.has_time_spec = true; +            metadata.time_spec.secs = ntohl(header_buff[1]); +            metadata.time_spec.ticks = ntohl(header_buff[3]); +            num_header_words32 = 4; +            num_payload_words32 = packet_words32 - 5; +        break; +    case 29: +            metadata.has_stream_id = true; +            metadata.stream_id = ntohl(header_buff[1]); +            metadata.has_time_spec = true; +            metadata.time_spec.secs = ntohl(header_buff[2]); +            metadata.time_spec.ticks = ntohl(header_buff[4]); +            num_header_words32 = 5; +            num_payload_words32 = packet_words32 - 6; +        break; +    case 30: +            metadata.has_time_spec = true; +            metadata.time_spec.secs = ntohl(header_buff[3]); +            metadata.time_spec.ticks = ntohl(header_buff[5]); +            num_header_words32 = 6; +            num_payload_words32 = packet_words32 - 7; +        break; +    case 31: +            metadata.has_stream_id = true; +            metadata.stream_id = ntohl(header_buff[1]); +            metadata.has_time_spec = true; +            metadata.time_spec.secs = ntohl(header_buff[4]); +            metadata.time_spec.ticks = ntohl(header_buff[6]); +            num_header_words32 = 7; +            num_payload_words32 = packet_words32 - 8; +        break;      } - -    size_t num_trailer_words32 = (vrt_hdr_word & (0x1 << 26))? 1 : 0; - -    num_payload_words32 = packet_words32 - num_header_words32 - num_trailer_words32;  } + diff --git a/host/lib/tune_helper.cpp b/host/lib/tune_helper.cpp new file mode 100644 index 000000000..1e5c4cd0d --- /dev/null +++ b/host/lib/tune_helper.cpp @@ -0,0 +1,125 @@ +// +// 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/tune_helper.hpp> +#include <uhd/utils/algorithm.hpp> +#include <uhd/props.hpp> +#include <cmath> + +using namespace uhd; + +/*********************************************************************** + * Tune Helper Function + **********************************************************************/ +static tune_result_t tune_xx_subdev_and_dxc( +    bool is_tx, +    wax::obj subdev, wax::obj dxc, +    double target_freq, double lo_offset +){ +    wax::obj subdev_freq_proxy = subdev[SUBDEV_PROP_FREQ]; +    bool subdev_quadrature = subdev[SUBDEV_PROP_QUADRATURE].as<bool>(); +    bool subdev_spectrum_inverted = subdev[SUBDEV_PROP_SPECTRUM_INVERTED].as<bool>(); +    wax::obj dxc_freq_proxy = dxc[std::string("freq")]; +    double dxc_sample_rate = dxc[std::string("if_rate")].as<double>(); + +    // Ask the d'board to tune as closely as it can to target_freq+lo_offset +    double target_inter_freq = target_freq + lo_offset; +    subdev_freq_proxy = target_inter_freq; +    double actual_inter_freq = subdev_freq_proxy.as<double>(); + +    // 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 = std::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 = dxc_freq_proxy.as<double>(); + +    //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; +} + +/*********************************************************************** + * RX Tune + **********************************************************************/ +tune_result_t uhd::tune_rx_subdev_and_ddc( +    wax::obj subdev, wax::obj ddc, +    double target_freq, double lo_offset +){ +    bool is_tx = false; +    return tune_xx_subdev_and_dxc(is_tx, subdev, ddc, target_freq, lo_offset); +} + +tune_result_t uhd::tune_rx_subdev_and_ddc( +    wax::obj subdev, wax::obj ddc, +    double target_freq +){ +    double lo_offset = 0.0; +    //if the local oscillator will be in the passband, use an offset +    if (subdev[SUBDEV_PROP_LO_INTERFERES].as<bool>()){ +        lo_offset = 2.0*ddc[std::string("bb_rate")].as<double>(); +    } +    return tune_rx_subdev_and_ddc(subdev, ddc, target_freq, lo_offset); +} + +/*********************************************************************** + * TX Tune + **********************************************************************/ +tune_result_t uhd::tune_tx_subdev_and_duc( +    wax::obj subdev, wax::obj duc, +    double target_freq, double lo_offset +){ +    bool is_tx = true; +    return tune_xx_subdev_and_dxc(is_tx, subdev, duc, target_freq, lo_offset); +} + +tune_result_t uhd::tune_tx_subdev_and_duc( +    wax::obj subdev, wax::obj duc, +    double target_freq +){ +    double lo_offset = 0.0; +    //if the local oscillator will be in the passband, use an offset +    if (subdev[SUBDEV_PROP_LO_INTERFERES].as<bool>()){ +        lo_offset = 2.0*duc[std::string("bb_rate")].as<double>(); +    } +    return tune_tx_subdev_and_duc(subdev, duc, target_freq, lo_offset); +} diff --git a/host/lib/types.cpp b/host/lib/types.cpp index f8a9a9b36..bf9f8b895 100644 --- a/host/lib/types.cpp +++ b/host/lib/types.cpp @@ -15,12 +15,27 @@  // along with this program.  If not, see <http://www.gnu.org/licenses/>.  // -#include <uhd/types.hpp> +#include <uhd/types/ranges.hpp> +#include <uhd/types/tune_result.hpp> +#include <uhd/types/clock_config.hpp> +#include <uhd/types/stream_cmd.hpp> +#include <uhd/types/metadata.hpp> +#include <uhd/types/time_spec.hpp> +#include <uhd/types/device_addr.hpp> +#include <uhd/types/mac_addr.hpp> +#include <uhd/types/otw_type.hpp> +#include <uhd/types/io_type.hpp> +#include <boost/algorithm/string.hpp> +#include <boost/foreach.hpp> +#include <boost/format.hpp> +#include <boost/cstdint.hpp> +#include <stdexcept> +#include <complex>  using namespace uhd;  /*********************************************************************** - * gain range + * ranges   **********************************************************************/  gain_range_t::gain_range_t(float min_, float max_, float step_){      min = min_; @@ -28,9 +43,6 @@ gain_range_t::gain_range_t(float min_, float max_, float step_){      step = step_;  } -/*********************************************************************** - * freq range - **********************************************************************/  freq_range_t::freq_range_t(double min_, double max_){      min = min_;      max = max_; @@ -51,7 +63,185 @@ tune_result_t::tune_result_t(void){   * clock config   **********************************************************************/  clock_config_t::clock_config_t(void){ -    ref_source = ""; //not a valid setting -    pps_source = ""; //not a valid setting -    pps_polarity = POLARITY_NEG; +    ref_source = REF_INT, +    pps_source = PPS_INT, +    pps_polarity = PPS_NEG; +} + +/*********************************************************************** + * stream command + **********************************************************************/ +stream_cmd_t::stream_cmd_t(void){ +    stream_now = true; +    continuous = false; +    num_samps = 0; +} + +/*********************************************************************** + * metadata + **********************************************************************/ +rx_metadata_t::rx_metadata_t(void){ +    stream_id = 0; +    has_stream_id = false; +    time_spec = time_spec_t(); +    has_time_spec = false; +    is_fragment = false; +} + +tx_metadata_t::tx_metadata_t(void){ +    stream_id = 0; +    has_stream_id = false; +    time_spec = time_spec_t(); +    has_time_spec = false; +    start_of_burst = false; +    end_of_burst = false; +} + +/*********************************************************************** + * time spec + **********************************************************************/ +time_spec_t::time_spec_t(boost::uint32_t new_secs, boost::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 = double(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 = boost::uint32_t(td.total_seconds()); +    double time_ticks_per_device_ticks = time_tick_rate/tick_rate; +    ticks = boost::uint32_t(td.fractional_seconds()/time_ticks_per_device_ticks); +} + +/*********************************************************************** + * device addr + **********************************************************************/ +std::string device_addr_t::to_string(void) const{ +    const device_addr_t &device_addr = *this; +    std::stringstream ss; +    BOOST_FOREACH(std::string key, device_addr.get_keys()){ +        ss << boost::format("%s: %s") % key % device_addr[key] << std::endl; +    } +    return ss.str(); +} + +static const std::string arg_delim = ";"; +static const std::string pair_delim = "="; + +static std::string trim(const std::string &in){ +    return boost::algorithm::trim_copy(in); +} + +std::string device_addr_t::to_args_str(void) const{ +    std::string args_str; +    const device_addr_t &device_addr = *this; +    BOOST_FOREACH(const std::string &key, device_addr.get_keys()){ +        args_str += key + pair_delim + device_addr[key] + arg_delim; +    } +    return args_str; +} + +device_addr_t device_addr_t::from_args_str(const std::string &args_str){ +    device_addr_t addr; + +    //split the args at the semi-colons +    std::vector<std::string> pairs; +    boost::split(pairs, args_str, boost::is_any_of(arg_delim)); +    BOOST_FOREACH(const 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(pair_delim)); +        if (key_val.size() != 2) throw std::runtime_error("invalid args string: "+args_str); +        addr[trim(key_val[0])] = trim(key_val[1]); +    } + +    return addr; +} + +/*********************************************************************** + * mac addr + **********************************************************************/ +mac_addr_t::mac_addr_t(const boost::uint8_t *bytes){ +    std::copy(bytes, bytes+hlen, _bytes); +} + +mac_addr_t mac_addr_t::from_bytes(const boost::uint8_t *bytes){ +    return mac_addr_t(bytes); +} + +mac_addr_t mac_addr_t::from_string(const std::string &mac_addr_str){ + +    boost::uint8_t p[hlen] = {0x00, 0x50, 0xC2, 0x85, 0x30, 0x00}; // Matt's IAB + +    try{ +        //only allow patterns of xx:xx or xx:xx:xx:xx:xx:xx +        //the IAB above will fill in for the shorter pattern +        if (mac_addr_str.size() != 5 and mac_addr_str.size() != 17) +            throw std::runtime_error("expected exactly 5 or 17 characters"); + +        //split the mac addr hex string at the colons +        std::vector<std::string> hex_strs; +        boost::split(hex_strs, mac_addr_str, boost::is_any_of(":")); +        for (size_t i = 0; i < hex_strs.size(); i++){ +            int hex_num; +            std::istringstream iss(hex_strs[i]); +            iss >> std::hex >> hex_num; +            p[i] = boost::uint8_t(hex_num); +        } + +    } +    catch(std::exception const& e){ +        throw std::runtime_error(str( +            boost::format("Invalid mac address: %s\n\t%s") % mac_addr_str % e.what() +        )); +    } + +    return from_bytes(p); +} + +const boost::uint8_t *mac_addr_t::to_bytes(void) const{ +    return _bytes; +} + +std::string mac_addr_t::to_string(void) const{ +    return str( +        boost::format("%02x:%02x:%02x:%02x:%02x:%02x") +        % int(to_bytes()[0]) % int(to_bytes()[1]) % int(to_bytes()[2]) +        % int(to_bytes()[3]) % int(to_bytes()[4]) % int(to_bytes()[5]) +    ); +} + +/*********************************************************************** + * otw type + **********************************************************************/ +otw_type_t::otw_type_t(void){ +    width = 0; +    shift = 0; +    byteorder = BO_NATIVE; +} + +/*********************************************************************** + * io type + **********************************************************************/ +static size_t tid_to_size(io_type_t::tid_t tid){ +    switch(tid){ +    case io_type_t::COMPLEX_FLOAT32: return sizeof(std::complex<float>); +    case io_type_t::COMPLEX_INT16:   return sizeof(std::complex<boost::int16_t>); +    case io_type_t::COMPLEX_INT8:    return sizeof(std::complex<boost::int8_t>); +    default: throw std::runtime_error("unknown io type tid"); +    } +} + +io_type_t::io_type_t(tid_t tid) +: size(tid_to_size(tid)), tid(tid){ +    /* NOP */ +} + +io_type_t::io_type_t(size_t size) +: size(size), tid(CUSTOM_TYPE){ +    /* NOP */  } diff --git a/host/lib/usrp/dboard/basic.cpp b/host/lib/usrp/dboard/basic.cpp index 82485ae6a..2f29c8e0c 100644 --- a/host/lib/usrp/dboard/basic.cpp +++ b/host/lib/usrp/dboard/basic.cpp @@ -15,9 +15,10 @@  // along with this program.  If not, see <http://www.gnu.org/licenses/>.  // -#include <uhd/utils.hpp>  #include <uhd/props.hpp> -#include <uhd/types.hpp> +#include <uhd/types/ranges.hpp> +#include <uhd/utils/assert.hpp> +#include <uhd/utils/static.hpp>  #include <uhd/usrp/dboard_base.hpp>  #include <uhd/usrp/dboard_manager.hpp>  #include <boost/assign/list_of.hpp> @@ -33,26 +34,26 @@ using namespace boost::assign;   **********************************************************************/  class basic_rx : public rx_dboard_base{  public: -    basic_rx(ctor_args_t const& args, freq_t max_freq); +    basic_rx(ctor_args_t const& args, double max_freq);      ~basic_rx(void);      void rx_get(const wax::obj &key, wax::obj &val);      void rx_set(const wax::obj &key, const wax::obj &val);  private: -    freq_t _max_freq; +    double _max_freq;  };  class basic_tx : public tx_dboard_base{  public: -    basic_tx(ctor_args_t const& args, freq_t max_freq); +    basic_tx(ctor_args_t const& args, double max_freq);      ~basic_tx(void);      void tx_get(const wax::obj &key, wax::obj &val);      void tx_set(const wax::obj &key, const wax::obj &val);  private: -    freq_t _max_freq; +    double _max_freq;  };  /*********************************************************************** @@ -74,17 +75,17 @@ static dboard_base::sptr make_lf_tx(dboard_base::ctor_args_t const& args){      return dboard_base::sptr(new basic_tx(args, 32e6));  } -STATIC_BLOCK(reg_dboards){ -    dboard_manager::register_dboard(0x0000, &make_basic_tx, "Basic TX", list_of("")); +UHD_STATIC_BLOCK(reg_dboards){ +    dboard_manager::register_dboard(0x0000, &make_basic_tx, "Basic TX");      dboard_manager::register_dboard(0x0001, &make_basic_rx, "Basic RX", list_of("ab")("a")("b")); -    dboard_manager::register_dboard(0x000e, &make_lf_tx,    "LF TX",    list_of("")); +    dboard_manager::register_dboard(0x000e, &make_lf_tx,    "LF TX");      dboard_manager::register_dboard(0x000f, &make_lf_rx,    "LF RX",    list_of("ab")("a")("b"));  }  /***********************************************************************   * Basic and LF RX dboard   **********************************************************************/ -basic_rx::basic_rx(ctor_args_t const& args, freq_t max_freq) : rx_dboard_base(args){ +basic_rx::basic_rx(ctor_args_t const& args, double max_freq) : rx_dboard_base(args){      _max_freq = max_freq;      // set the gpios to safe values (all inputs)      get_interface()->set_gpio_ddr(dboard_interface::GPIO_RX_BANK, 0x0000, 0xffff); @@ -112,7 +113,7 @@ void basic_rx::rx_get(const wax::obj &key_, wax::obj &val){          return;      case SUBDEV_PROP_GAIN: -        val = gain_t(0); +        val = float(0);          return;      case SUBDEV_PROP_GAIN_RANGE: @@ -124,7 +125,7 @@ void basic_rx::rx_get(const wax::obj &key_, wax::obj &val){          return;      case SUBDEV_PROP_FREQ: -        val = freq_t(0); +        val = double(0);          return;      case SUBDEV_PROP_FREQ_RANGE: @@ -163,7 +164,7 @@ void basic_rx::rx_set(const wax::obj &key_, const wax::obj &val){      switch(key.as<subdev_prop_t>()){      case SUBDEV_PROP_GAIN: -        ASSERT_THROW(val.as<gain_t>() == gain_t(0)); +        ASSERT_THROW(val.as<float>() == float(0));          return;      case SUBDEV_PROP_ANTENNA: @@ -195,7 +196,7 @@ void basic_rx::rx_set(const wax::obj &key_, const wax::obj &val){  /***********************************************************************   * Basic and LF TX dboard   **********************************************************************/ -basic_tx::basic_tx(ctor_args_t const& args, freq_t max_freq) : tx_dboard_base(args){ +basic_tx::basic_tx(ctor_args_t const& args, double max_freq) : tx_dboard_base(args){      _max_freq = max_freq;      // set the gpios to safe values (all inputs)      get_interface()->set_gpio_ddr(dboard_interface::GPIO_TX_BANK, 0x0000, 0xffff); @@ -220,7 +221,7 @@ void basic_tx::tx_get(const wax::obj &key_, wax::obj &val){          return;      case SUBDEV_PROP_GAIN: -        val = gain_t(0); +        val = float(0);          return;      case SUBDEV_PROP_GAIN_RANGE: @@ -232,7 +233,7 @@ void basic_tx::tx_get(const wax::obj &key_, wax::obj &val){          return;      case SUBDEV_PROP_FREQ: -        val = freq_t(0); +        val = double(0);          return;      case SUBDEV_PROP_FREQ_RANGE: @@ -271,7 +272,7 @@ void basic_tx::tx_set(const wax::obj &key_, const wax::obj &val){      switch(key.as<subdev_prop_t>()){      case SUBDEV_PROP_GAIN: -        ASSERT_THROW(val.as<gain_t>() == gain_t(0)); +        ASSERT_THROW(val.as<float>() == float(0));          return;      case SUBDEV_PROP_ANTENNA: diff --git a/host/lib/usrp/dboard_base.cpp b/host/lib/usrp/dboard_base.cpp index 6dd41cfd8..09d3bbfd4 100644 --- a/host/lib/usrp/dboard_base.cpp +++ b/host/lib/usrp/dboard_base.cpp @@ -52,15 +52,15 @@ dboard_id_t dboard_base::get_tx_id(void){   * xcvr dboard dboard_base class   **********************************************************************/  xcvr_dboard_base::xcvr_dboard_base(ctor_args_t const& args) : dboard_base(args){ -    if (get_rx_id() == ID_NONE){ +    if (get_rx_id() == dboard_id::NONE){          throw std::runtime_error(str(boost::format(              "cannot create xcvr board when the rx id is \"%s\"" -        ) % dboard_id::to_string(ID_NONE))); +        ) % dboard_id::to_string(dboard_id::NONE)));      } -    if (get_tx_id() == ID_NONE){ +    if (get_tx_id() == dboard_id::NONE){          throw std::runtime_error(str(boost::format(              "cannot create xcvr board when the tx id is \"%s\"" -        ) % dboard_id::to_string(ID_NONE))); +        ) % dboard_id::to_string(dboard_id::NONE)));      }  } @@ -72,11 +72,11 @@ xcvr_dboard_base::~xcvr_dboard_base(void){   * rx dboard dboard_base class   **********************************************************************/  rx_dboard_base::rx_dboard_base(ctor_args_t const& args) : dboard_base(args){ -    if (get_tx_id() != ID_NONE){ +    if (get_tx_id() != dboard_id::NONE){          throw std::runtime_error(str(boost::format(              "cannot create rx board when the tx id is \"%s\""              " -> expected a tx id of \"%s\"" -        ) % dboard_id::to_string(get_tx_id()) % dboard_id::to_string(ID_NONE))); +        ) % dboard_id::to_string(get_tx_id()) % dboard_id::to_string(dboard_id::NONE)));      }  } @@ -96,11 +96,11 @@ void rx_dboard_base::tx_set(const wax::obj &, const wax::obj &){   * tx dboard dboard_base class   **********************************************************************/  tx_dboard_base::tx_dboard_base(ctor_args_t const& args) : dboard_base(args){ -    if (get_rx_id() != ID_NONE){ +    if (get_rx_id() != dboard_id::NONE){          throw std::runtime_error(str(boost::format(              "cannot create tx board when the rx id is \"%s\""              " -> expected a rx id of \"%s\"" -        ) % dboard_id::to_string(get_rx_id()) % dboard_id::to_string(ID_NONE))); +        ) % dboard_id::to_string(get_rx_id()) % dboard_id::to_string(dboard_id::NONE)));      }  } diff --git a/host/lib/usrp/dboard_manager.cpp b/host/lib/usrp/dboard_manager.cpp index 6ca15e98c..424626023 100644 --- a/host/lib/usrp/dboard_manager.cpp +++ b/host/lib/usrp/dboard_manager.cpp @@ -16,9 +16,10 @@  //  #include <uhd/usrp/dboard_manager.hpp> -#include <uhd/gain_handler.hpp> -#include <uhd/utils.hpp> -#include <uhd/dict.hpp> +#include <uhd/utils/gain_handler.hpp> +#include <uhd/utils/static.hpp> +#include <uhd/utils/assert.hpp> +#include <uhd/types/dict.hpp>  #include <boost/tuple/tuple.hpp>  #include <boost/format.hpp>  #include <boost/bind.hpp> @@ -35,7 +36,7 @@ typedef boost::tuple<dboard_manager::dboard_ctor_t, std::string, prop_names_t> a  //map a dboard id to a dboard constructor  typedef uhd::dict<dboard_id_t, args_t> id_to_args_map_t; -STATIC_INSTANCE(id_to_args_map_t, get_id_to_args_map) +UHD_SINGLETON_FCN(id_to_args_map_t, get_id_to_args_map)  void dboard_manager::register_dboard(      dboard_id_t dboard_id, @@ -163,12 +164,12 @@ static args_t get_dboard_args(      std::string const& xx_type  ){      //special case, its rx and the none id (0xffff) -    if (xx_type == "rx" and dboard_id == ID_NONE){ +    if (xx_type == "rx" and dboard_id == dboard_id::NONE){          return get_dboard_args(0x0001, xx_type);      }      //special case, its tx and the none id (0xffff) -    if (xx_type == "tx" and dboard_id == ID_NONE){ +    if (xx_type == "tx" and dboard_id == dboard_id::NONE){          return get_dboard_args(0x0000, xx_type);      } @@ -203,7 +204,7 @@ dboard_manager_impl::dboard_manager_impl(      //make xcvr subdevs (make one subdev for both rx and tx dboards)      if (rx_dboard_ctor == tx_dboard_ctor){          ASSERT_THROW(rx_subdevs == tx_subdevs); -        BOOST_FOREACH(std::string subdev, rx_subdevs){ +        BOOST_FOREACH(const std::string &subdev, rx_subdevs){              dboard_base::sptr xcvr_dboard = rx_dboard_ctor(                  dboard_base::ctor_args_t(subdev, interface, rx_dboard_id, tx_dboard_id)              ); @@ -221,9 +222,9 @@ dboard_manager_impl::dboard_manager_impl(      //make tx and rx subdevs (separate subdevs for rx and tx dboards)      else{          //make the rx subdevs -        BOOST_FOREACH(std::string subdev, rx_subdevs){ +        BOOST_FOREACH(const std::string &subdev, rx_subdevs){              dboard_base::sptr rx_dboard = rx_dboard_ctor( -                dboard_base::ctor_args_t(subdev, interface, rx_dboard_id, ID_NONE) +                dboard_base::ctor_args_t(subdev, interface, rx_dboard_id, dboard_id::NONE)              );              //create a rx proxy for this rx board              _rx_dboards[subdev] = subdev_proxy::sptr( @@ -231,9 +232,9 @@ dboard_manager_impl::dboard_manager_impl(              );          }          //make the tx subdevs -        BOOST_FOREACH(std::string subdev, tx_subdevs){ +        BOOST_FOREACH(const std::string &subdev, tx_subdevs){              dboard_base::sptr tx_dboard = tx_dboard_ctor( -                dboard_base::ctor_args_t(subdev, interface, ID_NONE, tx_dboard_id) +                dboard_base::ctor_args_t(subdev, interface, dboard_id::NONE, tx_dboard_id)              );              //create a tx proxy for this tx board              _tx_dboards[subdev] = subdev_proxy::sptr( diff --git a/host/lib/usrp/usrp1e/usrp1e_none.cpp b/host/lib/usrp/usrp1e/usrp1e_none.cpp index ac0b12a75..94243523d 100644 --- a/host/lib/usrp/usrp1e/usrp1e_none.cpp +++ b/host/lib/usrp/usrp1e/usrp1e_none.cpp @@ -25,7 +25,7 @@ using namespace uhd::usrp;   * when the required kernel module headers are not present.   */ -device_addrs_t usrp1e::discover(const device_addr_t &){ +device_addrs_t usrp1e::find(const device_addr_t &){      return device_addrs_t(); //return empty list  } diff --git a/host/lib/usrp/usrp2/dboard_impl.cpp b/host/lib/usrp/usrp2/dboard_impl.cpp index 66e02d469..fd72aeaa4 100644 --- a/host/lib/usrp/usrp2/dboard_impl.cpp +++ b/host/lib/usrp/usrp2/dboard_impl.cpp @@ -15,7 +15,8 @@  // along with this program.  If not, see <http://www.gnu.org/licenses/>.  // -#include <uhd/utils.hpp> +#include <uhd/utils/assert.hpp> +#include <uhd/types/clock_config.hpp>  #include <boost/format.hpp>  #include "usrp2_impl.hpp" diff --git a/host/lib/usrp/usrp2/dboard_interface.cpp b/host/lib/usrp/usrp2/dboard_interface.cpp index d20465147..8fc7864b0 100644 --- a/host/lib/usrp/usrp2/dboard_interface.cpp +++ b/host/lib/usrp/usrp2/dboard_interface.cpp @@ -15,7 +15,7 @@  // along with this program.  If not, see <http://www.gnu.org/licenses/>.  // -#include <uhd/utils.hpp> +#include <uhd/utils/assert.hpp>  #include "usrp2_impl.hpp"  using namespace uhd::usrp; diff --git a/host/lib/usrp/usrp2/dsp_impl.cpp b/host/lib/usrp/usrp2/dsp_impl.cpp index 34cce0afb..0d43fac0e 100644 --- a/host/lib/usrp/usrp2/dsp_impl.cpp +++ b/host/lib/usrp/usrp2/dsp_impl.cpp @@ -15,7 +15,7 @@  // along with this program.  If not, see <http://www.gnu.org/licenses/>.  // -#include <uhd/utils.hpp> +#include <uhd/utils/assert.hpp>  #include <boost/format.hpp>  #include <boost/assign/list_of.hpp>  #include <boost/math/special_functions/round.hpp> @@ -35,7 +35,7 @@ template <class T> T log2(T num){  /***********************************************************************   * DDC Helper Methods   **********************************************************************/ -static boost::uint32_t calculate_freq_word_and_update_actual_freq(freq_t &freq, freq_t clock_freq){ +static boost::uint32_t calculate_freq_word_and_update_actual_freq(double &freq, double clock_freq){      double scale_factor = std::pow(2.0, 32);      //calculate the freq register word @@ -63,9 +63,8 @@ void usrp2_impl::init_ddc_config(void){      _ddc_freq = 0;      update_ddc_config(); -    _ddc_stream_at = time_spec_t(); -    _ddc_enabled = false; -    update_ddc_enabled(); +    //initial command that kills streaming (in case if was left on) +    //issue_ddc_stream_cmd(TODO)  }  void usrp2_impl::update_ddc_config(void){ @@ -86,21 +85,19 @@ void usrp2_impl::update_ddc_config(void){      ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_TOTALLY_SETUP_THE_DDC_DUDE);  } -void usrp2_impl::update_ddc_enabled(void){ +void usrp2_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){      //setup the out data      usrp2_ctrl_data_t out_data; -    out_data.id = htonl(USRP2_CTRL_ID_CONFIGURE_STREAMING_FOR_ME_BRO); -    out_data.data.streaming.enabled = (_ddc_enabled)? 1 : 0; -    out_data.data.streaming.secs =  htonl(_ddc_stream_at.secs); -    out_data.data.streaming.ticks = htonl(_ddc_stream_at.ticks); -    out_data.data.streaming.samples = htonl(_max_rx_samples_per_packet); +    out_data.id = htonl(USRP2_CTRL_ID_SEND_STREAM_COMMAND_FOR_ME_BRO); +    out_data.data.stream_cmd.now = (stream_cmd.stream_now)? 1 : 0; +    out_data.data.stream_cmd.continuous = (stream_cmd.continuous)? 1 : 0; +    out_data.data.stream_cmd.secs = htonl(stream_cmd.time_spec.secs); +    out_data.data.stream_cmd.ticks = htonl(stream_cmd.time_spec.ticks); +    out_data.data.stream_cmd.num_samps = htonl(stream_cmd.num_samps);      //send and recv      usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data); -    ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_CONFIGURED_THAT_STREAMING_DUDE); - -    //clear the stream at time spec (it must be set for the next round of enable/disable) -    _ddc_stream_at = time_spec_t(); +    ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_GOT_THAT_STREAM_COMMAND_DUDE);  }  /*********************************************************************** @@ -116,12 +113,12 @@ void usrp2_impl::ddc_get(const wax::obj &key, wax::obj &val){          case DSP_PROP_OTHERS:{                  prop_names_t others = boost::assign::list_of -                    ("rate") +                    ("if_rate") +                    ("bb_rate")                      ("decim")                      ("decims")                      ("freq") -                    ("enabled") -                    ("stream_at") +                    ("stream_cmd")                  ;                  val = others;              } @@ -131,10 +128,14 @@ void usrp2_impl::ddc_get(const wax::obj &key, wax::obj &val){      //handle string-based properties specific to this dsp      std::string key_name = key.as<std::string>(); -    if (key_name == "rate"){ +    if (key_name == "if_rate"){          val = get_master_clock_freq();          return;      } +    else if (key_name == "bb_rate"){ +        val = get_master_clock_freq()/_ddc_decim; +        return; +    }      else if (key_name == "decim"){          val = _ddc_decim;          return; @@ -147,10 +148,6 @@ void usrp2_impl::ddc_get(const wax::obj &key, wax::obj &val){          val = _ddc_freq;          return;      } -    else if (key_name == "enabled"){ -        val = _ddc_enabled; -        return; -    }      throw std::invalid_argument(str(          boost::format("error getting: unknown key with name %s") % key_name @@ -171,23 +168,15 @@ void usrp2_impl::ddc_set(const wax::obj &key, const wax::obj &val){          return;      }      else if (key_name == "freq"){ -        freq_t new_freq = val.as<freq_t>(); +        double new_freq = val.as<double>();          ASSERT_THROW(new_freq <= get_master_clock_freq()/2.0);          ASSERT_THROW(new_freq >= -get_master_clock_freq()/2.0);          _ddc_freq = new_freq; //shadow          update_ddc_config();          return;      } -    else if (key_name == "enabled"){ -        bool new_enabled = val.as<bool>(); -        _ddc_enabled = new_enabled; //shadow -        update_ddc_enabled(); -        return; -    } -    else if (key_name == "stream_at"){ -        time_spec_t new_stream_at = val.as<time_spec_t>(); -        _ddc_stream_at = new_stream_at; //shadow -        //update_ddc_enabled(); //dont update from here +    else if (key_name == "stream_cmd"){ +        issue_ddc_stream_cmd(val.as<stream_cmd_t>());          return;      } @@ -250,7 +239,8 @@ void usrp2_impl::duc_get(const wax::obj &key, wax::obj &val){          case DSP_PROP_OTHERS:{                  prop_names_t others = boost::assign::list_of -                    ("rate") +                    ("if_rate") +                    ("bb_rate")                      ("interp")                      ("interps")                      ("freq") @@ -263,10 +253,14 @@ void usrp2_impl::duc_get(const wax::obj &key, wax::obj &val){      //handle string-based properties specific to this dsp      std::string key_name = key.as<std::string>(); -    if (key_name == "rate"){ +    if (key_name == "if_rate"){          val = get_master_clock_freq();          return;      } +    else if (key_name == "bb_rate"){ +        val = get_master_clock_freq()/_duc_interp; +        return; +    }      else if (key_name == "interp"){          val = _duc_interp;          return; @@ -299,7 +293,7 @@ void usrp2_impl::duc_set(const wax::obj &key, const wax::obj &val){          return;      }      else if (key_name == "freq"){ -        freq_t new_freq = val.as<freq_t>(); +        double new_freq = val.as<double>();          ASSERT_THROW(new_freq <= get_master_clock_freq()/2.0);          ASSERT_THROW(new_freq >= -get_master_clock_freq()/2.0);          _duc_freq = new_freq; //shadow diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h index 7fcae6fb2..30fee6c32 100644 --- a/host/lib/usrp/usrp2/fw_common.h +++ b/host/lib/usrp/usrp2/fw_common.h @@ -32,6 +32,9 @@ extern "C" {  #define _SINS_  #endif +//used to differentiate control packets over data port +#define USRP2_INVALID_VRT_HEADER 0 +  // size of the vrt header and trailer to the host  #define USRP2_HOST_RX_VRT_HEADER_WORDS32 5  #define USRP2_HOST_RX_VRT_TRAILER_WORDS32 1 //FIXME fpga sets wrong header size when no trailer present @@ -90,8 +93,8 @@ typedef enum{      USRP2_CTRL_ID_SETUP_THIS_DDC_FOR_ME_BRO,      USRP2_CTRL_ID_TOTALLY_SETUP_THE_DDC_DUDE, -    USRP2_CTRL_ID_CONFIGURE_STREAMING_FOR_ME_BRO, -    USRP2_CTRL_ID_CONFIGURED_THAT_STREAMING_DUDE, +    USRP2_CTRL_ID_SEND_STREAM_COMMAND_FOR_ME_BRO, +    USRP2_CTRL_ID_GOT_THAT_STREAM_COMMAND_DUDE,      USRP2_CTRL_ID_SETUP_THIS_DUC_FOR_ME_BRO,      USRP2_CTRL_ID_TOTALLY_SETUP_THE_DUC_DUDE, @@ -186,12 +189,13 @@ typedef struct{              _SINS_ uint32_t scale_iq;          } ddc_args;          struct { -            _SINS_ uint8_t enabled; -            _SINS_ uint8_t _pad[3]; +            _SINS_ uint8_t now; //stream now? +            _SINS_ uint8_t continuous; //auto-reload commmands? +            _SINS_ uint8_t _pad[2];              _SINS_ uint32_t secs;              _SINS_ uint32_t ticks; -            _SINS_ uint32_t samples; -        } streaming; +            _SINS_ uint32_t num_samps; +        } stream_cmd;          struct {              _SINS_ uint32_t freq_word;              _SINS_ uint32_t interp; diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index dc8eea243..c87884ebb 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -16,7 +16,6 @@  //  #include <complex> -#include <algorithm>  #include <boost/format.hpp>  #include "usrp2_impl.hpp" @@ -42,20 +41,22 @@ void usrp2_impl::io_init(void){      _rx_copy_buff = asio::buffer("", 0);      //send a small data packet so the usrp2 knows the udp source port -    boost::uint32_t zero_data = 0; -    _data_transport->send(asio::buffer(&zero_data, sizeof(zero_data))); +    //and the maximum number of lines (32 bit words) per packet +    boost::uint32_t data[2] = { +        htonl(USRP2_INVALID_VRT_HEADER), +        htonl(_max_rx_samples_per_packet) +    }; +    _data_transport->send(asio::buffer(&data, sizeof(data)));  } -#define unrolled_loop(__i, __len, __inst) {\ +#define unrolled_loop(__inst, __len){ \      size_t __i = 0; \ -    while(__i < (__len & ~0x7)){ \ -        __inst; __i++; __inst; __i++; \ -        __inst; __i++; __inst; __i++; \ -        __inst; __i++; __inst; __i++; \ -        __inst; __i++; __inst; __i++; \ +    for(; __i < (__len & ~0x3); __i+= 4){ \ +        __inst(__i+0); __inst(__i+1); \ +        __inst(__i+2); __inst(__i+3); \      } \ -    while(__i < __len){ \ -        __inst; __i++;\ +    for(; __i < __len; __i++){ \ +        __inst(__i); \      } \  } @@ -71,11 +72,12 @@ static inline void host_floats_to_usrp2_items(      const fc32_t *host_floats,      size_t num_samps  ){ -    unrolled_loop(i, num_samps,{ -        boost::uint16_t real = boost::int16_t(host_floats[i].real()*shorts_per_float); -        boost::uint16_t imag = boost::int16_t(host_floats[i].imag()*shorts_per_float); -        usrp2_items[i] = htonl((real << 16) | (imag << 0)); -    }); +    #define host_floats_to_usrp2_items_i(i){ \ +        boost::uint16_t real = boost::int16_t(host_floats[i].real()*shorts_per_float); \ +        boost::uint16_t imag = boost::int16_t(host_floats[i].imag()*shorts_per_float); \ +        usrp2_items[i] = htonl((real << 16) | (imag << 0)); \ +    } +    unrolled_loop(host_floats_to_usrp2_items_i, num_samps);  }  static inline void usrp2_items_to_host_floats( @@ -83,12 +85,13 @@ static inline void usrp2_items_to_host_floats(      const boost::uint32_t *usrp2_items,      size_t num_samps  ){ -    unrolled_loop(i, num_samps,{ -        boost::uint32_t item = ntohl(usrp2_items[i]); -        boost::int16_t real = boost::uint16_t(item >> 16); -        boost::int16_t imag = boost::uint16_t(item >> 0); -        host_floats[i] = fc32_t(float(real*floats_per_short), float(imag*floats_per_short)); -    }); +    #define usrp2_items_to_host_floats_i(i){ \ +        boost::uint32_t item = ntohl(usrp2_items[i]); \ +        boost::int16_t real = boost::uint16_t(item >> 16); \ +        boost::int16_t imag = boost::uint16_t(item >> 0); \ +        host_floats[i] = fc32_t(float(real*floats_per_short), float(imag*floats_per_short)); \ +    } +    unrolled_loop(usrp2_items_to_host_floats_i, num_samps);  }  static inline void host_items_to_usrp2_items( @@ -96,11 +99,12 @@ static inline void host_items_to_usrp2_items(      const boost::uint32_t *host_items,      size_t num_samps  ){ +    #define host_items_to_usrp2_items_i(i) usrp2_items[i] = htonl(host_items[i])      if (is_big_endian){          std::memcpy(usrp2_items, host_items, num_samps*sizeof(boost::uint32_t));      }      else{ -        unrolled_loop(i, num_samps, usrp2_items[i] = htonl(host_items[i])); +        unrolled_loop(host_items_to_usrp2_items_i, num_samps);      }  } @@ -109,11 +113,12 @@ static inline void usrp2_items_to_host_items(      const boost::uint32_t *usrp2_items,      size_t num_samps  ){ +    #define usrp2_items_to_host_items_i(i) host_items[i] = ntohl(usrp2_items[i])      if (is_big_endian){          std::memcpy(host_items, usrp2_items, num_samps*sizeof(boost::uint32_t));      }      else{ -        unrolled_loop(i, num_samps, host_items[i] = ntohl(usrp2_items[i])); +        unrolled_loop(usrp2_items_to_host_items_i, num_samps);      }  } @@ -167,46 +172,43 @@ void usrp2_impl::recv_raw(rx_metadata_t &metadata){  size_t usrp2_impl::send(      const asio::const_buffer &buff,      const tx_metadata_t &metadata, -    const std::string &type +    const io_type_t &io_type  ){      boost::uint32_t tx_mem[_mtu/sizeof(boost::uint32_t)]; -    boost::uint32_t *items = tx_mem + vrt::max_header_words32; //offset for data -    size_t num_samps = _max_tx_samples_per_packet; - -    //calculate the number of samples to be copied -    //and copy the samples into the send buffer -    if (type == "32fc"){ -        num_samps = std::min(asio::buffer_size(buff)/sizeof(fc32_t), num_samps); -        host_floats_to_usrp2_items(items, asio::buffer_cast<const fc32_t*>(buff), num_samps); -    } -    else if (type == "16sc"){ -        num_samps = std::min(asio::buffer_size(buff)/sizeof(sc16_t), num_samps); -        host_items_to_usrp2_items(items, asio::buffer_cast<const boost::uint32_t*>(buff), num_samps); -    } -    else{ -        throw std::runtime_error(str(boost::format("usrp2 send: cannot handle type \"%s\"") % type)); -    } +    size_t num_samps = std::min( +        asio::buffer_size(buff)/io_type.size, +        size_t(_max_tx_samples_per_packet) +    ); -    boost::uint32_t vrt_hdr[vrt::max_header_words32];      size_t num_header_words32, num_packet_words32;      size_t packet_count = _tx_stream_id_to_packet_seq[metadata.stream_id]++;      //pack metadata into a vrt header      vrt::pack(          metadata,            //input -        vrt_hdr,             //output +        tx_mem,              //output          num_header_words32,  //output          num_samps,           //input          num_packet_words32,  //output          packet_count         //input      ); -    //copy in the vrt header (yes we left space) -    items -= num_header_words32; -    std::memcpy(items, vrt_hdr, num_header_words32*sizeof(boost::uint32_t)); +    boost::uint32_t *items = tx_mem + num_header_words32; //offset for data + +    //copy the samples into the send buffer +    switch(io_type.tid){ +    case io_type_t::COMPLEX_FLOAT32: +        host_floats_to_usrp2_items(items, asio::buffer_cast<const fc32_t*>(buff), num_samps); +        break; +    case io_type_t::COMPLEX_INT16: +        host_items_to_usrp2_items(items, asio::buffer_cast<const boost::uint32_t*>(buff), num_samps); +        break; +    default: +        throw std::runtime_error(str(boost::format("usrp2 send: cannot handle type \"%c\"") % io_type.tid)); +    }      //send and return number of samples -    _data_transport->send(asio::buffer(items, num_packet_words32*sizeof(boost::uint32_t))); +    _data_transport->send(asio::buffer(tx_mem, num_packet_words32*sizeof(boost::uint32_t)));      return num_samps;  } @@ -216,7 +218,7 @@ size_t usrp2_impl::send(  size_t usrp2_impl::recv(      const asio::mutable_buffer &buff,      rx_metadata_t &metadata, -    const std::string &type +    const io_type_t &io_type  ){      //perform a receive if no rx data is waiting to be copied      if (asio::buffer_size(_rx_copy_buff) == 0){ @@ -232,21 +234,22 @@ size_t usrp2_impl::recv(      //and a pointer into the usrp2 received items memory      size_t bytes_to_copy = asio::buffer_size(_rx_copy_buff);      if (bytes_to_copy == 0) return 0; //nothing to receive -    size_t num_samps = bytes_to_copy/sizeof(boost::uint32_t); +    size_t num_samps = std::min( +        asio::buffer_size(buff)/io_type.size, +        bytes_to_copy/sizeof(boost::uint32_t) +    );      const boost::uint32_t *items = asio::buffer_cast<const boost::uint32_t*>(_rx_copy_buff); -    //calculate the number of samples to be copied -    //and copy the samples from the recv buffer -    if (type == "32fc"){ -        num_samps = std::min(asio::buffer_size(buff)/sizeof(fc32_t), num_samps); +    //copy the samples from the recv buffer +    switch(io_type.tid){ +    case io_type_t::COMPLEX_FLOAT32:          usrp2_items_to_host_floats(asio::buffer_cast<fc32_t*>(buff), items, num_samps); -    } -    else if (type == "16sc"){ -        num_samps = std::min(asio::buffer_size(buff)/sizeof(sc16_t), num_samps); +        break; +    case io_type_t::COMPLEX_INT16:          usrp2_items_to_host_items(asio::buffer_cast<boost::uint32_t*>(buff), items, num_samps); -    } -    else{ -        throw std::runtime_error(str(boost::format("usrp2 recv: cannot handle type \"%s\"") % type)); +        break; +    default: +        throw std::runtime_error(str(boost::format("usrp2 recv: cannot handle type \"%c\"") % io_type.tid));      }      //update the rx copy buffer to reflect the bytes copied diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index cbca8eec7..35dfd6287 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -15,7 +15,8 @@  // along with this program.  If not, see <http://www.gnu.org/licenses/>.  // -#include <uhd/utils.hpp> +#include <uhd/utils/assert.hpp> +#include <uhd/types/mac_addr.hpp>  #include "usrp2_impl.hpp"  using namespace uhd; @@ -35,27 +36,10 @@ void usrp2_impl::mboard_init(void){  }  void usrp2_impl::init_clock_config(void){ -    //init the ref source clock config -    _ref_source_dict = boost::assign::map_list_of -        ("int", USRP2_REF_SOURCE_INT) -        ("sma", USRP2_REF_SOURCE_SMA) -        ("mimo", USRP2_REF_SOURCE_MIMO) -    ; -    _clock_config.ref_source = "int"; - -    //init the pps source clock config -    _pps_source_dict = boost::assign::map_list_of -        ("sma", USRP2_PPS_SOURCE_SMA) -        ("mimo", USRP2_PPS_SOURCE_MIMO) -    ; -    _clock_config.pps_source = "sma"; - -    //init the pps polarity clock config -    _pps_polarity_dict = boost::assign::map_list_of -        (clock_config_t::POLARITY_POS, USRP2_PPS_POLARITY_POS) -        (clock_config_t::POLARITY_NEG, USRP2_PPS_POLARITY_NEG) -    ; -    _clock_config.pps_polarity = clock_config_t::POLARITY_NEG; +    //setup the clock configuration settings +    _clock_config.ref_source = clock_config_t::REF_INT; +    _clock_config.pps_source = clock_config_t::PPS_SMA; +    _clock_config.pps_polarity = clock_config_t::PPS_NEG;      //update the clock config (sends a control packet)      update_clock_config(); @@ -65,9 +49,35 @@ void usrp2_impl::update_clock_config(void){      //setup the out data      usrp2_ctrl_data_t out_data;      out_data.id = htonl(USRP2_CTRL_ID_HERES_A_NEW_CLOCK_CONFIG_BRO); -    out_data.data.clock_config.ref_source   = _ref_source_dict  [_clock_config.ref_source]; -    out_data.data.clock_config.pps_source   = _pps_source_dict  [_clock_config.pps_source]; -    out_data.data.clock_config.pps_polarity = _pps_polarity_dict[_clock_config.pps_polarity]; + +    //translate ref source enums +    switch(_clock_config.ref_source){ +    case clock_config_t::REF_INT: +        out_data.data.clock_config.ref_source = USRP2_REF_SOURCE_INT; break; +    case clock_config_t::REF_SMA: +        out_data.data.clock_config.ref_source = USRP2_REF_SOURCE_SMA; break; +    case clock_config_t::REF_MIMO: +        out_data.data.clock_config.ref_source = USRP2_REF_SOURCE_MIMO; break; +    default: throw std::runtime_error("usrp2: unhandled clock configuration ref source"); +    } + +    //translate pps source enums +    switch(_clock_config.pps_source){ +    case clock_config_t::PPS_SMA: +        out_data.data.clock_config.pps_source = USRP2_PPS_SOURCE_SMA; break; +    case clock_config_t::PPS_MIMO: +        out_data.data.clock_config.pps_source = USRP2_PPS_SOURCE_MIMO; break; +    default: throw std::runtime_error("usrp2: unhandled clock configuration pps source"); +    } + +    //translate pps polarity enums +    switch(_clock_config.pps_polarity){ +    case clock_config_t::PPS_POS: +        out_data.data.clock_config.pps_source = USRP2_PPS_POLARITY_POS; break; +    case clock_config_t::PPS_NEG: +        out_data.data.clock_config.pps_source = USRP2_PPS_POLARITY_NEG; break; +    default: throw std::runtime_error("usrp2: unhandled clock configuration pps polarity"); +    }      //send and recv      usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data); @@ -106,7 +116,7 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){              ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THIS_IS_MY_MAC_ADDR_DUDE);              //extract the address -            val = reinterpret_cast<mac_addr_t*>(in_data.data.mac_addr)->to_string(); +            val = mac_addr_t::from_bytes(in_data.data.mac_addr).to_string();              return;          } @@ -159,7 +169,7 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){          return;      case MBOARD_PROP_CLOCK_RATE: -        val = freq_t(get_master_clock_freq()); +        val = double(get_master_clock_freq());          return;      case MBOARD_PROP_RX_DSP: @@ -184,14 +194,6 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){          val = _clock_config;          return; -    case MBOARD_PROP_PPS_SOURCE_NAMES: -        val = prop_names_t(_pps_source_dict.get_keys()); -        return; - -    case MBOARD_PROP_REF_SOURCE_NAMES: -        val = prop_names_t(_ref_source_dict.get_keys()); -        return; -      case MBOARD_PROP_TIME_NOW:      case MBOARD_PROP_TIME_NEXT_PPS:          throw std::runtime_error("Error: trying to get write-only property on usrp2 mboard"); @@ -209,8 +211,8 @@ void usrp2_impl::mboard_set(const wax::obj &key, const wax::obj &val){              //setup the out data              usrp2_ctrl_data_t out_data;              out_data.id = htonl(USRP2_CTRL_ID_HERE_IS_A_NEW_MAC_ADDR_BRO); -            mac_addr_t mac_addr(val.as<std::string>()); -            std::memcpy(out_data.data.mac_addr, &mac_addr, sizeof(mac_addr_t)); +            mac_addr_t mac_addr = mac_addr_t::from_string(val.as<std::string>()); +            std::copy(mac_addr.to_bytes(), mac_addr.to_bytes()+mac_addr_t::hlen, out_data.data.mac_addr);              //send and recv              usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data); @@ -234,13 +236,9 @@ void usrp2_impl::mboard_set(const wax::obj &key, const wax::obj &val){      //handle the get request conditioned on the key      switch(key.as<mboard_prop_t>()){ -    case MBOARD_PROP_CLOCK_CONFIG:{ -            clock_config_t clock_config = val.as<clock_config_t>(); -            assert_has(_pps_source_dict.get_keys(), clock_config.pps_source, "usrp2 pps source"); -            assert_has(_ref_source_dict.get_keys(), clock_config.ref_source, "usrp2 ref source"); -            _clock_config = clock_config; //shadow -            update_clock_config(); -        } +    case MBOARD_PROP_CLOCK_CONFIG: +        _clock_config = val.as<clock_config_t>(); +        update_clock_config();          return;      case MBOARD_PROP_TIME_NOW:{ @@ -264,8 +262,6 @@ void usrp2_impl::mboard_set(const wax::obj &key, const wax::obj &val){      case MBOARD_PROP_RX_DBOARD_NAMES:      case MBOARD_PROP_TX_DBOARD:      case MBOARD_PROP_TX_DBOARD_NAMES: -    case MBOARD_PROP_PPS_SOURCE_NAMES: -    case MBOARD_PROP_REF_SOURCE_NAMES:          throw std::runtime_error("Error: trying to set read-only property on usrp2 mboard");      } diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index 85d73e83a..67fbdf8d2 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -15,9 +15,12 @@  // along with this program.  If not, see <http://www.gnu.org/licenses/>.  // +#include <uhd/transport/if_addrs.hpp> +#include <uhd/utils/assert.hpp> +#include <uhd/utils/static.hpp>  #include <boost/format.hpp> +#include <boost/foreach.hpp>  #include <boost/bind.hpp> -#include <uhd/utils.hpp>  #include <iostream>  #include "usrp2_impl.hpp" @@ -27,16 +30,33 @@ using namespace uhd::transport;  namespace asio = boost::asio;  STATIC_BLOCK(register_usrp2_device){ -    device::register_device(&usrp2::discover, &usrp2::make); +    device::register_device(&usrp2::find, &usrp2::make);  }  /***********************************************************************   * Discovery over the udp transport   **********************************************************************/ -uhd::device_addrs_t usrp2::discover(const device_addr_t &hint){ +uhd::device_addrs_t usrp2::find(const device_addr_t &hint){      device_addrs_t usrp2_addrs; -    if (not hint.has_key("addr")) return usrp2_addrs; +    //if no address was specified, send a broadcast on each interface +    if (not hint.has_key("addr")){ +        BOOST_FOREACH(const if_addrs_t &if_addrs, get_if_addrs()){ +            //avoid the loopback device +            if (if_addrs.inet == asio::ip::address_v4::loopback().to_string()) continue; + +            //create a new hint with this broadcast address +            device_addr_t new_hint = hint; +            new_hint["addr"] = if_addrs.bcast; + +            //call discover with the new hint and append results +            device_addrs_t new_usrp2_addrs = usrp2::find(new_hint); +            usrp2_addrs.insert(usrp2_addrs.begin(), +                new_usrp2_addrs.begin(), new_usrp2_addrs.end() +            ); +        } +        return usrp2_addrs; +    }      //create a udp transport to communicate      //TODO if an addr is not provided, search all interfaces? @@ -63,7 +83,6 @@ uhd::device_addrs_t usrp2::discover(const device_addr_t &hint){                  boost::asio::ip::address_v4 ip_addr(ntohl(ctrl_data_in.data.ip_addr));                  device_addr_t new_addr;                  new_addr["name"] = "USRP2"; -                new_addr["transport"] = "udp";                  new_addr["addr"] = ip_addr.to_string();                  usrp2_addrs.push_back(new_addr);                  //dont break here, it will exit the while loop diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index 55ac0b192..3468a0cf1 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -19,9 +19,10 @@  #define INCLUDED_USRP2_IMPL_HPP  #include <uhd/usrp/usrp2.hpp> -#include <uhd/dict.hpp> -#include <uhd/types.hpp> -#include <uhd/time_spec.hpp> +#include <uhd/types/dict.hpp> +#include <uhd/types/stream_cmd.hpp> +#include <uhd/types/clock_config.hpp> +#include <boost/asio.hpp>  #include <boost/thread.hpp>  #include <boost/shared_ptr.hpp>  #include <boost/function.hpp> @@ -105,8 +106,8 @@ public:      double get_master_clock_freq(void);      //the io interface -    size_t send(const boost::asio::const_buffer &, const uhd::tx_metadata_t &, const std::string &); -    size_t recv(const boost::asio::mutable_buffer &, uhd::rx_metadata_t &, const std::string &); +    size_t send(const boost::asio::const_buffer &, const uhd::tx_metadata_t &, const uhd::io_type_t &); +    size_t recv(const boost::asio::mutable_buffer &, uhd::rx_metadata_t &, const uhd::io_type_t &);  private:      //device properties interface @@ -146,11 +147,6 @@ private:      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_ref_source_t> _ref_source_dict; -    uhd::dict<std::string, usrp2_pps_source_t> _pps_source_dict; -    uhd::dict<uhd::clock_config_t::polarity_t, usrp2_pps_polarity_t> _pps_polarity_dict; -      //rx and tx dboard methods and objects      uhd::usrp::dboard_manager::sptr _dboard_manager;      void dboard_init(void); @@ -177,16 +173,14 @@ private:      //methods and shadows for the ddc dsp      std::vector<size_t> _allowed_decim_and_interp_rates;      size_t _ddc_decim; -    uhd::freq_t _ddc_freq; -    bool _ddc_enabled; -    uhd::time_spec_t _ddc_stream_at; +    double _ddc_freq;      void init_ddc_config(void);      void update_ddc_config(void); -    void update_ddc_enabled(void); +    void issue_ddc_stream_cmd(const uhd::stream_cmd_t &stream_cmd);      //methods and shadows for the duc dsp      size_t _duc_interp; -    uhd::freq_t _duc_freq; +    double _duc_freq;      void init_duc_config(void);      void update_duc_config(void); | 
