diff options
Diffstat (limited to 'host/lib')
87 files changed, 2794 insertions, 1847 deletions
| diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt index 498841561..d2845ffda 100644 --- a/host/lib/CMakeLists.txt +++ b/host/lib/CMakeLists.txt @@ -1,5 +1,5 @@  # -# Copyright 2010 Ettus Research LLC +# Copyright 2010-2011 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 @@ -16,27 +16,6 @@  #  ######################################################################## -# Check Python Modules -######################################################################## -INCLUDE(UHDPython) - -PYTHON_CHECK_MODULE( -    "Python version 2.6 or greater" -    "platform" "platform.python_version() >= '2.6'" -    HAVE_PYTHON_PLAT_MIN_VERSION -) - -PYTHON_CHECK_MODULE( -    "Cheetah templates 2.0.0 or greater" -    "Cheetah" "Cheetah.Version >= '2.0.0'" -    HAVE_PYTHON_MODULE_CHEETAH -) - -IF(NOT HAVE_PYTHON_PLAT_MIN_VERSION OR NOT HAVE_PYTHON_MODULE_CHEETAH) -    MESSAGE(FATAL_ERROR "Error: python requirements not met for the build system.") -ENDIF(NOT HAVE_PYTHON_PLAT_MIN_VERSION OR NOT HAVE_PYTHON_MODULE_CHEETAH) - -########################################################################  # Helpful Macros  ########################################################################  MACRO(LIBUHD_APPEND_SOURCES) @@ -89,6 +68,8 @@ ENDMACRO(INCLUDE_SUBDIRECTORY)  # Include subdirectories (different than add)  ########################################################################  INCLUDE_SUBDIRECTORY(ic_reg_maps) +INCLUDE_SUBDIRECTORY(types) +INCLUDE_SUBDIRECTORY(convert)  INCLUDE_SUBDIRECTORY(transport)  INCLUDE_SUBDIRECTORY(usrp)  INCLUDE_SUBDIRECTORY(utils) @@ -116,7 +97,6 @@ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})  LIBUHD_APPEND_SOURCES(      ${CMAKE_CURRENT_BINARY_DIR}/constants.hpp      ${CMAKE_CURRENT_SOURCE_DIR}/device.cpp -    ${CMAKE_CURRENT_SOURCE_DIR}/types.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/version.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/wax.cpp  ) @@ -127,6 +107,7 @@ LIBUHD_APPEND_SOURCES(  ADD_LIBRARY(uhd SHARED ${libuhd_sources})  TARGET_LINK_LIBRARIES(uhd ${Boost_LIBRARIES} ${libuhd_libs})  SET_TARGET_PROPERTIES(uhd PROPERTIES DEFINE_SYMBOL "UHD_DLL_EXPORTS") +SET_TARGET_PROPERTIES(uhd PROPERTIES SOVERSION ${UHD_VERSION_MAJOR})  INSTALL(TARGETS uhd      LIBRARY DESTINATION ${LIBRARY_DIR} # .so file diff --git a/host/lib/convert/CMakeLists.txt b/host/lib/convert/CMakeLists.txt new file mode 100644 index 000000000..a9f977cdc --- /dev/null +++ b/host/lib/convert/CMakeLists.txt @@ -0,0 +1,65 @@ +# +# Copyright 2011 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 included, use CMake directory variables +######################################################################## +INCLUDE(CheckIncludeFileCXX) +MESSAGE(STATUS "") + +######################################################################## +# Check for SIMD headers +######################################################################## +CHECK_INCLUDE_FILE_CXX(emmintrin.h HAVE_EMMINTRIN_H) +IF(HAVE_EMMINTRIN_H) +    LIBUHD_APPEND_SOURCES( +        ${CMAKE_CURRENT_SOURCE_DIR}/convert_with_sse2.cpp +    ) +ENDIF(HAVE_EMMINTRIN_H) + +CHECK_INCLUDE_FILE_CXX(arm_neon.h HAVE_ARM_NEON_H) +IF(HAVE_ARM_NEON_H) +    LIBUHD_APPEND_SOURCES( +        ${CMAKE_CURRENT_SOURCE_DIR}/convert_with_neon.cpp +    ) +ENDIF(HAVE_ARM_NEON_H) + +######################################################################## +# Convert types generation +######################################################################## +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) + +LIBUHD_PYTHON_GEN_SOURCE( +    ${CMAKE_CURRENT_SOURCE_DIR}/gen_convert_pred.py +    ${CMAKE_CURRENT_BINARY_DIR}/convert_pred.hpp +) + +INCLUDE(AddFileDependencies) +ADD_FILE_DEPENDENCIES( +    ${CMAKE_CURRENT_SOURCE_DIR}/convert_impl.cpp +    ${CMAKE_CURRENT_BINARY_DIR}/convert_pred.hpp +) + +LIBUHD_PYTHON_GEN_SOURCE( +    ${CMAKE_CURRENT_SOURCE_DIR}/gen_convert_general.py +    ${CMAKE_CURRENT_BINARY_DIR}/convert_general.cpp +) + +LIBUHD_APPEND_SOURCES( +    ${CMAKE_CURRENT_SOURCE_DIR}/convert_impl.cpp +) diff --git a/host/lib/convert/convert_common.hpp b/host/lib/convert/convert_common.hpp new file mode 100644 index 000000000..1a653a56f --- /dev/null +++ b/host/lib/convert/convert_common.hpp @@ -0,0 +1,90 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_LIBUHD_CONVERT_COMMON_HPP +#define INCLUDED_LIBUHD_CONVERT_COMMON_HPP + +#include <uhd/convert.hpp> +#include <uhd/utils/static.hpp> +#include <boost/cstdint.hpp> +#include <complex> + +#define DECLARE_CONVERTER(fcn, prio) \ +    static void fcn( \ +        uhd::convert::input_type &inputs, \ +        uhd::convert::output_type &outputs, \ +        size_t nsamps \ +    ); \ +    UHD_STATIC_BLOCK(register_##fcn##_##prio){ \ +        uhd::convert::register_converter(#fcn, fcn, prio); \ +    } \ +    static void fcn( \ +        uhd::convert::input_type &inputs, \ +        uhd::convert::output_type &outputs, \ +        size_t nsamps \ +    ) + +/*********************************************************************** + * Typedefs + **********************************************************************/ +typedef std::complex<float>          fc32_t; +typedef std::complex<boost::int16_t> sc16_t; +typedef boost::uint32_t              item32_t; + +/*********************************************************************** + * Convert complex short buffer to items32 + **********************************************************************/ +static UHD_INLINE item32_t sc16_to_item32(sc16_t num){ +    boost::uint16_t real = num.real(); +    boost::uint16_t imag = num.imag(); +    return (item32_t(real) << 16) | (item32_t(imag) << 0); +} + +/*********************************************************************** + * Convert items32 buffer to complex short + **********************************************************************/ +static UHD_INLINE sc16_t item32_to_sc16(item32_t item){ +    return sc16_t( +        boost::int16_t(item >> 16), +        boost::int16_t(item >> 0) +    ); +} + +/*********************************************************************** + * Convert complex float buffer to items32 (no swap) + **********************************************************************/ +static const float shorts_per_float = float(32767); + +static UHD_INLINE item32_t fc32_to_item32(fc32_t num){ +    boost::uint16_t real = boost::int16_t(num.real()*shorts_per_float); +    boost::uint16_t imag = boost::int16_t(num.imag()*shorts_per_float); +    return (item32_t(real) << 16) | (item32_t(imag) << 0); +} + +/*********************************************************************** + * Convert items32 buffer to complex float + **********************************************************************/ +static const float floats_per_short = float(1.0/shorts_per_float); + +static UHD_INLINE fc32_t item32_to_fc32(item32_t item){ +    return fc32_t( +        float(boost::int16_t(item >> 16)*floats_per_short), +        float(boost::int16_t(item >> 0)*floats_per_short) +    ); +} + +#endif /* INCLUDED_LIBUHD_CONVERT_COMMON_HPP */ diff --git a/host/lib/convert/convert_impl.cpp b/host/lib/convert/convert_impl.cpp new file mode 100644 index 000000000..6a5a1465d --- /dev/null +++ b/host/lib/convert/convert_impl.cpp @@ -0,0 +1,111 @@ +// +// Copyright 2011 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/convert.hpp> +#include <uhd/utils/static.hpp> +#include <uhd/utils/exception.hpp> +#include <iostream> + +using namespace uhd; + +#include "convert_pred.hpp" + +static const bool debug = false; + +/*********************************************************************** + * Define types for the function tables + **********************************************************************/ +struct fcn_table_entry_type{ +    convert::priority_type prio; +    convert::function_type fcn; +    fcn_table_entry_type(void) +    : prio(convert::PRIORITY_EMPTY), fcn(NULL){ +        /* NOP */ +    } +}; +typedef std::vector<fcn_table_entry_type> fcn_table_type; + +/*********************************************************************** + * Setup the table registry + **********************************************************************/ +UHD_SINGLETON_FCN(fcn_table_type, get_cpu_to_otw_table); +UHD_SINGLETON_FCN(fcn_table_type, get_otw_to_cpu_table); + +fcn_table_type &get_table(dir_type dir){ +    switch(dir){ +    case DIR_OTW_TO_CPU: return get_otw_to_cpu_table(); +    case DIR_CPU_TO_OTW: return get_cpu_to_otw_table(); +    } +    UHD_THROW_INVALID_CODE_PATH(); +} + +/*********************************************************************** + * The registry functions + **********************************************************************/ +void uhd::convert::register_converter( +    const std::string &markup, +    function_type fcn, +    priority_type prio +){ +    //extract the predicate and direction from the markup +    dir_type dir; +    pred_type pred = make_pred(markup, dir); + +    //get a reference to the function table +    fcn_table_type &table = get_table(dir); + +    //resize the table so that its at least pred+1 +    if (table.size() <= pred) table.resize(pred+1); + +    //register the function if higher priority +    if (table[pred].prio < prio){ +        table[pred].fcn = fcn; +        table[pred].prio = prio; +    } + +    //----------------------------------------------------------------// +    if (debug) std::cout << "register_converter: " << markup << std::endl +        << "    prio: " << prio << std::endl +        << "    pred: " << pred << std::endl +        << "    dir: " << dir << std::endl +        << std::endl +    ; +    //----------------------------------------------------------------// +} + +/*********************************************************************** + * The converter functions + **********************************************************************/ +const convert::function_type &convert::get_converter_cpu_to_otw( +    const io_type_t &io_type, +    const otw_type_t &otw_type, +    size_t num_input_buffs, +    size_t num_output_buffs +){ +    pred_type pred = make_pred(io_type, otw_type, num_input_buffs, num_output_buffs); +    return get_cpu_to_otw_table().at(pred).fcn; +} + +const convert::function_type &convert::get_converter_otw_to_cpu( +    const io_type_t &io_type, +    const otw_type_t &otw_type, +    size_t num_input_buffs, +    size_t num_output_buffs +){ +    pred_type pred = make_pred(io_type, otw_type, num_input_buffs, num_output_buffs); +    return get_otw_to_cpu_table().at(pred).fcn; +} diff --git a/host/lib/convert/convert_with_neon.cpp b/host/lib/convert/convert_with_neon.cpp new file mode 100644 index 000000000..3d677db5b --- /dev/null +++ b/host/lib/convert/convert_with_neon.cpp @@ -0,0 +1,61 @@ +// +// Copyright 2011-2011 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 "convert_common.hpp" +#include <arm_neon.h> + +using namespace uhd::convert; + +DECLARE_CONVERTER(convert_fc32_1_to_item32_1_nswap, PRIORITY_CUSTOM){ +    const fc32_t *input = reinterpret_cast<const fc32_t *>(inputs[0]); +    item32_t *output = reinterpret_cast<item32_t *>(outputs[0]); + +    size_t i; + +    float32x4_t Q0 = vdupq_n_f32(shorts_per_float); +    for (i=0; i < (nsamps & ~0x03); i+=2) { +        float32x4_t Q1 = vld1q_f32(reinterpret_cast<const float *>(&input[i])); +        float32x4_t Q2 = vmulq_f32(Q1, Q0); +        int32x4_t Q3 = vcvtq_s32_f32(Q2); +        int16x4_t D8 = vmovn_s32(Q3); +        int16x4_t D9 = vrev32_s16(D8); +        vst1_s16((reinterpret_cast<int16_t *>(&output[i])), D9); +    } + +    for (; i < nsamps; i++) +        output[i] = fc32_to_item32(input[i]); +} + +DECLARE_CONVERTER(convert_item32_1_to_fc32_1_nswap, PRIORITY_CUSTOM){ +    const item32_t *input = reinterpret_cast<const item32_t *>(inputs[0]); +    fc32_t *output = reinterpret_cast<fc32_t *>(outputs[0]); + +    size_t i; + +    float32x4_t Q1 = vdupq_n_f32(floats_per_short); +    for (i=0; i < (nsamps & ~0x03); i+=2) { +        int16x4_t D0 = vld1_s16(reinterpret_cast<const int16_t *>(&input[i])); +        int16x4_t D1 = vrev32_s16(D0); +        int32x4_t Q2 = vmovl_s16(D1); +        float32x4_t Q3 = vcvtq_f32_s32(Q2); +        float32x4_t Q4 = vmulq_f32(Q3, Q1); +        vst1q_f32((reinterpret_cast<float *>(&output[i])), Q4); +    } + +    for (; i < nsamps; i++) +        output[i] = item32_to_fc32(input[i]); +} diff --git a/host/lib/convert/convert_with_sse2.cpp b/host/lib/convert/convert_with_sse2.cpp new file mode 100644 index 000000000..96ee9134c --- /dev/null +++ b/host/lib/convert/convert_with_sse2.cpp @@ -0,0 +1,148 @@ +// +// Copyright 2011-2011 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 "convert_common.hpp" +#include <uhd/utils/byteswap.hpp> +#include <emmintrin.h> + +using namespace uhd::convert; + +DECLARE_CONVERTER(convert_fc32_1_to_item32_1_nswap, PRIORITY_CUSTOM){ +    const fc32_t *input = reinterpret_cast<const fc32_t *>(inputs[0]); +    item32_t *output = reinterpret_cast<item32_t *>(outputs[0]); + +    __m128 scalar = _mm_set_ps1(shorts_per_float); + +    //convert blocks of samples with intrinsics +    size_t i = 0; for (; i < (nsamps & ~0x3); i+=4){ +        //load from input +        __m128 tmplo = _mm_loadu_ps(reinterpret_cast<const float *>(input+i+0)); +        __m128 tmphi = _mm_loadu_ps(reinterpret_cast<const float *>(input+i+2)); + +        //convert and scale +        __m128i tmpilo = _mm_cvtps_epi32(_mm_mul_ps(tmplo, scalar)); +        __m128i tmpihi = _mm_cvtps_epi32(_mm_mul_ps(tmphi, scalar)); + +        //pack + swap 16-bit pairs +        __m128i tmpi = _mm_packs_epi32(tmpilo, tmpihi); +        tmpi = _mm_shufflelo_epi16(tmpi, _MM_SHUFFLE(2, 3, 0, 1)); +        tmpi = _mm_shufflehi_epi16(tmpi, _MM_SHUFFLE(2, 3, 0, 1)); + +        //store to output +        _mm_storeu_si128(reinterpret_cast<__m128i *>(output+i), tmpi); +    } + +    //convert remainder +    for (; i < nsamps; i++){ +        output[i] = fc32_to_item32(input[i]); +    } +} + +DECLARE_CONVERTER(convert_fc32_1_to_item32_1_bswap, PRIORITY_CUSTOM){ +    const fc32_t *input = reinterpret_cast<const fc32_t *>(inputs[0]); +    item32_t *output = reinterpret_cast<item32_t *>(outputs[0]); + +    __m128 scalar = _mm_set_ps1(shorts_per_float); + +    //convert blocks of samples with intrinsics +    size_t i = 0; for (; i < (nsamps & ~0x3); i+=4){ +        //load from input +        __m128 tmplo = _mm_loadu_ps(reinterpret_cast<const float *>(input+i+0)); +        __m128 tmphi = _mm_loadu_ps(reinterpret_cast<const float *>(input+i+2)); + +        //convert and scale +        __m128i tmpilo = _mm_cvtps_epi32(_mm_mul_ps(tmplo, scalar)); +        __m128i tmpihi = _mm_cvtps_epi32(_mm_mul_ps(tmphi, scalar)); + +        //pack + byteswap -> byteswap 16 bit words +        __m128i tmpi = _mm_packs_epi32(tmpilo, tmpihi); +        tmpi = _mm_or_si128(_mm_srli_epi16(tmpi, 8), _mm_slli_epi16(tmpi, 8)); + +        //store to output +        _mm_storeu_si128(reinterpret_cast<__m128i *>(output+i), tmpi); +    } + +    //convert remainder +    for (; i < nsamps; i++){ +        output[i] = uhd::byteswap(fc32_to_item32(input[i])); +    } +} + +DECLARE_CONVERTER(convert_item32_1_to_fc32_1_nswap, PRIORITY_CUSTOM){ +    const item32_t *input = reinterpret_cast<const item32_t *>(inputs[0]); +    fc32_t *output = reinterpret_cast<fc32_t *>(outputs[0]); + +    __m128 scalar = _mm_set_ps1(floats_per_short/(1 << 16)); +    __m128i zeroi = _mm_setzero_si128(); + +    //convert blocks of samples with intrinsics +    size_t i = 0; for (; i < (nsamps & ~0x3); i+=4){ +        //load from input +        __m128i tmpi = _mm_loadu_si128(reinterpret_cast<const __m128i *>(input+i)); + +        //unpack + swap 16-bit pairs +        tmpi = _mm_shufflelo_epi16(tmpi, _MM_SHUFFLE(2, 3, 0, 1)); +        tmpi = _mm_shufflehi_epi16(tmpi, _MM_SHUFFLE(2, 3, 0, 1)); +        __m128i tmpilo = _mm_unpacklo_epi16(zeroi, tmpi); //value in upper 16 bits +        __m128i tmpihi = _mm_unpackhi_epi16(zeroi, tmpi); + +        //convert and scale +        __m128 tmplo = _mm_mul_ps(_mm_cvtepi32_ps(tmpilo), scalar); +        __m128 tmphi = _mm_mul_ps(_mm_cvtepi32_ps(tmpihi), scalar); + +        //store to output +        _mm_storeu_ps(reinterpret_cast<float *>(output+i+0), tmplo); +        _mm_storeu_ps(reinterpret_cast<float *>(output+i+2), tmphi); +    } + +    //convert remainder +    for (; i < nsamps; i++){ +        output[i] = item32_to_fc32(input[i]); +    } +} + +DECLARE_CONVERTER(convert_item32_1_to_fc32_1_bswap, PRIORITY_CUSTOM){ +    const item32_t *input = reinterpret_cast<const item32_t *>(inputs[0]); +    fc32_t *output = reinterpret_cast<fc32_t *>(outputs[0]); + +    __m128 scalar = _mm_set_ps1(floats_per_short/(1 << 16)); +    __m128i zeroi = _mm_setzero_si128(); + +    //convert blocks of samples with intrinsics +    size_t i = 0; for (; i < (nsamps & ~0x3); i+=4){ +        //load from input +        __m128i tmpi = _mm_loadu_si128(reinterpret_cast<const __m128i *>(input+i)); + +        //byteswap + unpack -> byteswap 16 bit words +        tmpi = _mm_or_si128(_mm_srli_epi16(tmpi, 8), _mm_slli_epi16(tmpi, 8)); +        __m128i tmpilo = _mm_unpacklo_epi16(zeroi, tmpi); //value in upper 16 bits +        __m128i tmpihi = _mm_unpackhi_epi16(zeroi, tmpi); + +        //convert and scale +        __m128 tmplo = _mm_mul_ps(_mm_cvtepi32_ps(tmpilo), scalar); +        __m128 tmphi = _mm_mul_ps(_mm_cvtepi32_ps(tmpihi), scalar); + +        //store to output +        _mm_storeu_ps(reinterpret_cast<float *>(output+i+0), tmplo); +        _mm_storeu_ps(reinterpret_cast<float *>(output+i+2), tmphi); +    } + +    //convert remainder +    for (; i < nsamps; i++){ +        output[i] = item32_to_fc32(uhd::byteswap(input[i])); +    } +} diff --git a/host/lib/convert/gen_convert_general.py b/host/lib/convert/gen_convert_general.py new file mode 100644 index 000000000..47c4cd7d0 --- /dev/null +++ b/host/lib/convert/gen_convert_general.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python +# +# Copyright 2011 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/>. +# + +TMPL_HEADER = """ +#import time +/*********************************************************************** + * This file was generated by $file on $time.strftime("%c") + **********************************************************************/ + +\#include "convert_common.hpp" +\#include <uhd/utils/byteswap.hpp> + +using namespace uhd::convert; +""" + +TMPL_CONV_TO_FROM_ITEM32_1 = """ +DECLARE_CONVERTER(convert_$(cpu_type)_1_to_item32_1_$(swap), PRIORITY_GENERAL){ +    const $(cpu_type)_t *input = reinterpret_cast<const $(cpu_type)_t *>(inputs[0]); +    item32_t *output = reinterpret_cast<item32_t *>(outputs[0]); + +    for (size_t i = 0; i < nsamps; i++){ +        output[i] = $(swap_fcn)($(cpu_type)_to_item32(input[i])); +    } +} + +DECLARE_CONVERTER(convert_item32_1_to_$(cpu_type)_1_$(swap), PRIORITY_GENERAL){ +    const item32_t *input = reinterpret_cast<const item32_t *>(inputs[0]); +    $(cpu_type)_t *output = reinterpret_cast<$(cpu_type)_t *>(outputs[0]); + +    for (size_t i = 0; i < nsamps; i++){ +        output[i] = item32_to_$(cpu_type)($(swap_fcn)(input[i])); +    } +} +""" +TMPL_CONV_TO_FROM_ITEM32_X = """ +DECLARE_CONVERTER(convert_$(cpu_type)_$(width)_to_item32_1_$(swap), PRIORITY_GENERAL){ +    #for $w in range($width) +    const $(cpu_type)_t *input$(w) = reinterpret_cast<const $(cpu_type)_t *>(inputs[$(w)]); +    #end for +    item32_t *output = reinterpret_cast<item32_t *>(outputs[0]); + +    for (size_t i = 0, j = 0; i < nsamps; i++){ +        #for $w in range($width) +        output[j++] = $(swap_fcn)($(cpu_type)_to_item32(input$(w)[i])); +        #end for +    } +} + +DECLARE_CONVERTER(convert_item32_1_to_$(cpu_type)_$(width)_$(swap), PRIORITY_GENERAL){ +    const item32_t *input = reinterpret_cast<const item32_t *>(inputs[0]); +    #for $w in range($width) +    $(cpu_type)_t *output$(w) = reinterpret_cast<$(cpu_type)_t *>(outputs[$(w)]); +    #end for + +    for (size_t i = 0, j = 0; i < nsamps; i++){ +        #for $w in range($width) +        output$(w)[i] = item32_to_$(cpu_type)($(swap_fcn)(input[j++])); +        #end for +    } +} +""" + +def parse_tmpl(_tmpl_text, **kwargs): +    from Cheetah.Template import Template +    return str(Template(_tmpl_text, kwargs)) + +if __name__ == '__main__': +    import sys, os +    file = os.path.basename(__file__) +    output = parse_tmpl(TMPL_HEADER, file=file) +    for width in 1, 2, 3, 4: +        for swap, swap_fcn in (('nswap', ''), ('bswap', 'uhd::byteswap')): +            for cpu_type in 'fc32', 'sc16': +                output += parse_tmpl( +                    TMPL_CONV_TO_FROM_ITEM32_1 if width == 1 else TMPL_CONV_TO_FROM_ITEM32_X, +                    width=width, swap=swap, swap_fcn=swap_fcn, cpu_type=cpu_type +                ) +    open(sys.argv[1], 'w').write(output) diff --git a/host/lib/convert/gen_convert_pred.py b/host/lib/convert/gen_convert_pred.py new file mode 100644 index 000000000..1d573bf1a --- /dev/null +++ b/host/lib/convert/gen_convert_pred.py @@ -0,0 +1,163 @@ +#!/usr/bin/env python +# +# Copyright 2011-2011 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/>. +# + +TMPL_TEXT = """ +#import time +/*********************************************************************** + * This file was generated by $file on $time.strftime("%c") + **********************************************************************/ +typedef size_t pred_type; + +\#include <boost/tokenizer.hpp> +\#include <boost/lexical_cast.hpp> +\#include <boost/detail/endian.hpp> +\#include <boost/cstdint.hpp> +\#include <stdexcept> +\#include <string> +\#include <vector> + +enum dir_type{ +    DIR_OTW_TO_CPU = 0, +    DIR_CPU_TO_OTW = 1 +}; + +struct pred_error : std::runtime_error{ +    pred_error(const std::string &what) +    :std::runtime_error("convert::make_pred: " + what){ +        /* NOP */ +    } +}; + +pred_type make_pred(const std::string &markup, dir_type &dir){ +    pred_type pred = 0; + +    try{ +        boost::tokenizer<boost::char_separator<char> > tokenizer(markup, boost::char_separator<char>("_")); +        std::vector<std::string> tokens(tokenizer.begin(), tokenizer.end()); +        //token 0 is <convert> +        std::string inp_type = tokens.at(1); +        std::string num_inps = tokens.at(2); +        //token 3 is <to> +        std::string out_type = tokens.at(4); +        std::string num_outs = tokens.at(5); +        std::string swap_type = tokens.at(6); + +        std::string cpu_type, otw_type; +        if (inp_type.find("item") == std::string::npos){ +            cpu_type = inp_type; +            otw_type = out_type; +            dir = DIR_CPU_TO_OTW; +        } +        else{ +            cpu_type = out_type; +            otw_type = inp_type; +            dir = DIR_OTW_TO_CPU; +        } + +        if      (cpu_type == "fc32") pred |= $ph.fc32_p; +        else if (cpu_type == "sc16") pred |= $ph.sc16_p; +        else throw pred_error("unhandled io type " + cpu_type); + +        if (otw_type == "item32") pred |= $ph.item32_p; +        else throw pred_error("unhandled otw type " + otw_type); + +        int num_inputs = boost::lexical_cast<int>(num_inps); +        int num_outputs = boost::lexical_cast<int>(num_outs); + +        switch(num_inputs*num_outputs){ //FIXME treated as one value +        case 1: pred |= $ph.chan1_p; break; +        case 2: pred |= $ph.chan2_p; break; +        case 3: pred |= $ph.chan3_p; break; +        case 4: pred |= $ph.chan4_p; break; +        default: throw pred_error("unhandled number of channels"); +        } + +        if      (swap_type == "bswap") pred |= $ph.bswap_p; +        else if (swap_type == "nswap") pred |= $ph.nswap_p; +        else throw pred_error("unhandled swap type"); + +    } +    catch(...){ +        throw pred_error("could not parse markup: " + markup); +    } + +    return pred; +} + +UHD_INLINE pred_type make_pred( +    const io_type_t &io_type, +    const otw_type_t &otw_type, +    size_t num_inputs, +    size_t num_outputs +){ +    pred_type pred = 0; + +    switch(otw_type.byteorder){ +    \#ifdef BOOST_BIG_ENDIAN +    case otw_type_t::BO_BIG_ENDIAN:    pred |= $ph.nswap_p; break; +    case otw_type_t::BO_LITTLE_ENDIAN: pred |= $ph.bswap_p; break; +    \#else +    case otw_type_t::BO_BIG_ENDIAN:    pred |= $ph.bswap_p; break; +    case otw_type_t::BO_LITTLE_ENDIAN: pred |= $ph.nswap_p; break; +    \#endif +    case otw_type_t::BO_NATIVE:        pred |= $ph.nswap_p; break; +    default: throw pred_error("unhandled otw byteorder type"); +    } + +    switch(otw_type.get_sample_size()){ +    case sizeof(boost::uint32_t): pred |= $ph.item32_p; break; +    default: throw pred_error("unhandled otw sample size"); +    } + +    switch(io_type.tid){ +    case io_type_t::COMPLEX_FLOAT32: pred |= $ph.fc32_p; break; +    case io_type_t::COMPLEX_INT16:   pred |= $ph.sc16_p; break; +    default: throw pred_error("unhandled io type id"); +    } + +    switch(num_inputs*num_outputs){ //FIXME treated as one value +    case 1: pred |= $ph.chan1_p; break; +    case 2: pred |= $ph.chan2_p; break; +    case 3: pred |= $ph.chan3_p; break; +    case 4: pred |= $ph.chan4_p; break; +    default: throw pred_error("unhandled number of channels"); +    } + +    return pred; +} +""" + +def parse_tmpl(_tmpl_text, **kwargs): +    from Cheetah.Template import Template +    return str(Template(_tmpl_text, kwargs)) + +class ph: +    bswap_p  = 0b00001 +    nswap_p  = 0b00000 +    item32_p = 0b00000 +    sc16_p   = 0b00010 +    fc32_p   = 0b00000 +    chan1_p  = 0b00000 +    chan2_p  = 0b00100 +    chan3_p  = 0b01000 +    chan4_p  = 0b01100 + +if __name__ == '__main__': +    import sys, os +    file = os.path.basename(__file__) +    open(sys.argv[1], 'w').write(parse_tmpl(TMPL_TEXT, file=file, ph=ph)) diff --git a/host/lib/gain_group.cpp b/host/lib/gain_group.cpp deleted file mode 100644 index 1be09dee2..000000000 --- a/host/lib/gain_group.cpp +++ /dev/null @@ -1,149 +0,0 @@ -// -// Copyright 2010 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program.  If not, see <http://www.gnu.org/licenses/>. -// - -#include <uhd/utils/gain_group.hpp> -#include <uhd/types/dict.hpp> -#include <uhd/utils/algorithm.hpp> -#include <uhd/utils/assert.hpp> -#include <boost/foreach.hpp> -#include <boost/bind.hpp> -#include <algorithm> -#include <vector> -#include <iostream> - -using namespace uhd; - -static const bool verbose = false; - -static bool compare_by_step_size( -    const size_t &rhs, const size_t &lhs, std::vector<gain_fcns_t> &fcns -){ -    return fcns.at(rhs).get_range().step > fcns.at(lhs).get_range().step; -} - -/*********************************************************************** - * gain group implementation - **********************************************************************/ -class gain_group_impl : public gain_group{ -public: -    gain_group_impl(void){ -        /*NOP*/ -    } - -    gain_range_t get_range(void){ -        float overall_min = 0, overall_max = 0, overall_step = 0; -        BOOST_FOREACH(const gain_fcns_t &fcns, get_all_fcns()){ -            const gain_range_t range = fcns.get_range(); -            overall_min += range.min; -            overall_max += range.max; -            //the overall step is the min (zero is invalid, first run) -            if (overall_step == 0) overall_step = range.step; -            overall_step = std::min(overall_step, range.step); -        } -        return gain_range_t(overall_min, overall_max, overall_step); -    } - -    float get_value(void){ -        float overall_gain = 0; -        BOOST_FOREACH(const gain_fcns_t &fcns, get_all_fcns()){ -            overall_gain += fcns.get_value(); -        } -        return overall_gain; -    } - -    void set_value(float gain){ -        std::vector<gain_fcns_t> all_fcns = get_all_fcns(); -        if (all_fcns.size() == 0) return; //nothing to set! - -        //get the max step size among the gains -        float max_step = 0; -        BOOST_FOREACH(const gain_fcns_t &fcns, all_fcns){ -            max_step = std::max(max_step, fcns.get_range().step); -        } - -        //create gain bucket to distribute power -        std::vector<float> gain_bucket; - -        //distribute power according to priority (round to max step) -        float gain_left_to_distribute = gain; -        BOOST_FOREACH(const gain_fcns_t &fcns, all_fcns){ -            const gain_range_t range = fcns.get_range(); -            gain_bucket.push_back( -                max_step*int(std::clip(gain_left_to_distribute, range.min, range.max)/max_step) -            ); -            gain_left_to_distribute -= gain_bucket.back(); -        } - -        //get a list of indexes sorted by step size large to small -        std::vector<size_t> indexes_step_size_dec; -        for (size_t i = 0; i < all_fcns.size(); i++){ -            indexes_step_size_dec.push_back(i); -        } -        std::sort( -            indexes_step_size_dec.begin(), indexes_step_size_dec.end(), -            boost::bind(&compare_by_step_size, _1, _2, all_fcns) -        ); -        UHD_ASSERT_THROW( -            all_fcns.at(indexes_step_size_dec.front()).get_range().step >= -            all_fcns.at(indexes_step_size_dec.back()).get_range().step -        ); - -        //distribute the remainder (less than max step) -        //fill in the largest step sizes first that are less than the remainder -        BOOST_FOREACH(size_t i, indexes_step_size_dec){ -            const gain_range_t range = all_fcns.at(i).get_range(); -            float additional_gain = range.step*int( -                std::clip(gain_bucket.at(i) + gain_left_to_distribute, range.min, range.max -            )/range.step) - gain_bucket.at(i); -            gain_bucket.at(i) += additional_gain; -            gain_left_to_distribute -= additional_gain; -        } -        if (verbose) std::cout << "gain_left_to_distribute " << gain_left_to_distribute << std::endl; - -        //now write the bucket out to the individual gain values -        for (size_t i = 0; i < gain_bucket.size(); i++){ -            if (verbose) std::cout << gain_bucket.at(i) << std::endl; -            all_fcns.at(i).set_value(gain_bucket.at(i)); -        } -    } - -    void register_fcns( -        const gain_fcns_t &gain_fcns, size_t priority -    ){ -        _registry[priority].push_back(gain_fcns); -    } - -private: -    //! get the gain function sets in order (highest priority first) -    std::vector<gain_fcns_t> get_all_fcns(void){ -        std::vector<gain_fcns_t> all_fcns; -        BOOST_FOREACH(ssize_t key, std::sorted(_registry.keys())){ -            const std::vector<gain_fcns_t> &fcns = _registry[key]; -            all_fcns.insert(all_fcns.begin(), fcns.begin(), fcns.end()); -        } -        return all_fcns; -    } - -    uhd::dict<size_t, std::vector<gain_fcns_t> > _registry; -}; - -/*********************************************************************** - * gain group factory function - **********************************************************************/ -gain_group::sptr gain_group::make(void){ -    return sptr(new gain_group_impl()); -} diff --git a/host/lib/transport/CMakeLists.txt b/host/lib/transport/CMakeLists.txt index 0d6226e4c..8765c6703 100644 --- a/host/lib/transport/CMakeLists.txt +++ b/host/lib/transport/CMakeLists.txt @@ -1,5 +1,5 @@  # -# Copyright 2010 Ettus Research LLC +# Copyright 2010-2011 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 @@ -23,7 +23,7 @@  # Setup libusb  ########################################################################  MESSAGE(STATUS "") -FIND_PACKAGE(USB1 REQUIRED) +FIND_PACKAGE(USB1)  LIBUHD_REGISTER_COMPONENT("USB" ENABLE_USB ON "ENABLE_LIBUHD;LIBUSB_FOUND" OFF) @@ -37,9 +37,6 @@ IF(ENABLE_USB)          ${CMAKE_CURRENT_SOURCE_DIR}/libusb1_base.cpp          ${CMAKE_CURRENT_SOURCE_DIR}/libusb1_base.hpp      ) -    IF(MSVC) #include our custom stdint for libusb -        INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/msvc) -    ENDIF(MSVC)  ELSE(ENABLE_USB)      LIBUHD_APPEND_SOURCES(          ${CMAKE_CURRENT_SOURCE_DIR}/usb_dummy_impl.cpp @@ -47,25 +44,6 @@ ELSE(ENABLE_USB)  ENDIF(ENABLE_USB)  ######################################################################## -# Check for SIMD headers -######################################################################## -MESSAGE(STATUS "") - -INCLUDE(CheckIncludeFileCXX) -CHECK_INCLUDE_FILE_CXX(emmintrin.h HAVE_EMMINTRIN_H) - -IF(HAVE_EMMINTRIN_H) -    ADD_DEFINITIONS(-DHAVE_EMMINTRIN_H) -ENDIF(HAVE_EMMINTRIN_H) - -INCLUDE(CheckIncludeFileCXX) -CHECK_INCLUDE_FILE_CXX(arm_neon.h HAVE_ARM_NEON_H) - -IF(HAVE_ARM_NEON_H) -    ADD_DEFINITIONS(-DHAVE_ARM_NEON_H) -ENDIF(HAVE_ARM_NEON_H) - -########################################################################  # Setup defines for interface address discovery  ########################################################################  MESSAGE(STATUS "") @@ -93,22 +71,8 @@ LIBUHD_PYTHON_GEN_SOURCE(      ${CMAKE_CURRENT_BINARY_DIR}/vrt_if_packet.cpp  ) -LIBUHD_PYTHON_GEN_SOURCE( -    ${CMAKE_CURRENT_SOURCE_DIR}/gen_convert_types.py -    ${CMAKE_CURRENT_BINARY_DIR}/convert_types.cpp -) - -# append this directory to the include path so the generated convert types -# can include the implementation convert types file in the source directory -INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) - -# make the generated convert types depend on the implementation header -SET_SOURCE_FILES_PROPERTIES( -    ${CMAKE_CURRENT_BINARY_DIR}/convert_types.cpp PROPERTIES -    OBJECT_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/convert_types_impl.hpp -) -  LIBUHD_APPEND_SOURCES( +    ${CMAKE_CURRENT_SOURCE_DIR}/buffer_pool.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/if_addrs.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/udp_simple.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/udp_zero_copy_asio.cpp diff --git a/host/lib/transport/buffer_pool.cpp b/host/lib/transport/buffer_pool.cpp new file mode 100644 index 000000000..971bbb75a --- /dev/null +++ b/host/lib/transport/buffer_pool.cpp @@ -0,0 +1,80 @@ +// +// Copyright 2011-2011 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/buffer_pool.hpp> +#include <boost/shared_array.hpp> +#include <vector> + +using namespace uhd::transport; + +//! pad the byte count to a multiple of alignment +static size_t pad_to_boundary(const size_t bytes, const size_t alignment){ +    return bytes + (alignment - bytes)%alignment; +} + +/*********************************************************************** + * Buffer pool implementation + **********************************************************************/ +class buffer_pool_impl : public buffer_pool{ +public: +    buffer_pool_impl( +        const std::vector<ptr_type> &ptrs, +        boost::shared_array<char> mem +    ): _ptrs(ptrs), _mem(mem){ +        /* NOP */ +    } + +    ptr_type at(const size_t index) const{ +        return _ptrs.at(index); +    } + +    size_t size(void) const{ +        return _ptrs.size(); +    } + +private: +    std::vector<ptr_type> _ptrs; +    boost::shared_array<char> _mem; +}; + +/*********************************************************************** + * Buffer pool factor function + **********************************************************************/ +buffer_pool::sptr buffer_pool::make( +    const size_t num_buffs, +    const size_t buff_size, +    const size_t alignment +){ +    //1) pad the buffer size to be a multiple of alignment +    //2) pad the overall memory size for room after alignment +    //3) allocate the memory in one block of sufficient size +    const size_t padded_buff_size = pad_to_boundary(buff_size, alignment); +    boost::shared_array<char> mem(new char[padded_buff_size*num_buffs + alignment-1]); + +    //Fill a vector with boundary-aligned points in the memory +    const size_t mem_start = pad_to_boundary(size_t(mem.get()), alignment); +    std::vector<ptr_type> ptrs(num_buffs); +    for (size_t i = 0; i < num_buffs; i++){ +        ptrs[i] = ptr_type(mem_start + padded_buff_size*i); +    } + +    //Create a new buffer pool implementation with: +    // - the pre-computed pointers, and +    // - the reference to allocated memory. +    return sptr(new buffer_pool_impl(ptrs, mem)); +} + diff --git a/host/lib/transport/convert_types_impl.hpp b/host/lib/transport/convert_types_impl.hpp deleted file mode 100644 index 48ff99725..000000000 --- a/host/lib/transport/convert_types_impl.hpp +++ /dev/null @@ -1,345 +0,0 @@ -// -// Copyright 2010 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program.  If not, see <http://www.gnu.org/licenses/>. -// - -#ifndef INCLUDED_LIBUHD_TRANSPORT_CONVERT_TYPES_IMPL_HPP -#define INCLUDED_LIBUHD_TRANSPORT_CONVERT_TYPES_IMPL_HPP - -#include <uhd/config.hpp> -#include <uhd/utils/byteswap.hpp> -#include <boost/cstdint.hpp> -#include <cstring> -#include <complex> - -#ifdef HAVE_EMMINTRIN_H -    #define USE_EMMINTRIN_H //use sse2 intrinsics -#endif - -#if defined(USE_EMMINTRIN_H) -    #include <emmintrin.h> -#endif - -#ifdef HAVE_ARM_NEON_H -    #define USE_ARM_NEON_H -#endif - -#if defined(USE_ARM_NEON_H) -    #include <arm_neon.h> -#endif - -/*********************************************************************** - * Typedefs - **********************************************************************/ -typedef std::complex<float>          fc32_t; -typedef std::complex<boost::int16_t> sc16_t; -typedef boost::uint32_t              item32_t; - -/*********************************************************************** - * Convert complex short buffer to items32 - **********************************************************************/ -static UHD_INLINE item32_t sc16_to_item32(sc16_t num){ -    boost::uint16_t real = num.real(); -    boost::uint16_t imag = num.imag(); -    return (item32_t(real) << 16) | (item32_t(imag) << 0); -} - -static UHD_INLINE void sc16_to_item32_nswap( -    const sc16_t *input, item32_t *output, size_t nsamps -){ -    for (size_t i = 0; i < nsamps; i++){ -        output[i] = sc16_to_item32(input[i]); -    } -} - -static UHD_INLINE void sc16_to_item32_bswap( -    const sc16_t *input, item32_t *output, size_t nsamps -){ -    for (size_t i = 0; i < nsamps; i++){ -        output[i] = uhd::byteswap(sc16_to_item32(input[i])); -    } -} - -/*********************************************************************** - * Convert items32 buffer to complex short - **********************************************************************/ -static UHD_INLINE sc16_t item32_to_sc16(item32_t item){ -    return sc16_t( -        boost::int16_t(item >> 16), -        boost::int16_t(item >> 0) -    ); -} - -static UHD_INLINE void item32_to_sc16_nswap( -    const item32_t *input, sc16_t *output, size_t nsamps -){ -    for (size_t i = 0; i < nsamps; i++){ -        output[i] = item32_to_sc16(input[i]); -    } -} - -static UHD_INLINE void item32_to_sc16_bswap( -    const item32_t *input, sc16_t *output, size_t nsamps -){ -    for (size_t i = 0; i < nsamps; i++){ -        output[i] = item32_to_sc16(uhd::byteswap(input[i])); -    } -} - -/*********************************************************************** - * Convert complex float buffer to items32 (no swap) - **********************************************************************/ -static const float shorts_per_float = float(32767); - -static UHD_INLINE item32_t fc32_to_item32(fc32_t num){ -    boost::uint16_t real = boost::int16_t(num.real()*shorts_per_float); -    boost::uint16_t imag = boost::int16_t(num.imag()*shorts_per_float); -    return (item32_t(real) << 16) | (item32_t(imag) << 0); -} - -//////////////////////////////////// -// none-swap -//////////////////////////////////// -#if defined(USE_EMMINTRIN_H) -static UHD_INLINE void fc32_to_item32_nswap( -    const fc32_t *input, item32_t *output, size_t nsamps -){ -    __m128 scalar = _mm_set_ps1(shorts_per_float); - -    //convert blocks of samples with intrinsics -    size_t i = 0; for (; i < (nsamps & ~0x3); i+=4){ -        //load from input -        __m128 tmplo = _mm_loadu_ps(reinterpret_cast<const float *>(input+i+0)); -        __m128 tmphi = _mm_loadu_ps(reinterpret_cast<const float *>(input+i+2)); - -        //convert and scale -        __m128i tmpilo = _mm_cvtps_epi32(_mm_mul_ps(tmplo, scalar)); -        __m128i tmpihi = _mm_cvtps_epi32(_mm_mul_ps(tmphi, scalar)); - -        //pack + swap 16-bit pairs -        __m128i tmpi = _mm_packs_epi32(tmpilo, tmpihi); -        tmpi = _mm_shufflelo_epi16(tmpi, _MM_SHUFFLE(2, 3, 0, 1)); -        tmpi = _mm_shufflehi_epi16(tmpi, _MM_SHUFFLE(2, 3, 0, 1)); - -        //store to output -        _mm_storeu_si128(reinterpret_cast<__m128i *>(output+i), tmpi); -    } - -    //convert remainder -    for (; i < nsamps; i++){ -        output[i] = fc32_to_item32(input[i]); -    } -} - -#elif defined(USE_ARM_NEON_H) -static UHD_INLINE void fc32_to_item32_nswap( -    const fc32_t *input, item32_t *output, size_t nsamps) -{ -    size_t i; - -    float32x4_t Q0 = vdupq_n_f32(shorts_per_float); -    for (i=0; i < (nsamps & ~0x03); i+=2) { -        float32x4_t Q1 = vld1q_f32(reinterpret_cast<const float *>(&input[i])); -        float32x4_t Q2 = vmulq_f32(Q1, Q0); -        int32x4_t Q3 = vcvtq_s32_f32(Q2); -        int16x4_t D8 = vmovn_s32(Q3); -        int16x4_t D9 = vrev32_s16(D8); -        vst1_s16((reinterpret_cast<int16_t *>(&output[i])), D9); -    } - -    for (; i < nsamps; i++) -        output[i] = fc32_to_item32(input[i]); -} - -#else -static UHD_INLINE void fc32_to_item32_nswap( -    const fc32_t *input, item32_t *output, size_t nsamps -){ -    for (size_t i = 0; i < nsamps; i++){ -        output[i] = fc32_to_item32(input[i]); -    } -} - -#endif - -//////////////////////////////////// -// byte-swap -//////////////////////////////////// -#if defined(USE_EMMINTRIN_H) -static UHD_INLINE void fc32_to_item32_bswap( -    const fc32_t *input, item32_t *output, size_t nsamps -){ -    __m128 scalar = _mm_set_ps1(shorts_per_float); - -    //convert blocks of samples with intrinsics -    size_t i = 0; for (; i < (nsamps & ~0x3); i+=4){ -        //load from input -        __m128 tmplo = _mm_loadu_ps(reinterpret_cast<const float *>(input+i+0)); -        __m128 tmphi = _mm_loadu_ps(reinterpret_cast<const float *>(input+i+2)); - -        //convert and scale -        __m128i tmpilo = _mm_cvtps_epi32(_mm_mul_ps(tmplo, scalar)); -        __m128i tmpihi = _mm_cvtps_epi32(_mm_mul_ps(tmphi, scalar)); - -        //pack + byteswap -> byteswap 16 bit words -        __m128i tmpi = _mm_packs_epi32(tmpilo, tmpihi); -        tmpi = _mm_or_si128(_mm_srli_epi16(tmpi, 8), _mm_slli_epi16(tmpi, 8)); - -        //store to output -        _mm_storeu_si128(reinterpret_cast<__m128i *>(output+i), tmpi); -    } - -    //convert remainder -    for (; i < nsamps; i++){ -        output[i] = uhd::byteswap(fc32_to_item32(input[i])); -    } -} - -#else -static UHD_INLINE void fc32_to_item32_bswap( -    const fc32_t *input, item32_t *output, size_t nsamps -){ -    for (size_t i = 0; i < nsamps; i++){ -        output[i] = uhd::byteswap(fc32_to_item32(input[i])); -    } -} - -#endif - -/*********************************************************************** - * Convert items32 buffer to complex float - **********************************************************************/ -static const float floats_per_short = float(1.0/shorts_per_float); - -static UHD_INLINE fc32_t item32_to_fc32(item32_t item){ -    return fc32_t( -        float(boost::int16_t(item >> 16)*floats_per_short), -        float(boost::int16_t(item >> 0)*floats_per_short) -    ); -} - -//////////////////////////////////// -// none-swap -//////////////////////////////////// -#if defined(USE_EMMINTRIN_H) -static UHD_INLINE void item32_to_fc32_nswap( -    const item32_t *input, fc32_t *output, size_t nsamps -){ -    __m128 scalar = _mm_set_ps1(floats_per_short/(1 << 16)); -    __m128i zeroi = _mm_setzero_si128(); - -    //convert blocks of samples with intrinsics -    size_t i = 0; for (; i < (nsamps & ~0x3); i+=4){ -        //load from input -        __m128i tmpi = _mm_loadu_si128(reinterpret_cast<const __m128i *>(input+i)); - -        //unpack + swap 16-bit pairs -        tmpi = _mm_shufflelo_epi16(tmpi, _MM_SHUFFLE(2, 3, 0, 1)); -        tmpi = _mm_shufflehi_epi16(tmpi, _MM_SHUFFLE(2, 3, 0, 1)); -        __m128i tmpilo = _mm_unpacklo_epi16(zeroi, tmpi); //value in upper 16 bits -        __m128i tmpihi = _mm_unpackhi_epi16(zeroi, tmpi); - -        //convert and scale -        __m128 tmplo = _mm_mul_ps(_mm_cvtepi32_ps(tmpilo), scalar); -        __m128 tmphi = _mm_mul_ps(_mm_cvtepi32_ps(tmpihi), scalar); - -        //store to output -        _mm_storeu_ps(reinterpret_cast<float *>(output+i+0), tmplo); -        _mm_storeu_ps(reinterpret_cast<float *>(output+i+2), tmphi); -    } - -    //convert remainder -    for (; i < nsamps; i++){ -        output[i] = item32_to_fc32(input[i]); -    } -} - -#elif defined(USE_ARM_NEON_H) -static UHD_INLINE void item32_to_fc32_nswap( -    const item32_t *input, fc32_t *output, size_t nsamps) -{ -    size_t i; - -    float32x4_t Q1 = vdupq_n_f32(floats_per_short); -    for (i=0; i < (nsamps & ~0x03); i+=2) { -        int16x4_t D0 = vld1_s16(reinterpret_cast<const int16_t *>(&input[i])); -        int16x4_t D1 = vrev32_s16(D0); -        int32x4_t Q2 = vmovl_s16(D1); -        float32x4_t Q3 = vcvtq_f32_s32(Q2); -        float32x4_t Q4 = vmulq_f32(Q3, Q1); -        vst1q_f32((reinterpret_cast<float *>(&output[i])), Q4); -    } - -    for (; i < nsamps; i++) -        output[i] = item32_to_fc32(input[i]); -} - -#else -static UHD_INLINE void item32_to_fc32_nswap( -    const item32_t *input, fc32_t *output, size_t nsamps -){ -    for (size_t i = 0; i < nsamps; i++){ -        output[i] = item32_to_fc32(input[i]); -    } -} -#endif - -//////////////////////////////////// -// byte-swap -//////////////////////////////////// -#if defined(USE_EMMINTRIN_H) -static UHD_INLINE void item32_to_fc32_bswap( -    const item32_t *input, fc32_t *output, size_t nsamps -){ -    __m128 scalar = _mm_set_ps1(floats_per_short/(1 << 16)); -    __m128i zeroi = _mm_setzero_si128(); - -    //convert blocks of samples with intrinsics -    size_t i = 0; for (; i < (nsamps & ~0x3); i+=4){ -        //load from input -        __m128i tmpi = _mm_loadu_si128(reinterpret_cast<const __m128i *>(input+i)); - -        //byteswap + unpack -> byteswap 16 bit words -        tmpi = _mm_or_si128(_mm_srli_epi16(tmpi, 8), _mm_slli_epi16(tmpi, 8)); -        __m128i tmpilo = _mm_unpacklo_epi16(zeroi, tmpi); //value in upper 16 bits -        __m128i tmpihi = _mm_unpackhi_epi16(zeroi, tmpi); - -        //convert and scale -        __m128 tmplo = _mm_mul_ps(_mm_cvtepi32_ps(tmpilo), scalar); -        __m128 tmphi = _mm_mul_ps(_mm_cvtepi32_ps(tmpihi), scalar); - -        //store to output -        _mm_storeu_ps(reinterpret_cast<float *>(output+i+0), tmplo); -        _mm_storeu_ps(reinterpret_cast<float *>(output+i+2), tmphi); -    } - -    //convert remainder -    for (; i < nsamps; i++){ -        output[i] = item32_to_fc32(uhd::byteswap(input[i])); -    } -} - -#else -static UHD_INLINE void item32_to_fc32_bswap( -    const item32_t *input, fc32_t *output, size_t nsamps -){ -    for (size_t i = 0; i < nsamps; i++){ -        output[i] = item32_to_fc32(uhd::byteswap(input[i])); -    } -} - -#endif - -#endif /* INCLUDED_LIBUHD_TRANSPORT_CONVERT_TYPES_IMPL_HPP */ diff --git a/host/lib/transport/gen_convert_types.py b/host/lib/transport/gen_convert_types.py deleted file mode 100755 index f9509c81d..000000000 --- a/host/lib/transport/gen_convert_types.py +++ /dev/null @@ -1,211 +0,0 @@ -#!/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/>. -# - -TMPL_TEXT = """ -#import time -/*********************************************************************** - * This file was generated by $file on $time.strftime("%c") - **********************************************************************/ - -\#include <uhd/config.hpp> -\#include <uhd/transport/convert_types.hpp> -\#include <boost/cstdint.hpp> -\#include <boost/detail/endian.hpp> -\#include <stdexcept> -\#include "convert_types_impl.hpp" - -using namespace uhd; - -/*********************************************************************** - * Generate predicate for jump table - **********************************************************************/ -UHD_INLINE boost::uint8_t get_pred( -    const io_type_t &io_type, -    const otw_type_t &otw_type, -    size_t num_chans -){ -    boost::uint8_t pred = 0; - -    switch(otw_type.byteorder){ -    \#ifdef BOOST_BIG_ENDIAN -    case otw_type_t::BO_BIG_ENDIAN:    pred |= $ph.nswap_p; break; -    case otw_type_t::BO_LITTLE_ENDIAN: pred |= $ph.bswap_p; break; -    \#else -    case otw_type_t::BO_BIG_ENDIAN:    pred |= $ph.bswap_p; break; -    case otw_type_t::BO_LITTLE_ENDIAN: pred |= $ph.nswap_p; break; -    \#endif -    case otw_type_t::BO_NATIVE:        pred |= $ph.nswap_p; break; -    default: throw std::runtime_error("unhandled otw byteorder type"); -    } - -    switch(otw_type.get_sample_size()){ -    case sizeof(boost::uint32_t): pred |= $ph.item32_p; break; -    default: throw std::runtime_error("unhandled otw sample size"); -    } - -    switch(io_type.tid){ -    case io_type_t::COMPLEX_FLOAT32: pred |= $ph.fc32_p; break; -    case io_type_t::COMPLEX_INT16:   pred |= $ph.sc16_p; break; -    default: throw std::runtime_error("unhandled io type id"); -    } - -    switch(num_chans){ -    case 1: pred |= $ph.chan1_p; break; -    case 2: pred |= $ph.chan2_p; break; -    case 3: pred |= $ph.chan3_p; break; -    case 4: pred |= $ph.chan4_p; break; -    default: throw std::runtime_error("unhandled number of channels"); -    } - -    return pred; -} - -/*********************************************************************** - * Convert host type to device type - **********************************************************************/ -void transport::convert_io_type_to_otw_type( -    const std::vector<const void *> &io_buffs, -    const io_type_t &io_type, -    void *otw_buff, -    const otw_type_t &otw_type, -    size_t nsamps_per_io_buff -){ -    switch(get_pred(io_type, otw_type, io_buffs.size())){ -    #for $pred in range(2**$ph.nbits) -    case $pred: -        #set $out_type = $ph.get_dev_type($pred) -        #set $in_type = $ph.get_host_type($pred) -        #set $num_chans = $ph.get_num_chans($pred) -        #set $converter = '_'.join([$in_type, 'to', $out_type]) -        #if $num_chans == 1 -        $(converter)_$ph.get_swap_type($pred)( -            reinterpret_cast<const $(in_type)_t *>(io_buffs.front()), -            reinterpret_cast<$(out_type)_t *>(otw_buff), -            nsamps_per_io_buff -        ); -        #else -        for (size_t i = 0, j = 0; i < nsamps_per_io_buff; i++){ -            #for $j in range($num_chans) -            reinterpret_cast<$(out_type)_t *>(otw_buff)[j++] = -                #if $ph.get_swap_type($pred) == 'bswap' -                uhd::byteswap($(converter)(reinterpret_cast<const $(in_type)_t *>(io_buffs[$j])[i])); -                #else -                $(converter)(reinterpret_cast<const $(in_type)_t *>(io_buffs[$j])[i]); -                #end if -            #end for -        } -        #end if -        break; -    #end for -    } -} - -/*********************************************************************** - * Convert device type to host type - **********************************************************************/ -void transport::convert_otw_type_to_io_type( -    const void *otw_buff, -    const otw_type_t &otw_type, -    std::vector<void *> &io_buffs, -    const io_type_t &io_type, -    size_t nsamps_per_io_buff -){ -    switch(get_pred(io_type, otw_type, io_buffs.size())){ -    #for $pred in range(2**$ph.nbits) -    case $pred: -        #set $out_type = $ph.get_host_type($pred) -        #set $in_type = $ph.get_dev_type($pred) -        #set $num_chans = $ph.get_num_chans($pred) -        #set $converter = '_'.join([$in_type, 'to', $out_type]) -        #if $num_chans == 1 -        $(converter)_$ph.get_swap_type($pred)( -            reinterpret_cast<const $(in_type)_t *>(otw_buff), -            reinterpret_cast<$(out_type)_t *>(io_buffs.front()), -            nsamps_per_io_buff -        ); -        #else -        for (size_t i = 0, j = 0; i < nsamps_per_io_buff; i++){ -            #for $j in range($num_chans) -            reinterpret_cast<$(out_type)_t *>(io_buffs[$j])[i] = -                #if $ph.get_swap_type($pred) == 'bswap' -                $(converter)(uhd::byteswap(reinterpret_cast<const $(in_type)_t *>(otw_buff)[j++])); -                #else -                $(converter)(reinterpret_cast<const $(in_type)_t *>(otw_buff)[j++]); -                #end if -            #end for -        } -        #end if -        break; -    #end for -    } -} - -""" - -def parse_tmpl(_tmpl_text, **kwargs): -    from Cheetah.Template import Template -    return str(Template(_tmpl_text, kwargs)) - -class ph: -    bswap_p  = 0b00001 -    nswap_p  = 0b00000 -    item32_p = 0b00000 -    sc16_p   = 0b00010 -    fc32_p   = 0b00000 -    chan1_p  = 0b00000 -    chan2_p  = 0b00100 -    chan3_p  = 0b01000 -    chan4_p  = 0b01100 - -    nbits = 4 #see above - -    @staticmethod -    def has(pred, mask, flag): return (pred & mask) == flag - -    @staticmethod -    def get_swap_type(pred): -        mask = 0b1 -        if ph.has(pred, mask, ph.bswap_p): return 'bswap' -        if ph.has(pred, mask, ph.nswap_p): return 'nswap' -        raise NotImplementedError - -    @staticmethod -    def get_dev_type(pred): -        mask = 0b0 -        if ph.has(pred, mask, ph.item32_p): return 'item32' -        raise NotImplementedError - -    @staticmethod -    def get_host_type(pred): -        mask = 0b10 -        if ph.has(pred, mask, ph.sc16_p): return 'sc16' -        if ph.has(pred, mask, ph.fc32_p): return 'fc32' -        raise NotImplementedError - -    @staticmethod -    def get_num_chans(pred): -        mask = 0b1100 -        if ph.has(pred, mask, ph.chan1_p): return 1 -        if ph.has(pred, mask, ph.chan2_p): return 2 -        if ph.has(pred, mask, ph.chan3_p): return 3 -        if ph.has(pred, mask, ph.chan4_p): return 4 -        raise NotImplementedError - -if __name__ == '__main__': -    import sys -    open(sys.argv[1], 'w').write(parse_tmpl(TMPL_TEXT, file=__file__, ph=ph)) diff --git a/host/lib/transport/libusb1_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp index f589d7c77..adc590284 100644 --- a/host/lib/transport/libusb1_zero_copy.cpp +++ b/host/lib/transport/libusb1_zero_copy.cpp @@ -1,5 +1,5 @@  // -// Copyright 2010 Ettus Research LLC +// Copyright 2010-2011 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 @@ -18,9 +18,9 @@  #include "libusb1_base.hpp"  #include <uhd/transport/usb_zero_copy.hpp>  #include <uhd/transport/bounded_buffer.hpp> +#include <uhd/transport/buffer_pool.hpp>  #include <uhd/utils/thread_priority.hpp>  #include <uhd/utils/assert.hpp> -#include <boost/shared_array.hpp>  #include <boost/foreach.hpp>  #include <boost/thread.hpp>  #include <boost/enable_shared_from_this.hpp> @@ -105,8 +105,8 @@ private:      //! a list of all transfer structs we allocated      std::vector<libusb_transfer *> _all_luts; -    //! a block of memory for the transfer buffers -    boost::shared_array<char> _buffer; +    //! memory allocated for the transfer buffers +    buffer_pool::sptr _buffer_pool;      // Calls for processing asynchronous I/O      libusb_transfer *allocate_transfer(void *mem, size_t len); @@ -134,7 +134,6 @@ static void callback(libusb_transfer *lut){   * \param pointer to libusb_transfer   */  void usb_endpoint::callback_handle_transfer(libusb_transfer *lut){ -    boost::this_thread::disable_interruption di; //disable because the wait can throw      _completed_list->push_with_wait(lut);  } @@ -157,9 +156,9 @@ usb_endpoint::usb_endpoint(      _input(input)  {      _completed_list = lut_buff_type::make(num_transfers); -    _buffer = boost::shared_array<char>(new char[num_transfers*transfer_size]); +    _buffer_pool = buffer_pool::make(num_transfers, transfer_size);      for (size_t i = 0; i < num_transfers; i++){ -        _all_luts.push_back(allocate_transfer(_buffer.get() + i*transfer_size, transfer_size)); +        _all_luts.push_back(allocate_transfer(_buffer_pool->at(i), transfer_size));          //input luts are immediately submitted to be filled          //output luts go into the completed list as free buffers @@ -272,7 +271,6 @@ void usb_endpoint::print_transfer_status(libusb_transfer *lut){  }  libusb_transfer *usb_endpoint::get_lut_with_wait(double timeout){ -    boost::this_thread::disable_interruption di; //disable because the wait can throw      libusb_transfer *lut;      if (_completed_list->pop_with_timed_wait(lut, timeout)) return lut;      return NULL; @@ -293,6 +291,7 @@ public:      ~libusb_zero_copy_impl(void){          _threads_running = false; +        _thread_group.interrupt_all();          _thread_group.join_all();      } @@ -333,12 +332,14 @@ private:          set_thread_priority_safe();          libusb::session::sptr session = libusb::session::get_global_session();          _threads_running = true; -        while(_threads_running){ -            timeval tv; -            tv.tv_sec = 0; -            tv.tv_usec = 100000; //100ms -            libusb_handle_events_timeout(session->get_context(), &tv); -        } +        try{ +            while(_threads_running){ +                timeval tv; +                tv.tv_sec = 0; +                tv.tv_usec = 100000; //100ms +                libusb_handle_events_timeout(session->get_context(), &tv); +            } +        } catch(const boost::thread_interrupted &){}      }  }; diff --git a/host/lib/transport/udp_zero_copy_asio.cpp b/host/lib/transport/udp_zero_copy_asio.cpp index c758fa894..5c049cfad 100644 --- a/host/lib/transport/udp_zero_copy_asio.cpp +++ b/host/lib/transport/udp_zero_copy_asio.cpp @@ -1,5 +1,5 @@  // -// Copyright 2010 Ettus Research LLC +// Copyright 2010-2011 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 @@ -18,10 +18,10 @@  #include <uhd/transport/udp_zero_copy.hpp>  #include <uhd/transport/udp_simple.hpp> //mtu  #include <uhd/transport/bounded_buffer.hpp> +#include <uhd/transport/buffer_pool.hpp>  #include <uhd/utils/thread_priority.hpp>  #include <uhd/utils/assert.hpp>  #include <uhd/utils/warning.hpp> -#include <boost/shared_array.hpp>  #include <boost/asio.hpp>  #include <boost/format.hpp>  #include <boost/thread.hpp> @@ -37,14 +37,15 @@ namespace asio = boost::asio;   **********************************************************************/  //Define this to the the boost async io calls to perform receive.  //Otherwise, get_recv_buff uses a blocking receive with timeout. -//#define USE_ASIO_ASYNC_RECV +#define USE_ASIO_ASYNC_RECV  //Define this to the the boost async io calls to perform send.  //Otherwise, the commit callback uses a blocking send.  //#define USE_ASIO_ASYNC_SEND -//enough buffering for half a second of samples at full rate on usrp2 -static const size_t MIN_RECV_SOCK_BUFF_SIZE = size_t(4 * 25e6 * 0.5); +//By default, this buffer is sized insufficiently small. +//For peformance, this buffer should be 10s of megabytes. +static const size_t MIN_RECV_SOCK_BUFF_SIZE = size_t(10e3);  //Large buffers cause more underflow at high rates.  //Perhaps this is due to the kernel scheduling, @@ -123,16 +124,16 @@ public:      void init(void){          //allocate all recv frames and release them to begin xfers          _pending_recv_buffs = pending_buffs_type::make(_num_recv_frames); -        _recv_buffer = boost::shared_array<char>(new char[_num_recv_frames*_recv_frame_size]); +        _recv_buffer_pool = buffer_pool::make(_num_recv_frames, _recv_frame_size);          for (size_t i = 0; i < _num_recv_frames; i++){ -            release(_recv_buffer.get() + i*_recv_frame_size); +            release(_recv_buffer_pool->at(i));          }          //allocate all send frames and push them into the fifo          _pending_send_buffs = pending_buffs_type::make(_num_send_frames); -        _send_buffer = boost::shared_array<char>(new char[_num_send_frames*_send_frame_size]); +        _send_buffer_pool = buffer_pool::make(_num_send_frames, _send_frame_size);          for (size_t i = 0; i < _num_send_frames; i++){ -            handle_send(_send_buffer.get() + i*_send_frame_size); +            handle_send(_send_buffer_pool->at(i));          }          //spawn the service threads that will run the io service @@ -302,7 +303,7 @@ public:  private:      //memory management -> buffers and fifos      boost::thread_group _thread_group; -    boost::shared_array<char> _send_buffer, _recv_buffer; +    buffer_pool::sptr _send_buffer_pool, _recv_buffer_pool;      typedef bounded_buffer<asio::mutable_buffer> pending_buffs_type;      pending_buffs_type::sptr _pending_recv_buffs, _pending_send_buffs;      const size_t _recv_frame_size, _num_recv_frames; @@ -321,12 +322,13 @@ private:   **********************************************************************/  template<typename Opt> static void resize_buff_helper(      udp_zero_copy_asio_impl::sptr udp_trans, -    size_t target_size, +    const size_t target_size,      const std::string &name  ){      size_t min_sock_buff_size = 0;      if (name == "recv") min_sock_buff_size = MIN_RECV_SOCK_BUFF_SIZE;      if (name == "send") min_sock_buff_size = MIN_SEND_SOCK_BUFF_SIZE; +    min_sock_buff_size = std::max(min_sock_buff_size, target_size);      std::string help_message;      #if defined(UHD_PLATFORM_LINUX) @@ -347,7 +349,7 @@ template<typename Opt> static void resize_buff_helper(          ) % name % actual_size << std::endl;          if (actual_size < target_size) uhd::warning::post(str(boost::format(              "The %s buffer is smaller than the requested size.\n" -            "The minimum recommended buffer size is %d bytes.\n" +            "The minimum requested buffer size is %d bytes.\n"              "See the transport application notes on buffer resizing.\n%s"          ) % name % min_sock_buff_size % help_message));      } diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp index 278bcfeaa..c535edd04 100644 --- a/host/lib/transport/vrt_packet_handler.hpp +++ b/host/lib/transport/vrt_packet_handler.hpp @@ -1,5 +1,5 @@  // -// Copyright 2010 Ettus Research LLC +// Copyright 2010-2011 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 @@ -26,7 +26,7 @@  #include <uhd/types/otw_type.hpp>  #include <uhd/types/metadata.hpp>  #include <uhd/transport/vrt_if_packet.hpp> -#include <uhd/transport/convert_types.hpp> +#include <uhd/convert.hpp>  #include <uhd/transport/zero_copy.hpp>  #include <boost/function.hpp>  #include <stdexcept> @@ -35,6 +35,9 @@  namespace vrt_packet_handler{ +//this may change in the future but its a constant for now +static const size_t OTW_BYTES_PER_SAMP = sizeof(boost::uint32_t); +  template <typename T> UHD_INLINE T get_context_code(      const boost::uint32_t *vrt_hdr,      const uhd::transport::vrt::if_packet_info_t &if_packet_info @@ -91,6 +94,7 @@ template <typename T> UHD_INLINE T get_context_code(          //vrt unpack each managed buffer          uhd::transport::vrt::if_packet_info_t if_packet_info;          for (size_t i = 0; i < state.width; i++){ +            if (state.managed_buffs[i].get() == NULL) continue; //better have a message packet coming up...              //extract packet words and check thats its enough to move on              size_t num_packet_words32 = state.managed_buffs[i]->size()/sizeof(boost::uint32_t); @@ -144,8 +148,7 @@ template <typename T> UHD_INLINE T get_context_code(          size_t offset_bytes,          size_t total_samps,          uhd::rx_metadata_t &metadata, -        const uhd::io_type_t &io_type, -        const uhd::otw_type_t &otw_type, +        uhd::convert::function_type &converter,          double tick_rate,          const vrt_unpacker_t &vrt_unpacker,          const get_recv_buffs_t &get_recv_buffs, @@ -183,7 +186,7 @@ template <typename T> UHD_INLINE T get_context_code(          }          //extract the number of samples available to copy -        size_t bytes_per_item = otw_type.get_sample_size(); +        size_t bytes_per_item = OTW_BYTES_PER_SAMP;          size_t nsamps_available = state.size_of_copy_buffs/bytes_per_item;          size_t nsamps_to_copy = std::min(total_samps*chans_per_otw_buff, nsamps_available);          size_t bytes_to_copy = nsamps_to_copy*bytes_per_item; @@ -198,9 +201,8 @@ template <typename T> UHD_INLINE T get_context_code(              }              //copy-convert the samples from the recv buffer -            uhd::transport::convert_otw_type_to_io_type( -                state.copy_buffs[i], otw_type, io_buffs, io_type, nsamps_to_copy_per_io_buff -            ); +            uhd::convert::input_type otw_buffs(1, state.copy_buffs[i]); +            converter(otw_buffs, io_buffs, nsamps_to_copy_per_io_buff);              //update the rx copy buffer to reflect the bytes copied              state.copy_buffs[i] += bytes_to_copy; @@ -234,6 +236,11 @@ template <typename T> UHD_INLINE T get_context_code(          size_t vrt_header_offset_words32 = 0,          size_t chans_per_otw_buff = 1      ){ +        uhd::convert::function_type converter( +            uhd::convert::get_converter_otw_to_cpu( +                io_type, otw_type, 1, chans_per_otw_buff +        )); +          switch(recv_mode){          //////////////////////////////////////////////////////////////// @@ -244,7 +251,7 @@ template <typename T> UHD_INLINE T get_context_code(                  buffs, 0,                  total_num_samps,                  metadata, -                io_type, otw_type, +                converter,                  tick_rate,                  vrt_unpacker,                  get_recv_buffs, @@ -265,7 +272,7 @@ template <typename T> UHD_INLINE T get_context_code(                      buffs, accum_num_samps*io_type.size,                      total_num_samps - accum_num_samps,                      (accum_num_samps == 0)? metadata : tmp_md, //only the first metadata gets kept -                    io_type, otw_type, +                    converter,                      tick_rate,                      vrt_unpacker,                      get_recv_buffs, @@ -309,15 +316,14 @@ template <typename T> UHD_INLINE T get_context_code(          const size_t offset_bytes,          const size_t num_samps,          uhd::transport::vrt::if_packet_info_t &if_packet_info, -        const uhd::io_type_t &io_type, -        const uhd::otw_type_t &otw_type, +        uhd::convert::function_type &converter,          const vrt_packer_t &vrt_packer,          const get_send_buffs_t &get_send_buffs,          const size_t vrt_header_offset_words32,          const size_t chans_per_otw_buff      ){          //load the rest of the if_packet_info in here -        if_packet_info.num_payload_words32 = (num_samps*chans_per_otw_buff*otw_type.get_sample_size())/sizeof(boost::uint32_t); +        if_packet_info.num_payload_words32 = (num_samps*chans_per_otw_buff*OTW_BYTES_PER_SAMP)/sizeof(boost::uint32_t);          if_packet_info.packet_count = state.next_packet_seq;          //get send buffers for each channel @@ -337,9 +343,8 @@ template <typename T> UHD_INLINE T get_context_code(              otw_mem += if_packet_info.num_header_words32;              //copy-convert the samples into the send buffer -            uhd::transport::convert_io_type_to_otw_type( -                io_buffs, io_type, otw_mem, otw_type, num_samps -            ); +            uhd::convert::output_type otw_buffs(1, otw_mem); +            converter(io_buffs, otw_buffs, num_samps);              //commit the samples to the zero-copy interface              size_t num_bytes_total = (vrt_header_offset_words32+if_packet_info.num_packet_words32)*sizeof(boost::uint32_t); @@ -367,6 +372,11 @@ template <typename T> UHD_INLINE T get_context_code(          size_t vrt_header_offset_words32 = 0,          size_t chans_per_otw_buff = 1      ){ +        uhd::convert::function_type converter( +            uhd::convert::get_converter_cpu_to_otw( +                io_type, otw_type, chans_per_otw_buff, 1 +        )); +          //translate the metadata to vrt if packet info          uhd::transport::vrt::if_packet_info_t if_packet_info;          if_packet_info.has_sid = false; @@ -402,7 +412,7 @@ template <typename T> UHD_INLINE T get_context_code(                  buffs_, 0,                  std::min(total_num_samps_, max_samples_per_packet),                  if_packet_info, -                io_type, otw_type, +                converter,                  vrt_packer,                  get_send_buffs,                  vrt_header_offset_words32, @@ -435,7 +445,7 @@ template <typename T> UHD_INLINE T get_context_code(                      buffs, total_num_samps_sent*io_type.size,                      std::min(total_num_samps_unsent, max_samples_per_packet),                      if_packet_info, -                    io_type, otw_type, +                    converter,                      vrt_packer,                      get_send_buffs,                      vrt_header_offset_words32, diff --git a/host/lib/types.cpp b/host/lib/types.cpp deleted file mode 100644 index bea20a4aa..000000000 --- a/host/lib/types.cpp +++ /dev/null @@ -1,350 +0,0 @@ -// -// Copyright 2010 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program.  If not, see <http://www.gnu.org/licenses/>. -// - -#include <uhd/utils/assert.hpp> -#include <uhd/types/tune_request.hpp> -#include <uhd/types/tune_result.hpp> -#include <uhd/types/clock_config.hpp> -#include <uhd/types/stream_cmd.hpp> -#include <uhd/types/metadata.hpp> -#include <uhd/types/ranges.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 <uhd/types/serial.hpp> -#include <boost/math/special_functions/round.hpp> -#include <boost/foreach.hpp> -#include <boost/format.hpp> -#include <boost/cstdint.hpp> -#include <boost/assign/list_of.hpp> -#include <boost/thread.hpp> -#include <stdexcept> -#include <complex> -#include <sstream> - -using namespace uhd; - -/*********************************************************************** - * ranges template instantiation - **********************************************************************/ -template struct uhd::meta_range_t<float>; -template struct uhd::meta_range_t<double>; - -/*********************************************************************** - * tune request - **********************************************************************/ -tune_request_t::tune_request_t(double target_freq): -    target_freq(target_freq), -    inter_freq_policy(POLICY_AUTO), -    dsp_freq_policy(POLICY_AUTO) -{ -    /* NOP */ -} - -tune_request_t::tune_request_t(double target_freq, double lo_off): -    target_freq(target_freq), -    inter_freq_policy(POLICY_MANUAL), -    inter_freq(target_freq + lo_off), -    dsp_freq_policy(POLICY_AUTO) -{ -    /* NOP */ -} - -/*********************************************************************** - * tune result - **********************************************************************/ -std::string tune_result_t::to_pp_string(void) const{ -    return str(boost::format( -        "Tune Result:\n" -        "    Target Intermediate Freq: %f (MHz)\n" -        "    Actual Intermediate Freq: %f (MHz)\n" -        "    Target DSP Freq Shift:    %f (MHz)\n" -        "    Actual DSP Freq Shift:    %f (MHz)\n" -    ) -        % (target_inter_freq/1e6) % (actual_inter_freq/1e6) -        % (target_dsp_freq/1e6)   % (actual_dsp_freq/1e6) -    ); -} - -/*********************************************************************** - * clock config - **********************************************************************/ -clock_config_t::clock_config_t(void): -    ref_source(REF_INT), -    pps_source(PPS_INT), -    pps_polarity(PPS_NEG) -{ -    /* NOP */ -} - -/*********************************************************************** - * stream command - **********************************************************************/ -stream_cmd_t::stream_cmd_t(const stream_mode_t &stream_mode): -    stream_mode(stream_mode), -    num_samps(0), -    stream_now(true) -{ -    /* NOP */ -} - -/*********************************************************************** - * metadata - **********************************************************************/ -tx_metadata_t::tx_metadata_t(void): -    has_time_spec(false), -    time_spec(time_spec_t()), -    start_of_burst(false), -    end_of_burst(false) -{ -    /* NOP */ -} - -/*********************************************************************** - * time spec - **********************************************************************/ -time_spec_t::time_spec_t(double secs): -    _full_secs(0), -    _frac_secs(secs) -{ -    /* NOP */ -} - -time_spec_t::time_spec_t(time_t full_secs, double frac_secs): -    _full_secs(full_secs), -    _frac_secs(frac_secs) -{ -    /* NOP */ -} - -time_spec_t::time_spec_t(time_t full_secs, long tick_count, double tick_rate): -    _full_secs(full_secs), -    _frac_secs(double(tick_count)/tick_rate) -{ -    /* NOP */ -} - -long time_spec_t::get_tick_count(double tick_rate) const{ -    return boost::math::iround(this->get_frac_secs()*tick_rate); -} - -double time_spec_t::get_real_secs(void) const{ -    return this->_full_secs + this->_frac_secs; -} - -time_t time_spec_t::get_full_secs(void) const{ -    double intpart; -    std::modf(this->_frac_secs, &intpart); -    return this->_full_secs + time_t(intpart); -} - -double time_spec_t::get_frac_secs(void) const{ -    return std::fmod(this->_frac_secs, 1.0); -} - -time_spec_t &time_spec_t::operator+=(const time_spec_t &rhs){ -    this->_full_secs += rhs.get_full_secs(); -    this->_frac_secs += rhs.get_frac_secs(); -    return *this; -} - -time_spec_t &time_spec_t::operator-=(const time_spec_t &rhs){ -    this->_full_secs -= rhs.get_full_secs(); -    this->_frac_secs -= rhs.get_frac_secs(); -    return *this; -} - -bool uhd::operator==(const time_spec_t &lhs, const time_spec_t &rhs){ -    return -        lhs.get_full_secs() == rhs.get_full_secs() and -        lhs.get_frac_secs() == rhs.get_frac_secs() -    ; -} - -bool uhd::operator<(const time_spec_t &lhs, const time_spec_t &rhs){ -    return ( -        (lhs.get_full_secs() < rhs.get_full_secs()) or ( -        (lhs.get_full_secs() == rhs.get_full_secs()) and -        (lhs.get_frac_secs() < rhs.get_frac_secs()) -    )); -} - -/*********************************************************************** - * device addr - **********************************************************************/ -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); -} - -device_addr_t::device_addr_t(const std::string &args){ -    BOOST_FOREACH(const std::string &pair, std::split_string(args, arg_delim)){ -        if (trim(pair) == "") continue; - -        std::vector<std::string> key_val = std::split_string(pair, pair_delim); -        if (key_val.size() != 2) throw std::runtime_error("invalid args string: "+args); -        (*this)[trim(key_val.front())] = trim(key_val.back()); -    } -} - -std::string device_addr_t::to_pp_string(void) const{ -    if (this->size() == 0) return "Empty Device Address"; - -    std::stringstream ss; -    ss << "Device Address:" << std::endl; -    BOOST_FOREACH(std::string key, this->keys()){ -        ss << boost::format("    %s: %s") % key % (*this)[key] << std::endl; -    } -    return ss.str(); -} - -std::string device_addr_t::to_string(void) const{ -    std::string args_str; -    size_t count = 0; -    BOOST_FOREACH(const std::string &key, this->keys()){ -        args_str += ((count++)? arg_delim : "") + key + pair_delim + (*this)[key]; -    } -    return args_str; -} - -/*********************************************************************** - * mac addr - **********************************************************************/ -mac_addr_t::mac_addr_t(const byte_vector_t &bytes) : _bytes(bytes){ -    UHD_ASSERT_THROW(_bytes.size() == 6); -} - -mac_addr_t mac_addr_t::from_bytes(const byte_vector_t &bytes){ -    return mac_addr_t(bytes); -} - -mac_addr_t mac_addr_t::from_string(const std::string &mac_addr_str){ - -    byte_vector_t bytes; - -    try{ -        if (mac_addr_str.size() != 17){ -            throw std::runtime_error("expected exactly 17 characters"); -        } - -        //split the mac addr hex string at the colons -        BOOST_FOREACH(const std::string &hex_str, std::split_string(mac_addr_str, ":")){ -            int hex_num; -            std::istringstream iss(hex_str); -            iss >> std::hex >> hex_num; -            bytes.push_back(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 mac_addr_t::from_bytes(bytes); -} - -byte_vector_t mac_addr_t::to_bytes(void) const{ -    return _bytes; -} - -std::string mac_addr_t::to_string(void) const{ -    std::string addr = ""; -    BOOST_FOREACH(boost::uint8_t byte, this->to_bytes()){ -        addr += str(boost::format("%s%02x") % ((addr == "")?"":":") % int(byte)); -    } -    return addr; -} - -/*********************************************************************** - * otw type - **********************************************************************/ -size_t otw_type_t::get_sample_size(void) const{ -    return (this->width * 2) / 8; -} - -otw_type_t::otw_type_t(void): -    width(0), -    shift(0), -    byteorder(BO_NATIVE) -{ -    /* NOP */ -} - -/*********************************************************************** - * 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 */ -} - -/*********************************************************************** - * serial - **********************************************************************/ -spi_config_t::spi_config_t(edge_t edge): -    mosi_edge(edge), -    miso_edge(edge) -{ -    /* NOP */ -} - -void i2c_iface::write_eeprom( -    boost::uint8_t addr, -    boost::uint8_t offset, -    const byte_vector_t &bytes -){ -    for (size_t i = 0; i < bytes.size(); i++){ -        //write a byte at a time, its easy that way -        byte_vector_t cmd = boost::assign::list_of(offset+i)(bytes[i]); -        this->write_i2c(addr, cmd); -        boost::this_thread::sleep(boost::posix_time::milliseconds(10)); //worst case write -    } -} - -byte_vector_t i2c_iface::read_eeprom( -    boost::uint8_t addr, -    boost::uint8_t offset, -    size_t num_bytes -){ -    byte_vector_t bytes; -    for (size_t i = 0; i < num_bytes; i++){ -        //do a zero byte write to start read cycle -        this->write_i2c(addr, byte_vector_t(1, offset+i)); -        bytes.push_back(this->read_i2c(addr, 1).at(0)); -    } -    return bytes; -} diff --git a/host/lib/types/CMakeLists.txt b/host/lib/types/CMakeLists.txt new file mode 100644 index 000000000..dfb7cf903 --- /dev/null +++ b/host/lib/types/CMakeLists.txt @@ -0,0 +1,31 @@ +# +# Copyright 2011 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 included, use CMake directory variables +######################################################################## +LIBUHD_APPEND_SOURCES( +    ${CMAKE_CURRENT_SOURCE_DIR}/clock_config.cpp +    ${CMAKE_CURRENT_SOURCE_DIR}/device_addr.cpp +    ${CMAKE_CURRENT_SOURCE_DIR}/mac_addr.cpp +    ${CMAKE_CURRENT_SOURCE_DIR}/ranges.cpp +    ${CMAKE_CURRENT_SOURCE_DIR}/sensors.cpp +    ${CMAKE_CURRENT_SOURCE_DIR}/serial.cpp +    ${CMAKE_CURRENT_SOURCE_DIR}/time_spec.cpp +    ${CMAKE_CURRENT_SOURCE_DIR}/tune.cpp +    ${CMAKE_CURRENT_SOURCE_DIR}/types.cpp +) diff --git a/host/lib/types/clock_config.cpp b/host/lib/types/clock_config.cpp new file mode 100644 index 000000000..c150c5cc3 --- /dev/null +++ b/host/lib/types/clock_config.cpp @@ -0,0 +1,44 @@ +// +// Copyright 2011 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/types/clock_config.hpp> + +using namespace uhd; + +clock_config_t clock_config_t::external(void){ +    clock_config_t clock_config; +    clock_config.ref_source = clock_config_t::REF_SMA; +    clock_config.pps_source = clock_config_t::PPS_SMA; +    clock_config.pps_polarity = clock_config_t::PPS_POS; +    return clock_config; +} + +clock_config_t clock_config_t::internal(void){ +    clock_config_t clock_config; +    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_POS; +    return clock_config; +} + +clock_config_t::clock_config_t(void): +    ref_source(REF_INT), +    pps_source(PPS_SMA), +    pps_polarity(PPS_POS) +{ +    /* NOP */ +} diff --git a/host/lib/types/device_addr.cpp b/host/lib/types/device_addr.cpp new file mode 100644 index 000000000..14afaa24b --- /dev/null +++ b/host/lib/types/device_addr.cpp @@ -0,0 +1,73 @@ +// +// Copyright 2011 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/types/device_addr.hpp> +#include <boost/algorithm/string.hpp> //for trim +#include <boost/tokenizer.hpp> +#include <boost/foreach.hpp> +#include <boost/format.hpp> +#include <stdexcept> +#include <sstream> + +using namespace uhd; + +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); +} + +#define tokenizer(inp, sep) \ +    boost::tokenizer<boost::char_separator<char> > \ +    (inp, boost::char_separator<char>(sep.c_str())) + +device_addr_t::device_addr_t(const std::string &args){ +    BOOST_FOREACH(const std::string &pair, tokenizer(args, arg_delim)){ +        if (trim(pair) == "") continue; +        std::string key; +        BOOST_FOREACH(const std::string &tok, tokenizer(pair, pair_delim)){ +            if (key.empty()) key = tok; +            else{ +                this->set(trim(key), trim(tok)); +                goto continue_next_arg; +            } +        } +        throw std::runtime_error("invalid args string: "+args); +        continue_next_arg: continue; +    } +} + +std::string device_addr_t::to_pp_string(void) const{ +    if (this->size() == 0) return "Empty Device Address"; + +    std::stringstream ss; +    ss << "Device Address:" << std::endl; +    BOOST_FOREACH(std::string key, this->keys()){ +        ss << boost::format("    %s: %s") % key % this->get(key) << std::endl; +    } +    return ss.str(); +} + +std::string device_addr_t::to_string(void) const{ +    std::string args_str; +    size_t count = 0; +    BOOST_FOREACH(const std::string &key, this->keys()){ +        args_str += ((count++)? arg_delim : "") + key + pair_delim + this->get(key); +    } +    return args_str; +} diff --git a/host/lib/types/mac_addr.cpp b/host/lib/types/mac_addr.cpp new file mode 100644 index 000000000..cf3c3fa97 --- /dev/null +++ b/host/lib/types/mac_addr.cpp @@ -0,0 +1,76 @@ +// +// Copyright 2011 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/types/mac_addr.hpp> +#include <uhd/utils/assert.hpp> +#include <boost/tokenizer.hpp> +#include <boost/foreach.hpp> +#include <boost/format.hpp> +#include <boost/cstdint.hpp> +#include <stdexcept> +#include <sstream> + +using namespace uhd; + +mac_addr_t::mac_addr_t(const byte_vector_t &bytes) : _bytes(bytes){ +    UHD_ASSERT_THROW(_bytes.size() == 6); +} + +mac_addr_t mac_addr_t::from_bytes(const byte_vector_t &bytes){ +    return mac_addr_t(bytes); +} + +mac_addr_t mac_addr_t::from_string(const std::string &mac_addr_str){ + +    byte_vector_t bytes; + +    try{ +        if (mac_addr_str.size() != 17){ +            throw std::runtime_error("expected exactly 17 characters"); +        } + +        //split the mac addr hex string at the colons +        boost::tokenizer<boost::char_separator<char> > hex_num_toks( +            mac_addr_str, boost::char_separator<char>(":")); +        BOOST_FOREACH(const std::string &hex_str, hex_num_toks){ +            int hex_num; +            std::istringstream iss(hex_str); +            iss >> std::hex >> hex_num; +            bytes.push_back(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 mac_addr_t::from_bytes(bytes); +} + +byte_vector_t mac_addr_t::to_bytes(void) const{ +    return _bytes; +} + +std::string mac_addr_t::to_string(void) const{ +    std::string addr = ""; +    BOOST_FOREACH(boost::uint8_t byte, this->to_bytes()){ +        addr += str(boost::format("%s%02x") % ((addr == "")?"":":") % int(byte)); +    } +    return addr; +} diff --git a/host/lib/types/ranges.cpp b/host/lib/types/ranges.cpp new file mode 100644 index 000000000..4a0d05d80 --- /dev/null +++ b/host/lib/types/ranges.cpp @@ -0,0 +1,163 @@ +// +// Copyright 2011-2011 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/types/ranges.hpp> +#include <boost/math/special_functions/round.hpp> +#include <boost/foreach.hpp> +#include <algorithm> +#include <stdexcept> +#include <sstream> + +using namespace uhd; + +/*********************************************************************** + * range_t implementation code + **********************************************************************/ +struct range_t::impl{ +    impl(double start, double stop, double step): +        start(start), stop(stop), step(step) +    { +        /* NOP */ +    } +    double start, stop, step; +}; + +range_t::range_t(double value): +    _impl(UHD_PIMPL_MAKE(impl, (value, value, 0))) +{ +    /* NOP */ +} + +range_t::range_t( +    double start, double stop, double step +): +    _impl(UHD_PIMPL_MAKE(impl, (start, stop, step))) +{ +    if (stop < start){ +        throw std::invalid_argument("cannot make range where stop < start"); +    } +} + +double range_t::start(void) const{ +    return _impl->start; +} + +double range_t::stop(void) const{ +    return _impl->stop; +} + +double range_t::step(void) const{ +    return _impl->step; +} + +const std::string range_t::to_pp_string(void) const{ +    std::stringstream ss; +    ss << "(" << this->start(); +    if (this->start() != this->stop()) ss << ", " << this->stop(); +    if (this->step() != 0) ss << ", " << this->step(); +    ss << ")"; +    return ss.str(); +} + +/*********************************************************************** + * meta_range_t implementation code + **********************************************************************/ +void check_meta_range_monotonic(const meta_range_t &mr){ +    if (mr.empty()){ +        throw std::runtime_error("meta-range cannot be empty"); +    } +    for (size_t i = 1; i < mr.size(); i++){ +        if (mr.at(i).start() < mr.at(i-1).stop()){ +            throw std::runtime_error("meta-range is not monotonic"); +        } +    } +} + +meta_range_t::meta_range_t(void){ +    /* NOP */ +} + +meta_range_t::meta_range_t( +    double start, double stop, double step +): +    std::vector<range_t > (1, range_t(start, stop, step)) +{ +    /* NOP */ +} + +double meta_range_t::start(void) const{ +    check_meta_range_monotonic(*this); +    double min_start = this->front().start(); +    BOOST_FOREACH(const range_t &r, (*this)){ +        min_start = std::min(min_start, r.start()); +    } +    return min_start; +} + +double meta_range_t::stop(void) const{ +    check_meta_range_monotonic(*this); +    double max_stop = this->front().stop(); +    BOOST_FOREACH(const range_t &r, (*this)){ +        max_stop = std::max(max_stop, r.stop()); +    } +    return max_stop; +} + +double meta_range_t::step(void) const{ +    check_meta_range_monotonic(*this); +    std::vector<double> non_zero_steps; +    range_t last = this->front(); +    BOOST_FOREACH(const range_t &r, (*this)){ +        //steps at each range +        if (r.step() > 0) non_zero_steps.push_back(r.step()); +        //and steps in-between ranges +        double ibtw_step = r.start() - last.stop(); +        if (ibtw_step > 0) non_zero_steps.push_back(ibtw_step); +        //store ref to last +        last = r; +    } +    if (non_zero_steps.empty()) return 0; //all zero steps, its zero... +    return *std::min_element(non_zero_steps.begin(), non_zero_steps.end()); +} + +double meta_range_t::clip(double value, bool clip_step) const{ +    check_meta_range_monotonic(*this); +    double last_stop = this->front().stop(); +    BOOST_FOREACH(const range_t &r, (*this)){ +        //in-between ranges, clip to nearest +        if (value < r.start()){ +            return (std::abs(value - r.start()) < std::abs(value - last_stop))? +                r.start() : last_stop; +        } +        //in this range, clip here +        if (value <= r.stop()){ +            if (not clip_step or r.step() == 0) return value; +            return boost::math::round((value - r.start())/r.step())*r.step() + r.start(); +        } +        //continue on to the next range +        last_stop = r.stop(); +    } +    return last_stop; +} + +const std::string meta_range_t::to_pp_string(void) const{ +    std::stringstream ss; +    BOOST_FOREACH(const range_t &r, (*this)){ +        ss << r.to_pp_string() << std::endl; +    } +    return ss.str(); +} diff --git a/host/lib/types/sensors.cpp b/host/lib/types/sensors.cpp new file mode 100644 index 000000000..2bff136a4 --- /dev/null +++ b/host/lib/types/sensors.cpp @@ -0,0 +1,81 @@ +// +// Copyright 2011-2011 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/types/sensors.hpp> +#include <uhd/utils/exception.hpp> +#include <boost/format.hpp> + +using namespace uhd; + +sensor_value_t::sensor_value_t( +    const std::string &name, +    bool value, +    const std::string &ufalse, +    const std::string &utrue +): +    name(name), value(value?"true":"false"), +    unit(value?utrue:ufalse), type(BOOLEAN) +{ +    /* NOP */ +} + +sensor_value_t::sensor_value_t( +    const std::string &name, +    int_type value, +    const std::string &unit, +    const std::string &formatter +): +    name(name), value(str(boost::format(formatter) % value)), +    unit(unit), type(INTEGER) +{ +    /* NOP */ +} + +sensor_value_t::sensor_value_t( +    const std::string &name, +    real_type value, +    const std::string &unit, +    const std::string &formatter +): +    name(name), value(str(boost::format(formatter) % value)), +    unit(unit), type(REALNUM) +{ +    /* NOP */ +} + +sensor_value_t::sensor_value_t( +    const std::string &name, +    const std::string &value, +    const std::string &unit +): +    name(name), value(value), +    unit(unit), type(STRING) +{ +    /* NOP */ +} + +std::string sensor_value_t::to_pp_string(void) const{ +    switch(type){ +    case BOOLEAN: +        return str(boost::format("%s: %s") % name % unit); +    case INTEGER: +    case REALNUM: +    case STRING: +        return str(boost::format("%s: %s %s") % name % value % unit); +    } +    UHD_THROW_INVALID_CODE_PATH(); +} diff --git a/host/lib/types/serial.cpp b/host/lib/types/serial.cpp new file mode 100644 index 000000000..9acf7156a --- /dev/null +++ b/host/lib/types/serial.cpp @@ -0,0 +1,56 @@ +// +// Copyright 2011 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/types/serial.hpp> +#include <boost/thread.hpp> //for sleeping +#include <boost/assign/list_of.hpp> + +using namespace uhd; + +spi_config_t::spi_config_t(edge_t edge): +    mosi_edge(edge), +    miso_edge(edge) +{ +    /* NOP */ +} + +void i2c_iface::write_eeprom( +    boost::uint8_t addr, +    boost::uint8_t offset, +    const byte_vector_t &bytes +){ +    for (size_t i = 0; i < bytes.size(); i++){ +        //write a byte at a time, its easy that way +        byte_vector_t cmd = boost::assign::list_of(offset+i)(bytes[i]); +        this->write_i2c(addr, cmd); +        boost::this_thread::sleep(boost::posix_time::milliseconds(10)); //worst case write +    } +} + +byte_vector_t i2c_iface::read_eeprom( +    boost::uint8_t addr, +    boost::uint8_t offset, +    size_t num_bytes +){ +    byte_vector_t bytes; +    for (size_t i = 0; i < num_bytes; i++){ +        //do a zero byte write to start read cycle +        this->write_i2c(addr, byte_vector_t(1, offset+i)); +        bytes.push_back(this->read_i2c(addr, 1).at(0)); +    } +    return bytes; +} diff --git a/host/lib/types/time_spec.cpp b/host/lib/types/time_spec.cpp new file mode 100644 index 000000000..f39625a11 --- /dev/null +++ b/host/lib/types/time_spec.cpp @@ -0,0 +1,86 @@ +// +// Copyright 2011 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/types/time_spec.hpp> +#include <boost/math/special_functions/round.hpp> + +using namespace uhd; +time_spec_t::time_spec_t(double secs): +    _full_secs(0), +    _frac_secs(secs) +{ +    /* NOP */ +} + +time_spec_t::time_spec_t(time_t full_secs, double frac_secs): +    _full_secs(full_secs), +    _frac_secs(frac_secs) +{ +    /* NOP */ +} + +time_spec_t::time_spec_t(time_t full_secs, long tick_count, double tick_rate): +    _full_secs(full_secs), +    _frac_secs(double(tick_count)/tick_rate) +{ +    /* NOP */ +} + +long time_spec_t::get_tick_count(double tick_rate) const{ +    return boost::math::iround(this->get_frac_secs()*tick_rate); +} + +double time_spec_t::get_real_secs(void) const{ +    return this->_full_secs + this->_frac_secs; +} + +time_t time_spec_t::get_full_secs(void) const{ +    double intpart; +    std::modf(this->_frac_secs, &intpart); +    return this->_full_secs + time_t(intpart); +} + +double time_spec_t::get_frac_secs(void) const{ +    return std::fmod(this->_frac_secs, 1.0); +} + +time_spec_t &time_spec_t::operator+=(const time_spec_t &rhs){ +    this->_full_secs += rhs.get_full_secs(); +    this->_frac_secs += rhs.get_frac_secs(); +    return *this; +} + +time_spec_t &time_spec_t::operator-=(const time_spec_t &rhs){ +    this->_full_secs -= rhs.get_full_secs(); +    this->_frac_secs -= rhs.get_frac_secs(); +    return *this; +} + +bool uhd::operator==(const time_spec_t &lhs, const time_spec_t &rhs){ +    return +        lhs.get_full_secs() == rhs.get_full_secs() and +        lhs.get_frac_secs() == rhs.get_frac_secs() +    ; +} + +bool uhd::operator<(const time_spec_t &lhs, const time_spec_t &rhs){ +    return ( +        (lhs.get_full_secs() < rhs.get_full_secs()) or ( +        (lhs.get_full_secs() == rhs.get_full_secs()) and +        (lhs.get_frac_secs() < rhs.get_frac_secs()) +    )); +} diff --git a/host/lib/types/tune.cpp b/host/lib/types/tune.cpp new file mode 100644 index 000000000..601bc20e8 --- /dev/null +++ b/host/lib/types/tune.cpp @@ -0,0 +1,52 @@ +// +// Copyright 2011 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/types/tune_request.hpp> +#include <uhd/types/tune_result.hpp> +#include <boost/format.hpp> + +using namespace uhd; + +tune_request_t::tune_request_t(double target_freq): +    target_freq(target_freq), +    inter_freq_policy(POLICY_AUTO), +    dsp_freq_policy(POLICY_AUTO) +{ +    /* NOP */ +} + +tune_request_t::tune_request_t(double target_freq, double lo_off): +    target_freq(target_freq), +    inter_freq_policy(POLICY_MANUAL), +    inter_freq(target_freq + lo_off), +    dsp_freq_policy(POLICY_AUTO) +{ +    /* NOP */ +} + +std::string tune_result_t::to_pp_string(void) const{ +    return str(boost::format( +        "Tune Result:\n" +        "    Target Intermediate Freq: %f (MHz)\n" +        "    Actual Intermediate Freq: %f (MHz)\n" +        "    Target DSP Freq Shift:    %f (MHz)\n" +        "    Actual DSP Freq Shift:    %f (MHz)\n" +    ) +        % (target_inter_freq/1e6) % (actual_inter_freq/1e6) +        % (target_dsp_freq/1e6)   % (actual_dsp_freq/1e6) +    ); +} diff --git a/host/lib/types/types.cpp b/host/lib/types/types.cpp new file mode 100644 index 000000000..34d5947eb --- /dev/null +++ b/host/lib/types/types.cpp @@ -0,0 +1,86 @@ +// +// Copyright 2011 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/types/stream_cmd.hpp> +#include <uhd/types/metadata.hpp> +#include <uhd/types/otw_type.hpp> +#include <uhd/types/io_type.hpp> +#include <boost/cstdint.hpp> +#include <stdexcept> +#include <complex> + +using namespace uhd; + +/*********************************************************************** + * stream command + **********************************************************************/ +stream_cmd_t::stream_cmd_t(const stream_mode_t &stream_mode): +    stream_mode(stream_mode), +    num_samps(0), +    stream_now(true) +{ +    /* NOP */ +} + +/*********************************************************************** + * metadata + **********************************************************************/ +tx_metadata_t::tx_metadata_t(void): +    has_time_spec(false), +    time_spec(time_spec_t()), +    start_of_burst(false), +    end_of_burst(false) +{ +    /* NOP */ +} + +/*********************************************************************** + * otw type + **********************************************************************/ +size_t otw_type_t::get_sample_size(void) const{ +    return (this->width * 2) / 8; +} + +otw_type_t::otw_type_t(void): +    width(0), +    shift(0), +    byteorder(BO_NATIVE) +{ +    /* NOP */ +} + +/*********************************************************************** + * 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/CMakeLists.txt b/host/lib/usrp/CMakeLists.txt index 9dc74a5fe..bd25aec2b 100644 --- a/host/lib/usrp/CMakeLists.txt +++ b/host/lib/usrp/CMakeLists.txt @@ -25,6 +25,7 @@ LIBUHD_APPEND_SOURCES(      ${CMAKE_CURRENT_SOURCE_DIR}/dboard_iface.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/dboard_manager.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/dsp_utils.cpp +    ${CMAKE_CURRENT_SOURCE_DIR}/gps_ctrl.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/mboard_eeprom.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/misc_utils.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/multi_usrp.cpp diff --git a/host/lib/usrp/dboard/db_basic_and_lf.cpp b/host/lib/usrp/dboard/db_basic_and_lf.cpp index f771595b6..b311576d2 100644 --- a/host/lib/usrp/dboard/db_basic_and_lf.cpp +++ b/host/lib/usrp/dboard/db_basic_and_lf.cpp @@ -1,5 +1,5 @@  // -// Copyright 2010 Ettus Research LLC +// Copyright 2010-2011 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 @@ -134,7 +134,7 @@ void basic_rx::rx_get(const wax::obj &key_, wax::obj &val){          return;      case SUBDEV_PROP_GAIN: -        val = float(0); +        val = double(0);          return;      case SUBDEV_PROP_GAIN_RANGE: @@ -192,7 +192,7 @@ void basic_rx::rx_set(const wax::obj &key_, const wax::obj &val){      switch(key.as<subdev_prop_t>()){      case SUBDEV_PROP_GAIN: -        UHD_ASSERT_THROW(val.as<float>() == float(0)); +        UHD_ASSERT_THROW(val.as<double>() == double(0));          return;      case SUBDEV_PROP_ANTENNA: @@ -245,7 +245,7 @@ void basic_tx::tx_get(const wax::obj &key_, wax::obj &val){          return;      case SUBDEV_PROP_GAIN: -        val = float(0); +        val = double(0);          return;      case SUBDEV_PROP_GAIN_RANGE: @@ -303,7 +303,7 @@ void basic_tx::tx_set(const wax::obj &key_, const wax::obj &val){      switch(key.as<subdev_prop_t>()){      case SUBDEV_PROP_GAIN: -        UHD_ASSERT_THROW(val.as<float>() == float(0)); +        UHD_ASSERT_THROW(val.as<double>() == double(0));          return;      case SUBDEV_PROP_ANTENNA: diff --git a/host/lib/usrp/dboard/db_dbsrx.cpp b/host/lib/usrp/dboard/db_dbsrx.cpp index 7250136f5..3ea9cea80 100644 --- a/host/lib/usrp/dboard/db_dbsrx.cpp +++ b/host/lib/usrp/dboard/db_dbsrx.cpp @@ -1,5 +1,5 @@  // -// Copyright 2010 Ettus Research LLC +// Copyright 2010-2011 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 @@ -70,7 +70,7 @@ public:  private:      double _lo_freq;      double _bandwidth; -    uhd::dict<std::string, float> _gains; +    uhd::dict<std::string, double> _gains;      max2118_write_regs_t _max2118_write_regs;      max2118_read_regs_t _max2118_read_regs;      boost::uint8_t _max2118_addr(void){ @@ -78,7 +78,7 @@ private:      };      void set_lo_freq(double target_freq); -    void set_gain(float gain, const std::string &name); +    void set_gain(double gain, const std::string &name);      void set_bandwidth(double bandwidth);      void send_reg(boost::uint8_t start_reg, boost::uint8_t stop_reg){ @@ -418,17 +418,17 @@ void dbsrx::set_lo_freq(double target_freq){   * \param gain the requested gain in dB   * \return 5 bit the register value   */ -static int gain_to_gc2_vga_reg(float &gain){ +static int gain_to_gc2_vga_reg(double &gain){      int reg = 0;      gain = dbsrx_gain_ranges["GC2"].clip(gain);      // Half dB steps from 0-5dB, 1dB steps from 5-24dB      if (gain < 5) {          reg = boost::math::iround(31.0 - gain/0.5); -        gain = float(boost::math::iround(gain) * 0.5); +        gain = double(boost::math::iround(gain) * 0.5);      } else {          reg = boost::math::iround(22.0 - (gain - 4.0)); -        gain = float(boost::math::iround(gain)); +        gain = double(boost::math::iround(gain));      }      if (dbsrx_debug) std::cerr << boost::format( @@ -444,16 +444,16 @@ static int gain_to_gc2_vga_reg(float &gain){   * \param gain the requested gain in dB   * \return dac voltage value   */ -static float gain_to_gc1_rfvga_dac(float &gain){ +static double gain_to_gc1_rfvga_dac(double &gain){      //clip the input      gain = dbsrx_gain_ranges["GC1"].clip(gain);      //voltage level constants -    static const float max_volts = float(1.2), min_volts = float(2.7); -    static const float slope = (max_volts-min_volts)/dbsrx_gain_ranges["GC1"].stop(); +    static const double max_volts = 1.2, min_volts = 2.7; +    static const double slope = (max_volts-min_volts)/dbsrx_gain_ranges["GC1"].stop();      //calculate the voltage for the aux dac -    float dac_volts = gain*slope + min_volts; +    double dac_volts = gain*slope + min_volts;      if (dbsrx_debug) std::cerr << boost::format(          "DBSRX GC1 Gain: %f dB, dac_volts: %f V" @@ -465,7 +465,7 @@ static float gain_to_gc1_rfvga_dac(float &gain){      return dac_volts;  } -void dbsrx::set_gain(float gain, const std::string &name){ +void dbsrx::set_gain(double gain, const std::string &name){      assert_has(dbsrx_gain_ranges.keys(), name, "dbsrx gain name");      if (name == "GC2"){          _max2118_write_regs.gc2 = gain_to_gc2_vga_reg(gain); @@ -584,7 +584,7 @@ void dbsrx::rx_set(const wax::obj &key_, const wax::obj &val){          return;      case SUBDEV_PROP_GAIN: -        this->set_gain(val.as<float>(), key.name); +        this->set_gain(val.as<double>(), key.name);          return;      case SUBDEV_PROP_ENABLED: diff --git a/host/lib/usrp/dboard/db_dbsrx2.cpp b/host/lib/usrp/dboard/db_dbsrx2.cpp index cdafd6a78..defb70ff5 100644 --- a/host/lib/usrp/dboard/db_dbsrx2.cpp +++ b/host/lib/usrp/dboard/db_dbsrx2.cpp @@ -1,5 +1,5 @@  // -// Copyright 2010 Ettus Research LLC +// Copyright 2010-2011 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 @@ -48,7 +48,7 @@ static const int dbsrx2_ref_divider = 4; // Hitachi HMC426 divider (U7)  static const prop_names_t dbsrx2_antennas = list_of("J3");  static const uhd::dict<std::string, gain_range_t> dbsrx2_gain_ranges = map_list_of -    ("GC1", gain_range_t(0, 73, float(0.05))) +    ("GC1", gain_range_t(0, 73, 0.05))      ("BBG", gain_range_t(0, 15, 1))  ; @@ -66,7 +66,7 @@ public:  private:      double _lo_freq;      double _bandwidth; -    uhd::dict<std::string, float> _gains; +    uhd::dict<std::string, double> _gains;      max2112_write_regs_t _max2112_write_regs;      max2112_read_regs_t _max2112_read_regs;      boost::uint8_t _max2112_addr(){ //0x60 or 0x61 depending on which side @@ -74,7 +74,7 @@ private:      }      void set_lo_freq(double target_freq); -    void set_gain(float gain, const std::string &name); +    void set_gain(double gain, const std::string &name);      void set_bandwidth(double bandwidth);      void send_reg(boost::uint8_t start_reg, boost::uint8_t stop_reg){ @@ -269,10 +269,10 @@ void dbsrx2::set_lo_freq(double target_freq){   * \param gain the requested gain in dB   * \return 4 bit the register value   */ -static int gain_to_bbg_vga_reg(float &gain){ +static int gain_to_bbg_vga_reg(double &gain){      int reg = boost::math::iround(dbsrx2_gain_ranges["BBG"].clip(gain)); -    gain = float(reg); +    gain = double(reg);      if (dbsrx2_debug) std::cerr           << boost::format("DBSRX2 BBG Gain:\n") @@ -288,16 +288,16 @@ static int gain_to_bbg_vga_reg(float &gain){   * \param gain the requested gain in dB   * \return dac voltage value   */ -static float gain_to_gc1_rfvga_dac(float &gain){ +static double gain_to_gc1_rfvga_dac(double &gain){      //clip the input      gain = dbsrx2_gain_ranges["GC1"].clip(gain);      //voltage level constants -    static const float max_volts = float(0.5), min_volts = float(2.7); -    static const float slope = (max_volts-min_volts)/dbsrx2_gain_ranges["GC1"].stop(); +    static const double max_volts = 0.5, min_volts = 2.7; +    static const double slope = (max_volts-min_volts)/dbsrx2_gain_ranges["GC1"].stop();      //calculate the voltage for the aux dac -    float dac_volts = gain*slope + min_volts; +    double dac_volts = gain*slope + min_volts;      if (dbsrx2_debug) std::cerr           << boost::format("DBSRX2 GC1 Gain:\n") @@ -310,7 +310,7 @@ static float gain_to_gc1_rfvga_dac(float &gain){      return dac_volts;  } -void dbsrx2::set_gain(float gain, const std::string &name){ +void dbsrx2::set_gain(double gain, const std::string &name){      assert_has(dbsrx2_gain_ranges.keys(), name, "dbsrx2 gain name");      if (name == "BBG"){          _max2112_write_regs.bbg = gain_to_bbg_vga_reg(gain); @@ -423,7 +423,7 @@ void dbsrx2::rx_set(const wax::obj &key_, const wax::obj &val){          return;      case SUBDEV_PROP_GAIN: -        this->set_gain(val.as<float>(), key.name); +        this->set_gain(val.as<double>(), key.name);          return;      case SUBDEV_PROP_ENABLED: diff --git a/host/lib/usrp/dboard/db_rfx.cpp b/host/lib/usrp/dboard/db_rfx.cpp index 74a9fb37b..cd25ee9b7 100644 --- a/host/lib/usrp/dboard/db_rfx.cpp +++ b/host/lib/usrp/dboard/db_rfx.cpp @@ -1,5 +1,5 @@  // -// Copyright 2010 Ettus Research LLC +// Copyright 2010-2011 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 @@ -67,11 +67,11 @@ static const prop_names_t rfx_rx_antennas = list_of("TX/RX")("RX2");  static const uhd::dict<std::string, gain_range_t> rfx_tx_gain_ranges; //empty  static const uhd::dict<std::string, gain_range_t> rfx_rx_gain_ranges = map_list_of -    ("PGA0", gain_range_t(0, 70, float(0.022))) +    ("PGA0", gain_range_t(0, 70, 0.022))  ;  static const uhd::dict<std::string, gain_range_t> rfx400_rx_gain_ranges = map_list_of -    ("PGA0", gain_range_t(0, 45, float(0.022))) +    ("PGA0", gain_range_t(0, 45, 0.022))  ;  /*********************************************************************** @@ -98,14 +98,14 @@ private:      const uhd::dict<dboard_iface::unit_t, bool> _div2;      double       _rx_lo_freq, _tx_lo_freq;      std::string  _rx_ant; -    uhd::dict<std::string, float> _rx_gains; +    uhd::dict<std::string, double> _rx_gains;      void set_rx_lo_freq(double freq);      void set_tx_lo_freq(double freq);      void set_rx_ant(const std::string &ant);      void set_tx_ant(const std::string &ant); -    void set_rx_gain(float gain, const std::string &name); -    void set_tx_gain(float gain, const std::string &name); +    void set_rx_gain(double gain, const std::string &name); +    void set_tx_gain(double gain, const std::string &name);      /*!       * Set the LO frequency for the particular dboard unit. @@ -240,13 +240,13 @@ void rfx_xcvr::set_tx_ant(const std::string &ant){  /***********************************************************************   * Gain Handling   **********************************************************************/ -static float rx_pga0_gain_to_dac_volts(float &gain, float range){ +static double rx_pga0_gain_to_dac_volts(double &gain, double range){      //voltage level constants (negative slope) -    static const float max_volts = float(.2), min_volts = float(1.2); -    static const float slope = (max_volts-min_volts)/(range); +    static const double max_volts = .2, min_volts = 1.2; +    static const double slope = (max_volts-min_volts)/(range);      //calculate the voltage for the aux dac -    float dac_volts = std::clip<float>(gain*slope + min_volts, max_volts, min_volts); +    double dac_volts = std::clip<double>(gain*slope + min_volts, max_volts, min_volts);      //the actual gain setting      gain = (dac_volts - min_volts)/slope; @@ -254,15 +254,15 @@ static float rx_pga0_gain_to_dac_volts(float &gain, float range){      return dac_volts;  } -void rfx_xcvr::set_tx_gain(float, const std::string &name){ +void rfx_xcvr::set_tx_gain(double, const std::string &name){      assert_has(rfx_tx_gain_ranges.keys(), name, "rfx tx gain name");      UHD_THROW_INVALID_CODE_PATH(); //no gains to set  } -void rfx_xcvr::set_rx_gain(float gain, const std::string &name){ +void rfx_xcvr::set_rx_gain(double gain, const std::string &name){      assert_has(_rx_gain_ranges.keys(), name, "rfx rx gain name");      if(name == "PGA0"){ -        float dac_volts = rx_pga0_gain_to_dac_volts(gain,  +        double dac_volts = rx_pga0_gain_to_dac_volts(gain,                                 (_rx_gain_ranges["PGA0"].stop() - _rx_gain_ranges["PGA0"].start()));          _rx_gains[name] = gain; @@ -474,7 +474,7 @@ void rfx_xcvr::rx_set(const wax::obj &key_, const wax::obj &val){          return;      case SUBDEV_PROP_GAIN: -        this->set_rx_gain(val.as<float>(), key.name); +        this->set_rx_gain(val.as<double>(), key.name);          return;      case SUBDEV_PROP_ANTENNA: @@ -571,7 +571,7 @@ void rfx_xcvr::tx_set(const wax::obj &key_, const wax::obj &val){          return;      case SUBDEV_PROP_GAIN: -        this->set_tx_gain(val.as<float>(), key.name); +        this->set_tx_gain(val.as<double>(), key.name);          return;      case SUBDEV_PROP_ANTENNA: diff --git a/host/lib/usrp/dboard/db_tvrx.cpp b/host/lib/usrp/dboard/db_tvrx.cpp index 2508555d0..4eb29c3e8 100644 --- a/host/lib/usrp/dboard/db_tvrx.cpp +++ b/host/lib/usrp/dboard/db_tvrx.cpp @@ -1,5 +1,5 @@  // -// Copyright 2010 Ettus Research LLC +// Copyright 2010-2011 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 @@ -119,8 +119,8 @@ static uhd::dict<std::string, gain_range_t> get_tvrx_gain_ranges(void) {      double ifmax = tvrx_if_gains_db.back();      return map_list_of -        ("RF", gain_range_t(float(rfmin), float(rfmax), float((rfmax-rfmin)/4096.0))) -        ("IF", gain_range_t(float(ifmin), float(ifmax), float((ifmax-ifmin)/4096.0))) +        ("RF", gain_range_t(rfmin, rfmax, (rfmax-rfmin)/4096.0)) +        ("IF", gain_range_t(ifmin, ifmax, (ifmax-ifmin)/4096.0))      ;  } @@ -141,14 +141,14 @@ public:      void rx_set(const wax::obj &key, const wax::obj &val);  private: -    uhd::dict<std::string, float> _gains; +    uhd::dict<std::string, double> _gains;      double _lo_freq;      tuner_4937di5_regs_t _tuner_4937di5_regs;      boost::uint8_t _tuner_4937di5_addr(void){          return (this->get_iface()->get_special_props().mangle_i2c_addrs)? 0x61 : 0x60; //ok really? we could rename that call      }; -    void set_gain(float gain, const std::string &name); +    void set_gain(double gain, const std::string &name);      void set_freq(double freq);      void update_regs(void){ @@ -275,7 +275,7 @@ static double gain_interp(double gain, boost::array<double, 17> db_vector, boost   * \return dac voltage value   */ -static float rf_gain_to_voltage(float gain, double lo_freq){ +static double rf_gain_to_voltage(double gain, double lo_freq){      //clip the input      gain = get_tvrx_gain_ranges()["RF"].clip(gain); @@ -293,7 +293,7 @@ static float rf_gain_to_voltage(float gain, double lo_freq){          "tvrx RF AGC gain: %f dB, dac_volts: %f V"      ) % gain % dac_volts << std::endl; -    return float(dac_volts); +    return dac_volts;  }  /*! @@ -303,7 +303,7 @@ static float rf_gain_to_voltage(float gain, double lo_freq){   * \return dac voltage value   */ -static float if_gain_to_voltage(float gain){ +static double if_gain_to_voltage(double gain){      //clip the input      gain = get_tvrx_gain_ranges()["IF"].clip(gain); @@ -316,10 +316,10 @@ static float if_gain_to_voltage(float gain){          "tvrx IF AGC gain: %f dB, dac_volts: %f V"      ) % gain % dac_volts << std::endl; -    return float(dac_volts); +    return dac_volts;  } -void tvrx::set_gain(float gain, const std::string &name){ +void tvrx::set_gain(double gain, const std::string &name){      assert_has(get_tvrx_gain_ranges().keys(), name, "tvrx gain name");      if (name == "RF"){          this->get_iface()->write_aux_dac(dboard_iface::UNIT_RX, dboard_iface::AUX_DAC_B, rf_gain_to_voltage(gain, _lo_freq)); @@ -473,7 +473,7 @@ void tvrx::rx_set(const wax::obj &key_, const wax::obj &val){      //handle the get request conditioned on the key      switch(key.as<subdev_prop_t>()){      case SUBDEV_PROP_GAIN: -        this->set_gain(val.as<float>(), key.name); +        this->set_gain(val.as<double>(), key.name);          return;      case SUBDEV_PROP_FREQ: diff --git a/host/lib/usrp/dboard/db_unknown.cpp b/host/lib/usrp/dboard/db_unknown.cpp index 168e1971c..d91d58409 100644 --- a/host/lib/usrp/dboard/db_unknown.cpp +++ b/host/lib/usrp/dboard/db_unknown.cpp @@ -1,5 +1,5 @@  // -// Copyright 2010 Ettus Research LLC +// Copyright 2010-2011 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 @@ -115,7 +115,7 @@ void unknown_rx::rx_get(const wax::obj &key_, wax::obj &val){          return;      case SUBDEV_PROP_GAIN: -        val = float(0); +        val = double(0);          return;      case SUBDEV_PROP_GAIN_RANGE: @@ -173,7 +173,7 @@ void unknown_rx::rx_set(const wax::obj &key_, const wax::obj &val){      switch(key.as<subdev_prop_t>()){      case SUBDEV_PROP_GAIN: -        UHD_ASSERT_THROW(val.as<float>() == float(0)); +        UHD_ASSERT_THROW(val.as<double>() == double(0));          return;      case SUBDEV_PROP_ANTENNA: @@ -217,7 +217,7 @@ void unknown_tx::tx_get(const wax::obj &key_, wax::obj &val){          return;      case SUBDEV_PROP_GAIN: -        val = float(0); +        val = double(0);          return;      case SUBDEV_PROP_GAIN_RANGE: @@ -275,7 +275,7 @@ void unknown_tx::tx_set(const wax::obj &key_, const wax::obj &val){      switch(key.as<subdev_prop_t>()){      case SUBDEV_PROP_GAIN: -        UHD_ASSERT_THROW(val.as<float>() == float(0)); +        UHD_ASSERT_THROW(val.as<double>() == double(0));          return;      case SUBDEV_PROP_ANTENNA: diff --git a/host/lib/usrp/dboard/db_wbx.cpp b/host/lib/usrp/dboard/db_wbx.cpp index dd5bd600b..135997789 100644 --- a/host/lib/usrp/dboard/db_wbx.cpp +++ b/host/lib/usrp/dboard/db_wbx.cpp @@ -1,5 +1,5 @@  // -// Copyright 2010 Ettus Research LLC +// Copyright 2010-2011 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 @@ -94,11 +94,11 @@ static const prop_names_t wbx_tx_antennas = list_of("TX/RX");  static const prop_names_t wbx_rx_antennas = list_of("TX/RX")("RX2");  static const uhd::dict<std::string, gain_range_t> wbx_tx_gain_ranges = map_list_of -    ("PGA0", gain_range_t(0, 25, float(0.05))) +    ("PGA0", gain_range_t(0, 25, 0.05))  ;  static const uhd::dict<std::string, gain_range_t> wbx_rx_gain_ranges = map_list_of -    ("PGA0", gain_range_t(0, 31.5, float(0.5))) +    ("PGA0", gain_range_t(0, 31.5, 0.5))  ;  /*********************************************************************** @@ -116,7 +116,7 @@ public:      void tx_set(const wax::obj &key, const wax::obj &val);  private: -    uhd::dict<std::string, float> _tx_gains, _rx_gains; +    uhd::dict<std::string, double> _tx_gains, _rx_gains;      double       _rx_lo_freq, _tx_lo_freq;      std::string  _tx_ant, _rx_ant; @@ -124,8 +124,8 @@ private:      void set_tx_lo_freq(double freq);      void set_rx_ant(const std::string &ant);      void set_tx_ant(const std::string &ant); -    void set_rx_gain(float gain, const std::string &name); -    void set_tx_gain(float gain, const std::string &name); +    void set_rx_gain(double gain, const std::string &name); +    void set_tx_gain(double gain, const std::string &name);      void update_atr(void); @@ -196,12 +196,12 @@ wbx_xcvr::~wbx_xcvr(void){  /***********************************************************************   * Gain Handling   **********************************************************************/ -static int rx_pga0_gain_to_iobits(float &gain){ +static int rx_pga0_gain_to_iobits(double &gain){      //clip the input      gain = wbx_rx_gain_ranges["PGA0"].clip(gain);      //convert to attenuation and update iobits for atr -    float attn = wbx_rx_gain_ranges["PGA0"].stop() - gain; +    double attn = wbx_rx_gain_ranges["PGA0"].stop() - gain;      //calculate the attenuation      int attn_code = boost::math::iround(attn*2); @@ -212,21 +212,21 @@ static int rx_pga0_gain_to_iobits(float &gain){      ) % attn % attn_code % (iobits & RX_ATTN_MASK) % RX_ATTN_MASK << std::endl;      //the actual gain setting -    gain = wbx_rx_gain_ranges["PGA0"].stop() - float(attn_code)/2; +    gain = wbx_rx_gain_ranges["PGA0"].stop() - double(attn_code)/2;      return iobits;  } -static float tx_pga0_gain_to_dac_volts(float &gain){ +static double tx_pga0_gain_to_dac_volts(double &gain){      //clip the input      gain = wbx_tx_gain_ranges["PGA0"].clip(gain);      //voltage level constants -    static const float max_volts = float(0.5), min_volts = float(1.4); -    static const float slope = (max_volts-min_volts)/wbx_tx_gain_ranges["PGA0"].stop(); +    static const double max_volts = 0.5, min_volts = 1.4; +    static const double slope = (max_volts-min_volts)/wbx_tx_gain_ranges["PGA0"].stop();      //calculate the voltage for the aux dac -    float dac_volts = gain*slope + min_volts; +    double dac_volts = gain*slope + min_volts;      if (wbx_debug) std::cerr << boost::format(          "WBX TX Gain: %f dB, dac_volts: %f V" @@ -238,10 +238,10 @@ static float tx_pga0_gain_to_dac_volts(float &gain){      return dac_volts;  } -void wbx_xcvr::set_tx_gain(float gain, const std::string &name){ +void wbx_xcvr::set_tx_gain(double gain, const std::string &name){      assert_has(wbx_tx_gain_ranges.keys(), name, "wbx tx gain name");      if(name == "PGA0"){ -        float dac_volts = tx_pga0_gain_to_dac_volts(gain); +        double dac_volts = tx_pga0_gain_to_dac_volts(gain);          _tx_gains[name] = gain;          //write the new voltage to the aux dac @@ -250,7 +250,7 @@ void wbx_xcvr::set_tx_gain(float gain, const std::string &name){      else UHD_THROW_INVALID_CODE_PATH();  } -void wbx_xcvr::set_rx_gain(float gain, const std::string &name){ +void wbx_xcvr::set_rx_gain(double gain, const std::string &name){      assert_has(wbx_rx_gain_ranges.keys(), name, "wbx rx gain name");      if(name == "PGA0"){          rx_pga0_gain_to_iobits(gain); @@ -544,7 +544,7 @@ void wbx_xcvr::rx_set(const wax::obj &key_, const wax::obj &val){          return;      case SUBDEV_PROP_GAIN: -        this->set_rx_gain(val.as<float>(), key.name); +        this->set_rx_gain(val.as<double>(), key.name);          return;      case SUBDEV_PROP_ANTENNA: @@ -645,7 +645,7 @@ void wbx_xcvr::tx_set(const wax::obj &key_, const wax::obj &val){          return;      case SUBDEV_PROP_GAIN: -        this->set_tx_gain(val.as<float>(), key.name); +        this->set_tx_gain(val.as<double>(), key.name);          return;      case SUBDEV_PROP_ANTENNA: diff --git a/host/lib/usrp/dboard/db_xcvr2450.cpp b/host/lib/usrp/dboard/db_xcvr2450.cpp index e76727bec..6fb5a26a8 100644 --- a/host/lib/usrp/dboard/db_xcvr2450.cpp +++ b/host/lib/usrp/dboard/db_xcvr2450.cpp @@ -1,5 +1,5 @@  // -// Copyright 2010 Ettus Research LLC +// Copyright 2010-2011 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 @@ -73,8 +73,8 @@ using namespace boost::assign;  static const bool xcvr2450_debug = false;  static const freq_range_t xcvr_freq_range = list_of -    (range_t<double>(2.4e9, 2.5e9)) -    (range_t<double>(4.9e9, 6.0e9)) +    (range_t(2.4e9, 2.5e9)) +    (range_t(4.9e9, 6.0e9))  ;  static const prop_names_t xcvr_antennas = list_of("J1")("J2"); @@ -85,9 +85,9 @@ static const uhd::dict<std::string, gain_range_t> xcvr_tx_gain_ranges = map_list  ;  static const uhd::dict<std::string, gain_range_t> xcvr_rx_gain_ranges = map_list_of      ("LNA", gain_range_t(list_of -        (range_t<float>(0)) -        (range_t<float>(15)) -        (range_t<float>(30.5)) +        (range_t(0)) +        (range_t(15)) +        (range_t(30.5))      ))      ("VGA", gain_range_t(0, 62, 2.0))  ; @@ -109,7 +109,7 @@ public:  private:      double _lo_freq;      double _rx_bandwidth, _tx_bandwidth; -    uhd::dict<std::string, float> _tx_gains, _rx_gains; +    uhd::dict<std::string, double> _tx_gains, _rx_gains;      std::string _tx_ant, _rx_ant;      int _ad9515div;      max2829_regs_t _max2829_regs; @@ -117,8 +117,8 @@ private:      void set_lo_freq(double target_freq);      void set_tx_ant(const std::string &ant);      void set_rx_ant(const std::string &ant); -    void set_tx_gain(float gain, const std::string &name); -    void set_rx_gain(float gain, const std::string &name); +    void set_tx_gain(double gain, const std::string &name); +    void set_rx_gain(double gain, const std::string &name);      void set_rx_bandwidth(double bandwidth);      void set_tx_bandwidth(double bandwidth); @@ -150,12 +150,12 @@ private:       * Read the RSSI from the aux adc       * \return the rssi in dB       */ -    float get_rssi(void){ +    double get_rssi(void){          //constants for the rssi calculation -        static const float min_v = float(0.5), max_v = float(2.5); -        static const float rssi_dyn_range = 60; +        static const double min_v = 0.5, max_v = 2.5; +        static const double rssi_dyn_range = 60;          //calculate the rssi from the voltage -        float voltage = this->get_iface()->read_aux_adc(dboard_iface::UNIT_RX, dboard_iface::AUX_ADC_B); +        double voltage = this->get_iface()->read_aux_adc(dboard_iface::UNIT_RX, dboard_iface::AUX_ADC_B);          return rssi_dyn_range*(voltage - min_v)/(max_v - min_v);      }  }; @@ -355,14 +355,14 @@ void xcvr2450::set_rx_ant(const std::string &ant){   * \param gain the requested gain in dB   * \return 6 bit the register value   */ -static int gain_to_tx_vga_reg(float &gain){ +static int gain_to_tx_vga_reg(double &gain){      //calculate the register value      int reg = std::clip(boost::math::iround(gain*60/30.0) + 3, 0, 63);      //calculate the actual gain value      if (reg < 4)       gain = 0; -    else if (reg < 48) gain = float(reg/2 - 1); -    else               gain = float(reg/2.0 - 1.5); +    else if (reg < 48) gain = double(reg/2 - 1); +    else               gain = double(reg/2.0 - 1.5);      //return register value      return reg; @@ -374,7 +374,7 @@ static int gain_to_tx_vga_reg(float &gain){   * \param gain the requested gain in dB   * \return gain enum value   */ -static max2829_regs_t::tx_baseband_gain_t gain_to_tx_bb_reg(float &gain){ +static max2829_regs_t::tx_baseband_gain_t gain_to_tx_bb_reg(double &gain){      int reg = std::clip(boost::math::iround(gain*3/5.0), 0, 3);      switch(reg){      case 0: @@ -399,9 +399,9 @@ static max2829_regs_t::tx_baseband_gain_t gain_to_tx_bb_reg(float &gain){   * \param gain the requested gain in dB   * \return 5 bit the register value   */ -static int gain_to_rx_vga_reg(float &gain){ +static int gain_to_rx_vga_reg(double &gain){      int reg = std::clip(boost::math::iround(gain/2.0), 0, 31); -    gain = float(reg*2); +    gain = double(reg*2);      return reg;  } @@ -411,7 +411,7 @@ static int gain_to_rx_vga_reg(float &gain){   * \param gain the requested gain in dB   * \return 2 bit the register value   */ -static int gain_to_rx_lna_reg(float &gain){ +static int gain_to_rx_lna_reg(double &gain){      int reg = std::clip(boost::math::iround(gain*2/30.5) + 1, 0, 3);      switch(reg){      case 0: @@ -422,7 +422,7 @@ static int gain_to_rx_lna_reg(float &gain){      return reg;  } -void xcvr2450::set_tx_gain(float gain, const std::string &name){ +void xcvr2450::set_tx_gain(double gain, const std::string &name){      assert_has(xcvr_tx_gain_ranges.keys(), name, "xcvr tx gain name");      if (name == "VGA"){          _max2829_regs.tx_vga_gain = gain_to_tx_vga_reg(gain); @@ -436,7 +436,7 @@ void xcvr2450::set_tx_gain(float gain, const std::string &name){      _tx_gains[name] = gain;  } -void xcvr2450::set_rx_gain(float gain, const std::string &name){ +void xcvr2450::set_rx_gain(double gain, const std::string &name){      assert_has(xcvr_rx_gain_ranges.keys(), name, "xcvr rx gain name");      if (name == "VGA"){          _max2829_regs.rx_vga_gain = gain_to_rx_vga_reg(gain); @@ -643,7 +643,7 @@ void xcvr2450::rx_set(const wax::obj &key_, const wax::obj &val){          return;      case SUBDEV_PROP_GAIN: -        this->set_rx_gain(val.as<float>(), key.name); +        this->set_rx_gain(val.as<double>(), key.name);          return;      case SUBDEV_PROP_ANTENNA: @@ -742,7 +742,7 @@ void xcvr2450::tx_set(const wax::obj &key_, const wax::obj &val){          return;      case SUBDEV_PROP_GAIN: -        this->set_tx_gain(val.as<float>(), key.name); +        this->set_tx_gain(val.as<double>(), key.name);          return;      case SUBDEV_PROP_BANDWIDTH: diff --git a/host/lib/usrp/usrp2/gps_ctrl.cpp b/host/lib/usrp/gps_ctrl.cpp index 2273b2cd9..3c7c00134 100644 --- a/host/lib/usrp/usrp2/gps_ctrl.cpp +++ b/host/lib/usrp/gps_ctrl.cpp @@ -15,7 +15,7 @@  // along with this program.  If not, see <http://www.gnu.org/licenses/>.  // -#include "gps_ctrl.hpp" +#include <uhd/usrp/gps_ctrl.hpp>  #include <uhd/utils/assert.hpp>  #include <boost/cstdint.hpp>  #include <string> @@ -30,14 +30,15 @@ using namespace boost::posix_time;  using namespace boost::algorithm;  /*! - * A usrp2 GPS control for Jackson Labs devices + * A GPS control for Jackson Labs devices (and other NMEA compatible GPS's)   */  //TODO: multiple baud rate support (requires mboard_impl changes for poking UART registers) -class usrp2_gps_ctrl_impl : public usrp2_gps_ctrl{ +class gps_ctrl_impl : public gps_ctrl{  public: -  usrp2_gps_ctrl_impl(usrp2_iface::sptr iface){ -    _iface = iface; +  gps_ctrl_impl(gps_send_fn_t send, gps_recv_fn_t recv){ +    _send = send; +    _recv = recv;      std::string reply;      bool i_heard_some_nmea = false, i_heard_something_weird = false; @@ -47,8 +48,8 @@ public:  //    set_uart_baud_rate(GPS_UART, 115200);      //first we look for a Jackson Labs Firefly (since that's what we sell with the USRP2+...) -    _iface->read_uart(GPS_UART); //get whatever junk is in the rx buffer right now, and throw it away -    _iface->write_uart(GPS_UART, "HAAAY GUYYYYS\n"); //to elicit a response from the Firefly +    _recv(); //get whatever junk is in the rx buffer right now, and throw it away +    _send("HAAAY GUYYYYS\n"); //to elicit a response from the Firefly      //then we loop until we either timeout, or until we get a response that indicates we're a JL device      int timeout = GPS_TIMEOUT_TRIES; @@ -60,13 +61,14 @@ public:        }        else if(reply.substr(0, 3) == "$GP") i_heard_some_nmea = true; //but keep looking for that "Command Error" response        else if(reply.length() != 0) i_heard_something_weird = true; //probably wrong baud rate +      boost::this_thread::sleep(boost::posix_time::milliseconds(200));      }      if((i_heard_some_nmea) && (gps_type != GPS_TYPE_JACKSON_LABS)) gps_type = GPS_TYPE_GENERIC_NMEA;      //otherwise, we can try some other common baud rates looking to see if a GPS is connected (todo, later)      if((gps_type == GPS_TYPE_NONE) && i_heard_something_weird) { -      std::cout << "Invalid reply, possible incorrect baud rate" << std::endl; +      std::cout << "GPS invalid reply \"" << reply << "\", assuming none available" << std::endl;      }      bool found_gprmc = false; @@ -78,15 +80,15 @@ public:        //none of these should issue replies so we don't bother looking for them        //we have to sleep between commands because the JL device, despite not acking, takes considerable time to process each command.         boost::this_thread::sleep(boost::posix_time::milliseconds(FIREFLY_STUPID_DELAY_MS)); -      _iface->write_uart(GPS_UART, "SYST:COMM:SER:ECHO OFF\n"); +      _send("SYST:COMM:SER:ECHO OFF\n");         boost::this_thread::sleep(boost::posix_time::milliseconds(FIREFLY_STUPID_DELAY_MS)); -      _iface->write_uart(GPS_UART, "SYST:COMM:SER:PRO OFF\n"); +      _send("SYST:COMM:SER:PRO OFF\n");         boost::this_thread::sleep(boost::posix_time::milliseconds(FIREFLY_STUPID_DELAY_MS)); -      _iface->write_uart(GPS_UART, "GPS:GPGGA 0\n"); +      _send("GPS:GPGGA 0\n");         boost::this_thread::sleep(boost::posix_time::milliseconds(FIREFLY_STUPID_DELAY_MS)); -      _iface->write_uart(GPS_UART, "GPS:GGAST 0\n"); +      _send("GPS:GGAST 0\n");         boost::this_thread::sleep(boost::posix_time::milliseconds(FIREFLY_STUPID_DELAY_MS)); -      _iface->write_uart(GPS_UART, "GPS:GPRMC 1\n"); +      _send("GPS:GPRMC 1\n");         boost::this_thread::sleep(boost::posix_time::milliseconds(FIREFLY_STUPID_DELAY_MS));  //      break; @@ -119,15 +121,15 @@ public:    } -  ~usrp2_gps_ctrl_impl(void){ +  ~gps_ctrl_impl(void){    } +//TODO: this isn't generalizeable to non-USRP2 USRPs.    std::string safe_gps_read() {      std::string reply;      try { -        reply = _iface->read_uart(GPS_UART); -  	    //std::cerr << "Got reply from GPS: " << reply.c_str() << " with length = " << reply.length() << std::endl; +        reply = _recv();      } catch (std::runtime_error err) {        if(err.what() != std::string("usrp2 no control response")) throw; //sorry can't cope with that        else { //we don't actually have a GPS installed @@ -185,7 +187,8 @@ public:    }  private: -  usrp2_iface::sptr _iface; +  gps_send_fn_t _send; +  gps_recv_fn_t _recv;    enum {      GPS_TYPE_JACKSON_LABS, @@ -193,8 +196,8 @@ private:      GPS_TYPE_NONE    } gps_type; -  static const int GPS_UART = 2; //TODO: this should be plucked from fw_common.h or memory_map.h or somewhere in common with the firmware    static const int GPS_TIMEOUT_TRIES = 5; +  static const int GPS_TIMEOUT_DELAY_MS = 200;    static const int FIREFLY_STUPID_DELAY_MS = 200;  }; @@ -202,6 +205,6 @@ private:  /***********************************************************************   * Public make function for the GPS control   **********************************************************************/ -usrp2_gps_ctrl::sptr usrp2_gps_ctrl::make(usrp2_iface::sptr iface){ -    return sptr(new usrp2_gps_ctrl_impl(iface)); +gps_ctrl::sptr gps_ctrl::make(gps_send_fn_t send, gps_recv_fn_t recv){ +    return sptr(new gps_ctrl_impl(send, recv));  } diff --git a/host/lib/usrp/mboard_eeprom.cpp b/host/lib/usrp/mboard_eeprom.cpp index 863a80191..f7f4b2c68 100644 --- a/host/lib/usrp/mboard_eeprom.cpp +++ b/host/lib/usrp/mboard_eeprom.cpp @@ -1,5 +1,5 @@  // -// Copyright 2010 Ettus Research LLC +// Copyright 2010-2011 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 @@ -97,8 +97,14 @@ static void load_n100(mboard_eeprom_t &mb_eeprom, i2c_iface &iface){          N100_EEPROM_ADDR, USRP_N100_OFFSETS["name"], NAME_MAX_LEN      )); -    //empty serial correction: use the mac address -    if (mb_eeprom["serial"].empty()) mb_eeprom["serial"] = mb_eeprom["mac-addr"]; +    //Empty serial correction: use the mac address to determine serial. +    //Older usrp2 models don't have a serial burned into EEPROM. +    //The lower mac address bits will function as the serial number. +    if (mb_eeprom["serial"].empty()){ +        byte_vector_t mac_addr_bytes = mac_addr_t::from_string(mb_eeprom["mac-addr"]).to_bytes(); +        unsigned serial = mac_addr_bytes.at(5) | (unsigned(mac_addr_bytes.at(4) & 0x0f) << 8); +        mb_eeprom["serial"] = boost::lexical_cast<std::string>(serial); +    }  }  static void store_n100(const mboard_eeprom_t &mb_eeprom, i2c_iface &iface){ diff --git a/host/lib/usrp/misc_utils.cpp b/host/lib/usrp/misc_utils.cpp index 5856d706f..02f4b216d 100644 --- a/host/lib/usrp/misc_utils.cpp +++ b/host/lib/usrp/misc_utils.cpp @@ -1,5 +1,5 @@  // -// Copyright 2010 Ettus Research LLC +// Copyright 2010-2011 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 @@ -39,24 +39,24 @@ static gain_range_t get_codec_gain_range(wax::obj codec, const std::string &name      return codec[named_prop_t(CODEC_PROP_GAIN_RANGE, name)].as<gain_range_t>();  } -static float get_codec_gain_i(wax::obj codec, const std::string &name){ -    return codec[named_prop_t(CODEC_PROP_GAIN_I, name)].as<float>(); +static double get_codec_gain_i(wax::obj codec, const std::string &name){ +    return codec[named_prop_t(CODEC_PROP_GAIN_I, name)].as<double>();  } -static float get_codec_gain_q(wax::obj codec, const std::string &name){ -    return codec[named_prop_t(CODEC_PROP_GAIN_Q, name)].as<float>(); +static double get_codec_gain_q(wax::obj codec, const std::string &name){ +    return codec[named_prop_t(CODEC_PROP_GAIN_Q, name)].as<double>();  } -static void set_codec_gain_both(wax::obj codec, const std::string &name, float gain){ +static void set_codec_gain_both(wax::obj codec, const std::string &name, double gain){      codec[named_prop_t(CODEC_PROP_GAIN_I, name)] = gain;      codec[named_prop_t(CODEC_PROP_GAIN_Q, name)] = gain;  } -static void set_codec_gain_i(wax::obj codec, const std::string &name, float gain){ +static void set_codec_gain_i(wax::obj codec, const std::string &name, double gain){      codec[named_prop_t(CODEC_PROP_GAIN_I, name)] = gain;  } -static void set_codec_gain_q(wax::obj codec, const std::string &name, float gain){ +static void set_codec_gain_q(wax::obj codec, const std::string &name, double gain){      codec[named_prop_t(CODEC_PROP_GAIN_Q, name)] = gain;  } @@ -64,15 +64,15 @@ static void set_codec_gain_q(wax::obj codec, const std::string &name, float gain   * subdev gain group helper functions:   *    do this so we dont have to bind a templated function   **********************************************************************/ -static float get_subdev_gain(wax::obj subdev, const std::string &name){ -    return subdev[named_prop_t(SUBDEV_PROP_GAIN, name)].as<float>(); +static double get_subdev_gain(wax::obj subdev, const std::string &name){ +    return subdev[named_prop_t(SUBDEV_PROP_GAIN, name)].as<double>();  }  static gain_range_t get_subdev_gain_range(wax::obj subdev, const std::string &name){      return subdev[named_prop_t(SUBDEV_PROP_GAIN_RANGE, name)].as<gain_range_t>();  } -static void set_subdev_gain(wax::obj subdev, const std::string &name, float gain){ +static void set_subdev_gain(wax::obj subdev, const std::string &name, double gain){      subdev[named_prop_t(SUBDEV_PROP_GAIN, name)] = gain;  } diff --git a/host/lib/usrp/multi_usrp.cpp b/host/lib/usrp/multi_usrp.cpp index 876f1a3fc..48eec28c1 100644 --- a/host/lib/usrp/multi_usrp.cpp +++ b/host/lib/usrp/multi_usrp.cpp @@ -1,5 +1,5 @@  // -// Copyright 2010 Ettus Research LLC +// Copyright 2010-2011 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 @@ -117,26 +117,32 @@ public:          return _mboard(0)[MBOARD_PROP_TIME_NOW].as<time_spec_t>();      } +    time_spec_t get_time_last_pps(void){ +        return _mboard(0)[MBOARD_PROP_TIME_PPS].as<time_spec_t>(); +    } +      void set_time_next_pps(const time_spec_t &time_spec){          for (size_t m = 0; m < get_num_mboards(); m++){ -            _mboard(m)[MBOARD_PROP_TIME_NEXT_PPS] = time_spec; +            _mboard(m)[MBOARD_PROP_TIME_PPS] = time_spec;          }      }      void set_time_unknown_pps(const time_spec_t &time_spec){ -        std::cout << "Set time with unknown pps edge:" << std::endl; -        std::cout << "    1) set times next pps (race condition)" << std::endl; -        set_time_next_pps(time_spec); -        boost::this_thread::sleep(boost::posix_time::seconds(1)); - -        std::cout << "    2) catch seconds rollover at pps edge" << std::endl; -        time_t last_secs = 0, curr_secs = 0; -        while(curr_secs == last_secs){ -            last_secs = curr_secs; -            curr_secs = get_time_now().get_full_secs(); +        std::cout << "    1) catch time transition at pps edge" << std::endl; +        time_spec_t time_start = get_time_now(); +        time_spec_t time_start_last_pps = get_time_last_pps(); +        while(true){ +            if (get_time_last_pps() != time_start_last_pps) break; +            if ((get_time_now() - time_start) > time_spec_t(1.1)){ +                throw std::runtime_error( +                    "Board 0 may not be getting a PPS signal!\n" +                    "No PPS detected within the time interval.\n" +                    "See the application notes for your device.\n" +                ); +            }          } -        std::cout << "    3) set times next pps (synchronously)" << std::endl; +        std::cout << "    2) set times next pps (synchronously)" << std::endl;          set_time_next_pps(time_spec);          boost::this_thread::sleep(boost::posix_time::seconds(1)); @@ -233,11 +239,11 @@ public:          return add_dsp_shift(_rx_subdev(chan)[SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>(), _rx_dsp(chan/rx_cpm()));      } -    void set_rx_gain(float gain, const std::string &name, size_t chan){ +    void set_rx_gain(double gain, const std::string &name, size_t chan){          return _rx_gain_group(chan)->set_value(gain, name);      } -    float get_rx_gain(const std::string &name, size_t chan){ +    double get_rx_gain(const std::string &name, size_t chan){          return _rx_gain_group(chan)->get_value(name);      } @@ -273,8 +279,8 @@ public:          return _rx_subdev(chan)[SUBDEV_PROP_BANDWIDTH].as<double>();      } -    float read_rssi(size_t chan){ -        return _rx_subdev(chan)[SUBDEV_PROP_RSSI].as<float>(); +    double read_rssi(size_t chan){ +        return _rx_subdev(chan)[SUBDEV_PROP_RSSI].as<double>();      }      dboard_iface::sptr get_rx_dboard_iface(size_t chan){ @@ -331,11 +337,11 @@ public:          return add_dsp_shift(_tx_subdev(chan)[SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>(), _tx_dsp(chan/tx_cpm()));      } -    void set_tx_gain(float gain, const std::string &name, size_t chan){ +    void set_tx_gain(double gain, const std::string &name, size_t chan){          return _tx_gain_group(chan)->set_value(gain, name);      } -    float get_tx_gain(const std::string &name, size_t chan){ +    double get_tx_gain(const std::string &name, size_t chan){          return _tx_gain_group(chan)->get_value(name);      } diff --git a/host/lib/usrp/single_usrp.cpp b/host/lib/usrp/single_usrp.cpp index a0456d1f0..c37449c5f 100644 --- a/host/lib/usrp/single_usrp.cpp +++ b/host/lib/usrp/single_usrp.cpp @@ -1,5 +1,5 @@  // -// Copyright 2010 Ettus Research LLC +// Copyright 2010-2011 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 @@ -106,12 +106,16 @@ public:          return _mboard()[MBOARD_PROP_TIME_NOW].as<time_spec_t>();      } +    time_spec_t get_time_last_pps(void){ +        return _mboard()[MBOARD_PROP_TIME_PPS].as<time_spec_t>(); +    } +      void set_time_now(const time_spec_t &time_spec){          _mboard()[MBOARD_PROP_TIME_NOW] = time_spec;      }      void set_time_next_pps(const time_spec_t &time_spec){ -        _mboard()[MBOARD_PROP_TIME_NEXT_PPS] = time_spec; +        _mboard()[MBOARD_PROP_TIME_PPS] = time_spec;      }      void issue_stream_cmd(const stream_cmd_t &stream_cmd){ @@ -160,11 +164,11 @@ public:          return add_dsp_shift(_rx_subdev(chan)[SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>(), _rx_dsp());      } -    void set_rx_gain(float gain, const std::string &name, size_t chan){ +    void set_rx_gain(double gain, const std::string &name, size_t chan){          return _rx_gain_group(chan)->set_value(gain, name);      } -    float get_rx_gain(const std::string &name, size_t chan){ +    double get_rx_gain(const std::string &name, size_t chan){          return _rx_gain_group(chan)->get_value(name);      } @@ -200,8 +204,8 @@ public:          return _rx_subdev(chan)[SUBDEV_PROP_BANDWIDTH].as<double>();      } -    float read_rssi(size_t chan){ -        return _rx_subdev(chan)[SUBDEV_PROP_RSSI].as<float>(); +    double read_rssi(size_t chan){ +        return _rx_subdev(chan)[SUBDEV_PROP_RSSI].as<double>();      }      dboard_iface::sptr get_rx_dboard_iface(size_t chan){ @@ -246,11 +250,11 @@ public:          return add_dsp_shift(_tx_subdev(chan)[SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>(), _tx_dsp());      } -    void set_tx_gain(float gain, const std::string &name, size_t chan){ +    void set_tx_gain(double gain, const std::string &name, size_t chan){          return _tx_gain_group(chan)->set_value(gain, name);      } -    float get_tx_gain(const std::string &name, size_t chan){ +    double get_tx_gain(const std::string &name, size_t chan){          return _tx_gain_group(chan)->get_value(name);      } diff --git a/host/lib/usrp/subdev_spec.cpp b/host/lib/usrp/subdev_spec.cpp index 95d2cbb12..51c88bda3 100644 --- a/host/lib/usrp/subdev_spec.cpp +++ b/host/lib/usrp/subdev_spec.cpp @@ -1,5 +1,5 @@  // -// Copyright 2010 Ettus Research LLC +// Copyright 2010-2011 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 @@ -16,15 +16,21 @@  //  #include <uhd/usrp/subdev_spec.hpp> -#include <uhd/utils/algorithm.hpp> +#include <boost/algorithm/string.hpp> //for split +#include <boost/tokenizer.hpp>  #include <boost/format.hpp>  #include <boost/foreach.hpp>  #include <stdexcept>  #include <sstream> +#include <vector>  using namespace uhd;  using namespace uhd::usrp; +#define pair_tokenizer(inp) \ +    boost::tokenizer<boost::char_separator<char> > \ +    (inp, boost::char_separator<char>(" ")) +  subdev_spec_pair_t::subdev_spec_pair_t(      const std::string &db_name, const std::string &sd_name  ): @@ -39,9 +45,9 @@ bool usrp::operator==(const subdev_spec_pair_t &lhs, const subdev_spec_pair_t &r  }  subdev_spec_t::subdev_spec_t(const std::string &markup){ -    BOOST_FOREACH(const std::string &pair, std::split_string(markup)){ +    BOOST_FOREACH(const std::string &pair, pair_tokenizer(markup)){          if (pair == "") continue; -        std::vector<std::string> db_sd = std::split_string(pair, ":"); +        std::vector<std::string> db_sd; boost::split(db_sd, pair, boost::is_any_of(":"));          switch(db_sd.size()){          case 1: this->push_back(subdev_spec_pair_t("", db_sd.front())); break;          case 2: this->push_back(subdev_spec_pair_t(db_sd.front(), db_sd.back())); break; diff --git a/host/lib/usrp/usrp1/CMakeLists.txt b/host/lib/usrp/usrp1/CMakeLists.txt index 519e17bfa..9e50f5728 100644 --- a/host/lib/usrp/usrp1/CMakeLists.txt +++ b/host/lib/usrp/usrp1/CMakeLists.txt @@ -1,5 +1,5 @@  # -# Copyright 2010 Ettus Research LLC +# Copyright 2010-2011 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 @@ -38,6 +38,7 @@ IF(ENABLE_USRP1)          ${CMAKE_CURRENT_SOURCE_DIR}/dsp_impl.cpp          ${CMAKE_CURRENT_SOURCE_DIR}/io_impl.cpp          ${CMAKE_CURRENT_SOURCE_DIR}/mboard_impl.cpp +        ${CMAKE_CURRENT_SOURCE_DIR}/soft_time_ctrl.cpp          ${CMAKE_CURRENT_SOURCE_DIR}/usrp1_iface.cpp          ${CMAKE_CURRENT_SOURCE_DIR}/usrp1_iface.hpp          ${CMAKE_CURRENT_SOURCE_DIR}/usrp1_impl.cpp diff --git a/host/lib/usrp/usrp1/codec_ctrl.cpp b/host/lib/usrp/usrp1/codec_ctrl.cpp index 18f794632..f3816b377 100644 --- a/host/lib/usrp/usrp1/codec_ctrl.cpp +++ b/host/lib/usrp/usrp1/codec_ctrl.cpp @@ -1,5 +1,5 @@  // -// Copyright 2010 Ettus Research LLC +// Copyright 2010-2011 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 @@ -35,7 +35,7 @@ using namespace uhd;  static const bool codec_debug = false; -const gain_range_t usrp1_codec_ctrl::tx_pga_gain_range(-20, 0, float(0.1)); +const gain_range_t usrp1_codec_ctrl::tx_pga_gain_range(-20, 0, double(0.1));  const gain_range_t usrp1_codec_ctrl::rx_pga_gain_range(0, 20, 1);  /*********************************************************************** @@ -50,17 +50,18 @@ public:      ~usrp1_codec_ctrl_impl(void);      //aux adc and dac control -    float read_aux_adc(aux_adc_t which); -    void write_aux_dac(aux_dac_t which, float volts); +    double read_aux_adc(aux_adc_t which); +    void write_aux_dac(aux_dac_t which, double volts);      //duc control      void set_duc_freq(double freq); +    void enable_tx_digital(bool enb);      //pga gain control -    void set_tx_pga_gain(float); -    float get_tx_pga_gain(void); -    void set_rx_pga_gain(float, char); -    float get_rx_pga_gain(char); +    void set_tx_pga_gain(double); +    double get_tx_pga_gain(void); +    void set_rx_pga_gain(double, char); +    double get_rx_pga_gain(char);      //rx adc buffer control      void bypass_adc_buffers(bool bypass); @@ -159,19 +160,19 @@ usrp1_codec_ctrl_impl::~usrp1_codec_ctrl_impl(void)   **********************************************************************/  static const int mtpgw = 255; //maximum tx pga gain word -void usrp1_codec_ctrl_impl::set_tx_pga_gain(float gain){ +void usrp1_codec_ctrl_impl::set_tx_pga_gain(double gain){      int gain_word = int(mtpgw*(gain - tx_pga_gain_range.start())/(tx_pga_gain_range.stop() - tx_pga_gain_range.start()));      _ad9862_regs.tx_pga_gain = std::clip(gain_word, 0, mtpgw);      this->send_reg(16);  } -float usrp1_codec_ctrl_impl::get_tx_pga_gain(void){ +double usrp1_codec_ctrl_impl::get_tx_pga_gain(void){      return (_ad9862_regs.tx_pga_gain*(tx_pga_gain_range.stop() - tx_pga_gain_range.start())/mtpgw) + tx_pga_gain_range.start();  }  static const int mrpgw = 0x14; //maximum rx pga gain word -void usrp1_codec_ctrl_impl::set_rx_pga_gain(float gain, char which){ +void usrp1_codec_ctrl_impl::set_rx_pga_gain(double gain, char which){      int gain_word = int(mrpgw*(gain - rx_pga_gain_range.start())/(rx_pga_gain_range.stop() - rx_pga_gain_range.start()));      gain_word = std::clip(gain_word, 0, mrpgw);      switch(which){ @@ -187,7 +188,7 @@ void usrp1_codec_ctrl_impl::set_rx_pga_gain(float gain, char which){      }  } -float usrp1_codec_ctrl_impl::get_rx_pga_gain(char which){ +double usrp1_codec_ctrl_impl::get_rx_pga_gain(char which){      int gain_word;      switch(which){      case 'A': gain_word = _ad9862_regs.rx_pga_a; break; @@ -200,12 +201,12 @@ float usrp1_codec_ctrl_impl::get_rx_pga_gain(char which){  /***********************************************************************   * Codec Control AUX ADC Methods   **********************************************************************/ -static float aux_adc_to_volts(boost::uint8_t high, boost::uint8_t low) +static double aux_adc_to_volts(boost::uint8_t high, boost::uint8_t low)  { -    return float(((boost::uint16_t(high) << 2) | low)*3.3)/0x3ff; +    return double(((boost::uint16_t(high) << 2) | low)*3.3)/0x3ff;  } -float usrp1_codec_ctrl_impl::read_aux_adc(aux_adc_t which) +double usrp1_codec_ctrl_impl::read_aux_adc(aux_adc_t which)  {      //check to see if the switch needs to be set      bool write_switch = false; @@ -259,7 +260,7 @@ float usrp1_codec_ctrl_impl::read_aux_adc(aux_adc_t which)  /***********************************************************************   * Codec Control AUX DAC Methods   **********************************************************************/ -void usrp1_codec_ctrl_impl::write_aux_dac(aux_dac_t which, float volts) +void usrp1_codec_ctrl_impl::write_aux_dac(aux_dac_t which, double volts)  {      //special case for aux dac d (aka sigma delta word)      if (which == AUX_DAC_D) { @@ -421,6 +422,11 @@ void usrp1_codec_ctrl_impl::set_duc_freq(double freq)      this->send_reg(23);  } +void usrp1_codec_ctrl_impl::enable_tx_digital(bool enb){ +    _ad9862_regs.tx_digital_pd = (enb)? 0 : 1; +    this->send_reg(8); +} +  /***********************************************************************   * Codec Control ADC buffer bypass   * Disable this for AC-coupled daughterboards (TVRX) diff --git a/host/lib/usrp/usrp1/codec_ctrl.hpp b/host/lib/usrp/usrp1/codec_ctrl.hpp index e2e8a010d..20e4015c5 100644 --- a/host/lib/usrp/usrp1/codec_ctrl.hpp +++ b/host/lib/usrp/usrp1/codec_ctrl.hpp @@ -1,5 +1,5 @@  // -// Copyright 2010 Ettus Research LLC +// Copyright 2010-2011 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 @@ -61,7 +61,7 @@ public:       * \param which which of the 4 adcs       * \return a value in volts       */ -    virtual float read_aux_adc(aux_adc_t which) = 0; +    virtual double read_aux_adc(aux_adc_t which) = 0;      //! aux dac identifier constants      enum aux_dac_t{ @@ -76,23 +76,26 @@ public:       * \param which which of the 4 dacs       * \param volts the level in in volts       */ -    virtual void write_aux_dac(aux_dac_t which, float volts) = 0; +    virtual void write_aux_dac(aux_dac_t which, double volts) = 0;      //! Set the TX PGA gain -    virtual void set_tx_pga_gain(float gain) = 0; +    virtual void set_tx_pga_gain(double gain) = 0;      //! Get the TX PGA gain -    virtual float get_tx_pga_gain(void) = 0; +    virtual double get_tx_pga_gain(void) = 0;      //! Set the RX PGA gain ('A' or 'B') -    virtual void set_rx_pga_gain(float gain, char which) = 0; +    virtual void set_rx_pga_gain(double gain, char which) = 0;      //! Get the RX PGA gain ('A' or 'B') -    virtual float get_rx_pga_gain(char which) = 0; +    virtual double get_rx_pga_gain(char which) = 0;      //! Set the TX modulator frequency      virtual void set_duc_freq(double freq) = 0; -     + +    //! Enable or disable the digital part of the DAC +    virtual void enable_tx_digital(bool enb) = 0; +      //! Enable or disable ADC buffer bypass      virtual void bypass_adc_buffers(bool bypass) = 0;  }; diff --git a/host/lib/usrp/usrp1/codec_impl.cpp b/host/lib/usrp/usrp1/codec_impl.cpp index db53be53e..14ecd2d2e 100644 --- a/host/lib/usrp/usrp1/codec_impl.cpp +++ b/host/lib/usrp/usrp1/codec_impl.cpp @@ -1,5 +1,5 @@  // -// Copyright 2010 Ettus Research LLC +// Copyright 2010-2011 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 @@ -92,12 +92,12 @@ void usrp1_impl::rx_codec_set(const wax::obj &key_, const wax::obj &val, dboard_      switch(key.as<codec_prop_t>()) {      case CODEC_PROP_GAIN_I:          UHD_ASSERT_THROW(key.name == adc_pga_gain_name); -        _codec_ctrls[dboard_slot]->set_rx_pga_gain(val.as<float>(), 'A'); +        _codec_ctrls[dboard_slot]->set_rx_pga_gain(val.as<double>(), 'A');          return;      case CODEC_PROP_GAIN_Q:          UHD_ASSERT_THROW(key.name == adc_pga_gain_name); -        _codec_ctrls[dboard_slot]->set_rx_pga_gain(val.as<float>(), 'B'); +        _codec_ctrls[dboard_slot]->set_rx_pga_gain(val.as<double>(), 'B');          return;      default: UHD_THROW_PROP_SET_ERROR(); @@ -151,7 +151,7 @@ void usrp1_impl::tx_codec_set(const wax::obj &key_, const wax::obj &val, dboard_      case CODEC_PROP_GAIN_I: //only one gain for I and Q      case CODEC_PROP_GAIN_Q:          UHD_ASSERT_THROW(key.name == dac_pga_gain_name); -        _codec_ctrls[dboard_slot]->set_tx_pga_gain(val.as<float>()); +        _codec_ctrls[dboard_slot]->set_tx_pga_gain(val.as<double>());          return;      default: UHD_THROW_PROP_SET_ERROR(); diff --git a/host/lib/usrp/usrp1/dboard_iface.cpp b/host/lib/usrp/usrp1/dboard_iface.cpp index 4e47d6bf6..eec4a52db 100644 --- a/host/lib/usrp/usrp1/dboard_iface.cpp +++ b/host/lib/usrp/usrp1/dboard_iface.cpp @@ -1,5 +1,5 @@  // -// Copyright 2010 Ettus Research LLC +// Copyright 2010-2011 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 @@ -72,8 +72,8 @@ public:          return props;      } -    void write_aux_dac(unit_t, aux_dac_t, float); -    float read_aux_adc(unit_t, aux_adc_t); +    void write_aux_dac(unit_t, aux_dac_t, double); +    double read_aux_adc(unit_t, aux_adc_t);      void _set_pin_ctrl(unit_t, boost::uint16_t);      void _set_atr_reg(unit_t, atr_reg_t, boost::uint16_t); @@ -369,7 +369,7 @@ byte_vector_t usrp1_dboard_iface::read_i2c(boost::uint8_t addr,   * Aux DAX/ADC   **********************************************************************/  void usrp1_dboard_iface::write_aux_dac(dboard_iface::unit_t, -                                       aux_dac_t which, float value) +                                       aux_dac_t which, double value)  {      //same aux dacs for each unit      static const uhd::dict<aux_dac_t, usrp1_codec_ctrl::aux_dac_t> @@ -382,7 +382,7 @@ void usrp1_dboard_iface::write_aux_dac(dboard_iface::unit_t,      _codec->write_aux_dac(which_to_aux_dac[which], value);  } -float usrp1_dboard_iface::read_aux_adc(dboard_iface::unit_t unit, +double usrp1_dboard_iface::read_aux_adc(dboard_iface::unit_t unit,                                         aux_adc_t which)  {      static const diff --git a/host/lib/usrp/usrp1/io_impl.cpp b/host/lib/usrp/usrp1/io_impl.cpp index 6728d9b15..9fa1b4f72 100644 --- a/host/lib/usrp/usrp1/io_impl.cpp +++ b/host/lib/usrp/usrp1/io_impl.cpp @@ -1,5 +1,5 @@  // -// Copyright 2010 Ettus Research LLC +// Copyright 2010-2011 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 @@ -19,7 +19,6 @@  #include "usrp_commands.h"  #include "usrp1_impl.hpp"  #include <uhd/utils/thread_priority.hpp> -#include <uhd/transport/convert_types.hpp>  #include <uhd/transport/bounded_buffer.hpp>  #include <boost/bind.hpp>  #include <boost/format.hpp> @@ -92,6 +91,7 @@ struct usrp1_impl::io_impl{      void commit_send_buff(offset_send_buffer::sptr, offset_send_buffer::sptr, size_t);      void flush_send_buff(void);      bool get_send_buffs(vrt_packet_handler::managed_send_buffs_t &, double); +    bool transmitting_enb;  };  /*! @@ -184,6 +184,28 @@ void usrp1_impl::io_init(void){      _tx_otw_type.byteorder = otw_type_t::BO_LITTLE_ENDIAN;      _io_impl = UHD_PIMPL_MAKE(io_impl, (_data_transport)); + +    _soft_time_ctrl = soft_time_ctrl::make( +        boost::bind(&usrp1_impl::rx_stream_on_off, this, _1) +    ); + +    rx_stream_on_off(false); +    tx_stream_on_off(false); +} + +void usrp1_impl::rx_stream_on_off(bool enb){ +    return _iface->write_firmware_cmd(VRQ_FPGA_SET_RX_ENABLE, enb, 0, 0, 0); +    //drain any junk in the receive transport after stop streaming command +    while(not enb and _data_transport->get_recv_buff().get() != NULL){ +        /* NOP */ +    } +} + +void usrp1_impl::tx_stream_on_off(bool enb){ +    if (not enb) _io_impl->flush_send_buff(); +    _codec_ctrls[DBOARD_SLOT_A]->enable_tx_digital(enb); +    _codec_ctrls[DBOARD_SLOT_B]->enable_tx_digital(enb); +    _io_impl->transmitting_enb = enb;  }  /*********************************************************************** @@ -209,6 +231,9 @@ size_t usrp1_impl::send(      const tx_metadata_t &metadata, const io_type_t &io_type,      send_mode_t send_mode, double timeout  ){ +    if (_soft_time_ctrl->send_pre(metadata, timeout)) return num_samps; +    if (not _io_impl->transmitting_enb) tx_stream_on_off(true); +      size_t num_samps_sent = vrt_packet_handler::send(          _io_impl->packet_handler_send_state,       //last state of the send handler          buffs, num_samps,                          //buffer to fill @@ -222,9 +247,11 @@ size_t usrp1_impl::send(          _tx_subdev_spec.size()                     //num channels      ); -    //Don't honor sob because it is normal to be always bursting... -    //handle eob flag (commit the buffer) -    if (metadata.end_of_burst) _io_impl->flush_send_buff(); +    //handle eob flag (commit the buffer, disable the DACs) +    //check num samps sent to avoid flush on incomplete/timeout +    if (metadata.end_of_burst and num_samps_sent == num_samps){ +        this->tx_stream_on_off(false); +    }      //handle the polling for underflow conditions      _io_impl->underflow_poll_samp_count += num_samps_sent; @@ -296,6 +323,8 @@ size_t usrp1_impl::recv(          _rx_subdev_spec.size()                     //num channels      ); +    _soft_time_ctrl->recv_post(metadata, num_samps_recvd); +      //handle the polling for overflow conditions      _io_impl->overflow_poll_samp_count += num_samps_recvd;      if (_io_impl->overflow_poll_samp_count >= _rx_samps_per_poll_interval){ diff --git a/host/lib/usrp/usrp1/mboard_impl.cpp b/host/lib/usrp/usrp1/mboard_impl.cpp index 4df5ada0a..23c8f03c4 100644 --- a/host/lib/usrp/usrp1/mboard_impl.cpp +++ b/host/lib/usrp/usrp1/mboard_impl.cpp @@ -1,5 +1,5 @@  // -// Copyright 2010 Ettus Research LLC +// Copyright 2010-2011 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 @@ -240,19 +240,6 @@ void usrp1_impl::mboard_init(void)      }  } -void usrp1_impl::issue_stream_cmd(const stream_cmd_t &stream_cmd) -{ -    switch(stream_cmd.stream_mode){ -    case stream_cmd_t::STREAM_MODE_START_CONTINUOUS: -        return _iface->write_firmware_cmd(VRQ_FPGA_SET_RX_ENABLE, true, 0, 0, 0); - -    case stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS: -        return _iface->write_firmware_cmd(VRQ_FPGA_SET_RX_ENABLE, false, 0, 0, 0); - -    default: throw std::runtime_error("unsupported stream command type for USRP1"); -    } -} -  /***********************************************************************   * Mboard Get   **********************************************************************/ @@ -326,6 +313,10 @@ void usrp1_impl::mboard_get(const wax::obj &key_, wax::obj &val)          val = _iface->mb_eeprom;          return; +    case MBOARD_PROP_TIME_NOW: +        val = _soft_time_ctrl->get_time(); +        return; +      default: UHD_THROW_PROP_GET_ERROR();      }  } @@ -348,7 +339,7 @@ void usrp1_impl::mboard_set(const wax::obj &key, const wax::obj &val)      switch(key.as<mboard_prop_t>()){      case MBOARD_PROP_STREAM_CMD: -        issue_stream_cmd(val.as<stream_cmd_t>()); +        _soft_time_ctrl->issue_stream_cmd(val.as<stream_cmd_t>());          return;      case MBOARD_PROP_RX_SUBDEV_SPEC: @@ -384,6 +375,10 @@ void usrp1_impl::mboard_set(const wax::obj &key, const wax::obj &val)          _iface->mb_eeprom = mboard_eeprom_t(*_iface, mboard_eeprom_t::MAP_B000);          return; +    case MBOARD_PROP_TIME_NOW: +        _soft_time_ctrl->set_time(val.as<time_spec_t>()); +        return; +      default: UHD_THROW_PROP_SET_ERROR();      }  } diff --git a/host/lib/usrp/usrp1/soft_time_ctrl.cpp b/host/lib/usrp/usrp1/soft_time_ctrl.cpp new file mode 100644 index 000000000..4d6abe218 --- /dev/null +++ b/host/lib/usrp/usrp1/soft_time_ctrl.cpp @@ -0,0 +1,224 @@ +// +// Copyright 2011 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 "soft_time_ctrl.hpp" +#include <uhd/transport/bounded_buffer.hpp> +#include <boost/any.hpp> +#include <boost/thread.hpp> +#include <boost/date_time/posix_time/posix_time.hpp> +#include <boost/date_time/local_time/local_time.hpp> +#include <iostream> + +using namespace uhd; +using namespace uhd::usrp; +using namespace uhd::transport; +namespace pt = boost::posix_time; +namespace lt = boost::local_time; + +static const time_spec_t TWIDDLE(0.0015); + +/*********************************************************************** + * Utility helper functions + **********************************************************************/ + +//TODO put these in time_spec_t (maybe useful) + +static const double time_dur_tps = double(pt::time_duration::ticks_per_second()); + +time_spec_t time_dur_to_time_spec(const pt::time_duration &time_dur){ +    return time_spec_t( +        time_dur.total_seconds(), +        long(time_dur.fractional_seconds()), +        time_dur_tps +    ); +} + +pt::time_duration time_spec_to_time_dur(const time_spec_t &time_spec){ +    return pt::time_duration( +        0, 0, long(time_spec.get_full_secs()), +        time_spec.get_tick_count(time_dur_tps) +    ); +} + +/*********************************************************************** + * Soft time control implementation + **********************************************************************/ +class soft_time_ctrl_impl : public soft_time_ctrl{ +public: + +    soft_time_ctrl_impl(const cb_fcn_type &stream_on_off): +        _nsamps_remaining(0), +        _stream_mode(stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS), +        _cmd_queue(bounded_buffer<boost::any>::make(2)), +        _stream_on_off(stream_on_off) +    { +        //synchronously spawn a new thread +        _update_mutex.lock(); //lock mutex before spawned +        _thread_group.create_thread(boost::bind(&soft_time_ctrl_impl::recv_cmd_dispatcher, this)); +        _update_mutex.lock(); //lock blocks until spawned +        _update_mutex.unlock(); //unlock mutex before done +    } + +    ~soft_time_ctrl_impl(void){ +        _thread_group.interrupt_all(); +        _thread_group.join_all(); +    } + +    /******************************************************************* +     * Time control +     ******************************************************************/ +    void set_time(const time_spec_t &time){ +        boost::mutex::scoped_lock lock(_update_mutex); +        _time_offset = boost::get_system_time() - time_spec_to_time_dur(time); +    } + +    time_spec_t get_time(void){ +        boost::mutex::scoped_lock lock(_update_mutex); +        return time_now(); +    } + +    UHD_INLINE time_spec_t time_now(void){ +        //internal get time without scoped lock +        return time_dur_to_time_spec(boost::get_system_time() - _time_offset); +    } + +    UHD_INLINE void sleep_until_time( +        boost::mutex::scoped_lock &lock, const time_spec_t &time +    ){ +        boost::condition_variable cond; +        //use a condition variable to unlock, sleep, lock +        cond.timed_wait(lock, _time_offset + time_spec_to_time_dur(time)); +    } + +    /******************************************************************* +     * Receive control +     ******************************************************************/ +    void recv_post(rx_metadata_t &md, size_t &nsamps){ +        boost::mutex::scoped_lock lock(_update_mutex); + +        //load the metadata with the expected time +        md.has_time_spec = true; +        md.time_spec = time_now(); + +        //none of the stuff below matters in continuous streaming mode +        if (_stream_mode == stream_cmd_t::STREAM_MODE_START_CONTINUOUS) return; + +        //When to stop streaming: +        //The samples have been received and the stream mode is non-continuous. +        //Rewrite the sample count to clip to the requested number of samples. +        if (_nsamps_remaining <= nsamps){ +            nsamps = _nsamps_remaining; //set nsamps, then stop +            md.end_of_burst = true; +            stream_on_off(false); +            return; +        } + +        //update the consumed samples +        _nsamps_remaining -= nsamps; +    } + +    void issue_stream_cmd(const stream_cmd_t &cmd){ +        _cmd_queue->push_with_wait(cmd); +    } + +    void stream_on_off(bool enb){ +        _stream_on_off(enb); +        _nsamps_remaining = 0; +    } + +    /******************************************************************* +     * Transmit control +     ******************************************************************/ +    bool send_pre(const tx_metadata_t &md, double &timeout){ +        if (not md.has_time_spec) return false; + +        boost::mutex::scoped_lock lock(_update_mutex); + +        time_spec_t time_at(md.time_spec - TWIDDLE); + +        //handle late packets +        if (time_at < time_now()){ +            //TODO post async message +            return true; +        } + +        timeout -= (time_at - time_now()).get_real_secs(); +        sleep_until_time(lock, time_at); +        return false; +    } + +    /******************************************************************* +     * Thread control +     ******************************************************************/ +    void recv_cmd_handle_cmd(const stream_cmd_t &cmd){ +        boost::mutex::scoped_lock lock(_update_mutex); + +        //handle the stream at time by sleeping +        if (not cmd.stream_now){ +            time_spec_t time_at(cmd.time_spec - TWIDDLE); +            if (time_at < time_now()){ +                //TODO inject late cmd inline error +            } +            else{ +                sleep_until_time(lock, time_at); +            } +        } + +        //When to stop streaming: +        //Stop streaming when the command is a stop and streaming. +        if (cmd.stream_mode == stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS +           and _stream_mode != stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS +        ) stream_on_off(false); + +        //When to start streaming: +        //Start streaming when the command is not a stop and not streaming. +        if (cmd.stream_mode != stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS +           and _stream_mode == stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS +        ) stream_on_off(true); + +        //update the state +        _nsamps_remaining += cmd.num_samps; +        _stream_mode = cmd.stream_mode; +    } + +    void recv_cmd_dispatcher(void){ +        _update_mutex.unlock(); +        try{ +            boost::any cmd; +            while (true){ +                _cmd_queue->pop_with_wait(cmd); +                recv_cmd_handle_cmd(boost::any_cast<stream_cmd_t>(cmd)); +            } +        } catch(const boost::thread_interrupted &){} +    } + +private: +    boost::mutex _update_mutex; +    size_t _nsamps_remaining; +    stream_cmd_t::stream_mode_t _stream_mode; +    pt::ptime _time_offset; +    bounded_buffer<boost::any>::sptr _cmd_queue; +    const cb_fcn_type _stream_on_off; +    boost::thread_group _thread_group; +}; + +/*********************************************************************** + * Soft time control factor + **********************************************************************/ +soft_time_ctrl::sptr soft_time_ctrl::make(const cb_fcn_type &stream_on_off){ +    return sptr(new soft_time_ctrl_impl(stream_on_off)); +} diff --git a/host/lib/usrp/usrp1/soft_time_ctrl.hpp b/host/lib/usrp/usrp1/soft_time_ctrl.hpp new file mode 100644 index 000000000..7fdac7fc8 --- /dev/null +++ b/host/lib/usrp/usrp1/soft_time_ctrl.hpp @@ -0,0 +1,69 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_LIBUHD_USRP_USRP1_SOFT_TIME_CTRL_HPP +#define INCLUDED_LIBUHD_USRP_USRP1_SOFT_TIME_CTRL_HPP + +#include <uhd/types/stream_cmd.hpp> +#include <uhd/types/time_spec.hpp> +#include <uhd/types/metadata.hpp> +#include <boost/utility.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/function.hpp> + +namespace uhd{ namespace usrp{ + +/*! + * The soft time control emulates some of the + * advanced streaming capabilities of the later USRP models. + * Soft time control uses the system time to emulate + * timed transmits, timed receive commands, device time, + * and inline and async error messages. + */ +class soft_time_ctrl : boost::noncopyable{ +public: +    typedef boost::shared_ptr<soft_time_ctrl> sptr; +    typedef boost::function<void(bool)> cb_fcn_type; + +    /*! +     * Make a new soft time control. +     * \param stream_on_off a function to enable/disable rx +     * \return a new soft time control object +     */ +    static sptr make(const cb_fcn_type &stream_on_off); +        //TODO pass in the error queue for async msgs +        //TODO pass in the queue for inline msgs + +    //! Set the current time +    virtual void set_time(const time_spec_t &time) = 0; + +    //! Get the current time +    virtual time_spec_t get_time(void) = 0; + +    //! Call after the internal recv function +    virtual void recv_post(rx_metadata_t &md, size_t &nsamps) = 0; + +    //! Call before the internal send function +    virtual bool send_pre(const tx_metadata_t &md, double &timeout) = 0; + +    //! Issue a stream command to receive +    virtual void issue_stream_cmd(const stream_cmd_t &cmd) = 0; +}; + +}} //namespace + +#endif /* INCLUDED_LIBUHD_USRP_USRP1_SOFT_TIME_CTRL_HPP */ diff --git a/host/lib/usrp/usrp1/usrp1_ctrl.cpp b/host/lib/usrp/usrp1/usrp1_ctrl.cpp index 5043aed7d..09f854813 100644 --- a/host/lib/usrp/usrp1/usrp1_ctrl.cpp +++ b/host/lib/usrp/usrp1/usrp1_ctrl.cpp @@ -139,13 +139,6 @@ public:          _ctrl_transport = ctrl_transport;      } - -    ~usrp_ctrl_impl(void) -    { -        /* NOP */ -    } - -      int usrp_load_firmware(std::string filestring, bool force)      {          const char *filename = filestring.c_str(); @@ -233,6 +226,20 @@ public:          return -1;      } +    void usrp_init(void){ +        /* not calling because this causes junk to come at init +         * and it does not seem to be necessary to call anyway +        usrp_rx_enable(false); +        usrp_rx_reset(true); +        usrp_rx_reset(false); +        usrp_rx_enable(true); +        */ + +        usrp_tx_enable(false); +        usrp_tx_reset(true); +        usrp_tx_reset(false); +        usrp_tx_enable(true); +    }      int usrp_load_fpga(std::string filestring)      { @@ -288,7 +295,7 @@ public:          usrp_set_fpga_hash(hash);          file.close();          if (load_img_msg) std::cout << " done" << std::endl; -        return 0;  +        return 0;      }      int usrp_load_eeprom(std::string filestring) @@ -393,6 +400,12 @@ public:      } +    int usrp_rx_reset(bool on) +    { +        return usrp_control_write_cmd(VRQ_FPGA_SET_RX_RESET, on, 0);  +    } + +      int usrp_control_write(boost::uint8_t request,                             boost::uint16_t value,                             boost::uint16_t index, diff --git a/host/lib/usrp/usrp1/usrp1_ctrl.hpp b/host/lib/usrp/usrp1/usrp1_ctrl.hpp index a02d9f96c..8ccfacab7 100644 --- a/host/lib/usrp/usrp1/usrp1_ctrl.hpp +++ b/host/lib/usrp/usrp1/usrp1_ctrl.hpp @@ -33,6 +33,9 @@ public:       */      static sptr make(uhd::transport::usb_control::sptr ctrl_transport); +    //! Call init after the fpga is loaded +    virtual void usrp_init(void) = 0; +      /*!       * Load firmware in Intel HEX Format onto device        * \param filename name of firmware file @@ -93,20 +96,6 @@ public:      virtual int usrp_set_fpga_hash(size_t hash) = 0;      /*! -     * Set rx enable or disable  -     * \param on enable or disable value -     * \return 0 on success, error code otherwise -     */ -    virtual int usrp_rx_enable(bool on) = 0; - -    /*! -     * Set rx enable or disable  -     * \param on enable or disable value -     * \return 0 on success, error code otherwise -     */ -    virtual int usrp_tx_enable(bool on) = 0; - -    /*!       * Submit an IN transfer        * \param request device specific request        * \param value device specific field diff --git a/host/lib/usrp/usrp1/usrp1_impl.cpp b/host/lib/usrp/usrp1/usrp1_impl.cpp index 6016b0979..c395db0b9 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.cpp +++ b/host/lib/usrp/usrp1/usrp1_impl.cpp @@ -1,5 +1,5 @@  // -// Copyright 2010 Ettus Research LLC +// Copyright 2010-2011 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 @@ -139,6 +139,7 @@ static device::sptr usrp1_make(const device_addr_t &device_addr){      usb_control::sptr ctrl_transport = usb_control::make(handle);      usrp_ctrl::sptr usrp_ctrl = usrp_ctrl::make(ctrl_transport);      usrp_ctrl->usrp_load_fpga(usrp1_fpga_image); +    usrp_ctrl->usrp_init();      usb_zero_copy::sptr data_transport = usb_zero_copy::make(          handle,        // identifier          6,             // IN endpoint @@ -192,9 +193,6 @@ usrp1_impl::usrp1_impl(uhd::transport::usb_zero_copy::sptr data_transport,      //initialize the send/recv      io_init(); -    //turn on the transmitter -    _ctrl_transport->usrp_tx_enable(true); -      //init the subdev specs      this->mboard_set(MBOARD_PROP_RX_SUBDEV_SPEC, subdev_spec_t());      this->mboard_set(MBOARD_PROP_TX_SUBDEV_SPEC, subdev_spec_t()); diff --git a/host/lib/usrp/usrp1/usrp1_impl.hpp b/host/lib/usrp/usrp1/usrp1_impl.hpp index ff4d40762..057725394 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.hpp +++ b/host/lib/usrp/usrp1/usrp1_impl.hpp @@ -1,5 +1,5 @@  // -// Copyright 2010 Ettus Research LLC +// Copyright 2010-2011 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 @@ -19,6 +19,7 @@  #include "usrp1_ctrl.hpp"  #include "clock_ctrl.hpp"  #include "codec_ctrl.hpp" +#include "soft_time_ctrl.hpp"  #include <uhd/device.hpp>  #include <uhd/utils/pimpl.hpp>  #include <uhd/types/dict.hpp> @@ -114,13 +115,17 @@ private:          const uhd::usrp::dboard_id_t &rx_dboard_id      ); +    //soft time control emulation +    uhd::usrp::soft_time_ctrl::sptr _soft_time_ctrl; +      //interface to ioctls and file descriptor      usrp1_iface::sptr _iface;      //handle io stuff      UHD_PIMPL_DECL(io_impl) _io_impl;      void io_init(void); -    void issue_stream_cmd(const uhd::stream_cmd_t &stream_cmd); +    void rx_stream_on_off(bool); +    void tx_stream_on_off(bool);      void handle_overrun(size_t);      //underrun and overrun poll intervals diff --git a/host/lib/usrp/usrp2/CMakeLists.txt b/host/lib/usrp/usrp2/CMakeLists.txt index 527669852..e8811a8fb 100644 --- a/host/lib/usrp/usrp2/CMakeLists.txt +++ b/host/lib/usrp/usrp2/CMakeLists.txt @@ -34,12 +34,8 @@ IF(ENABLE_USRP2)          ${CMAKE_CURRENT_SOURCE_DIR}/dboard_impl.cpp          ${CMAKE_CURRENT_SOURCE_DIR}/dboard_iface.cpp          ${CMAKE_CURRENT_SOURCE_DIR}/dsp_impl.cpp -        ${CMAKE_CURRENT_SOURCE_DIR}/gps_ctrl.hpp -        ${CMAKE_CURRENT_SOURCE_DIR}/gps_ctrl.cpp          ${CMAKE_CURRENT_SOURCE_DIR}/io_impl.cpp          ${CMAKE_CURRENT_SOURCE_DIR}/mboard_impl.cpp -        ${CMAKE_CURRENT_SOURCE_DIR}/serdes_ctrl.cpp -        ${CMAKE_CURRENT_SOURCE_DIR}/serdes_ctrl.hpp          ${CMAKE_CURRENT_SOURCE_DIR}/usrp2_iface.cpp          ${CMAKE_CURRENT_SOURCE_DIR}/usrp2_iface.hpp          ${CMAKE_CURRENT_SOURCE_DIR}/usrp2_impl.cpp diff --git a/host/lib/usrp/usrp2/clock_ctrl.cpp b/host/lib/usrp/usrp2/clock_ctrl.cpp index 428d5539b..27ccefb2b 100644 --- a/host/lib/usrp/usrp2/clock_ctrl.cpp +++ b/host/lib/usrp/usrp2/clock_ctrl.cpp @@ -22,10 +22,13 @@  #include <uhd/utils/assert.hpp>  #include <boost/cstdint.hpp>  #include <boost/lexical_cast.hpp> +#include <boost/math/special_functions/round.hpp>  #include <iostream>  using namespace uhd; +static const bool enb_test_clk = false; +  /*!   * A usrp2 clock control specific to the ad9510 ic.   */ @@ -66,13 +69,12 @@ public:          this->enable_external_ref(false);          this->enable_rx_dboard_clock(false);          this->enable_tx_dboard_clock(false); +        this->enable_mimo_clock_out(false);          /* private clock enables, must be set here */          this->enable_dac_clock(true);          this->enable_adc_clock(true); - -        /* always driving the mimo reference */ -        this->enable_mimo_clock_out(true); +        this->enable_test_clock(enb_test_clk);      }      ~usrp2_clock_ctrl_impl(void){ @@ -83,6 +85,7 @@ public:          this->enable_dac_clock(false);          this->enable_adc_clock(false);          this->enable_mimo_clock_out(false); +        this->enable_test_clock(false);      }      void enable_mimo_clock_out(bool enb){ @@ -246,6 +249,54 @@ public:      double get_master_clock_rate(void){          return 100e6;      } +     +    void set_mimo_clock_delay(double delay) { +        //delay_val is a 5-bit value (0-31) for fine control +        //the equations below determine delay for a given ramp current, # of caps and fine delay register +        //delay range: +        //range_ns = 200*((caps+3)/i_ramp_ua)*1.3286 +        //offset (zero delay): +        //offset_ns = 0.34 + (1600 - i_ramp_ua)*1e-4 + ((caps-1)/ramp)*6 +        //delay_ns = offset_ns + range_ns * delay / 31 + +        int delay_val = boost::math::iround(delay/9.744e-9*31); + +        if(delay_val == 0) { +            switch(clk_regs.exp) { +            case 5: +                _ad9510_regs.delay_control_out5 = 1; +                break; +            case 6: +                _ad9510_regs.delay_control_out6 = 1; +                break; +            default: +                break; //delay not supported on U2 rev 3 +            } +        } else { +            switch(clk_regs.exp) { +            case 5: +                _ad9510_regs.delay_control_out5 = 0; +                _ad9510_regs.ramp_current_out5 = ad9510_regs_t::RAMP_CURRENT_OUT5_200UA; +                _ad9510_regs.ramp_capacitor_out5 = ad9510_regs_t::RAMP_CAPACITOR_OUT5_4CAPS; +                _ad9510_regs.delay_fine_adjust_out5 = delay_val; +                this->write_reg(0x34); +                this->write_reg(0x35); +                this->write_reg(0x36); +                break; +            case 6: +                _ad9510_regs.delay_control_out6 = 0; +                _ad9510_regs.ramp_current_out6 = ad9510_regs_t::RAMP_CURRENT_OUT6_200UA; +                _ad9510_regs.ramp_capacitor_out6 = ad9510_regs_t::RAMP_CAPACITOR_OUT6_4CAPS; +                _ad9510_regs.delay_fine_adjust_out6 = delay_val; +                this->write_reg(0x38); +                this->write_reg(0x39); +                this->write_reg(0x3A); +                break; +            default: +                break; +            } +        } +    }  private:      /*! diff --git a/host/lib/usrp/usrp2/clock_ctrl.hpp b/host/lib/usrp/usrp2/clock_ctrl.hpp index db6c52c83..9ccbc959e 100644 --- a/host/lib/usrp/usrp2/clock_ctrl.hpp +++ b/host/lib/usrp/usrp2/clock_ctrl.hpp @@ -91,8 +91,18 @@ public:      virtual void enable_test_clock(bool enb) = 0;      /*! -     * TODO other clock control api here.... +     * Enable/disable the ref clock output over the serdes cable. +     * \param enb true to enable +     */ +    virtual void enable_mimo_clock_out(bool enb) = 0; +     +    /*! +     * Set the output delay of the mimo clock +     * Used to synchronise daisy-chained USRPs over the MIMO cable +     * Can also be used to adjust delay for uneven reference cable lengths +     * \param delay the clock delay in seconds       */ +    virtual void set_mimo_clock_delay(double delay) = 0;  }; diff --git a/host/lib/usrp/usrp2/codec_ctrl.cpp b/host/lib/usrp/usrp2/codec_ctrl.cpp index 3a34afe11..890969b5a 100644 --- a/host/lib/usrp/usrp2/codec_ctrl.cpp +++ b/host/lib/usrp/usrp2/codec_ctrl.cpp @@ -1,5 +1,5 @@  // -// Copyright 2010 Ettus Research LLC +// Copyright 2010-2011 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 @@ -124,7 +124,7 @@ public:          this->send_ad9777_reg(0x01); //set the register      } -    void set_rx_digital_gain(float gain) {  //fine digital gain +    void set_rx_digital_gain(double gain) {  //fine digital gain          switch(_iface->get_rev()){          case usrp2_iface::USRP_N200:          case usrp2_iface::USRP_N210: @@ -136,7 +136,7 @@ public:          }      } -    void set_rx_digital_fine_gain(float gain) { //gain correction       +    void set_rx_digital_fine_gain(double gain) { //gain correction                switch(_iface->get_rev()){          case usrp2_iface::USRP_N200:          case usrp2_iface::USRP_N210: @@ -148,7 +148,7 @@ public:          }      } -    void set_rx_analog_gain(bool gain) { //turns on/off analog 3.5dB preamp +    void set_rx_analog_gain(bool /*gain*/) { //turns on/off analog 3.5dB preamp          switch(_iface->get_rev()){          case usrp2_iface::USRP_N200:          case usrp2_iface::USRP_N210: diff --git a/host/lib/usrp/usrp2/codec_ctrl.hpp b/host/lib/usrp/usrp2/codec_ctrl.hpp index c8d977a1f..ca300e2b1 100644 --- a/host/lib/usrp/usrp2/codec_ctrl.hpp +++ b/host/lib/usrp/usrp2/codec_ctrl.hpp @@ -1,5 +1,5 @@  // -// Copyright 2010 Ettus Research LLC +// Copyright 2010-2011 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 @@ -54,14 +54,14 @@ public:       * \param gain from 0-6dB       */ -    virtual void set_rx_digital_gain(float gain) = 0; +    virtual void set_rx_digital_gain(double gain) = 0;      /*!       * Set the digital gain correction on the USRP2+ ADC (ADS62P44).       * \param gain from 0-0.5dB       */ -    virtual void set_rx_digital_fine_gain(float gain) = 0; +    virtual void set_rx_digital_fine_gain(double gain) = 0;  }; diff --git a/host/lib/usrp/usrp2/codec_impl.cpp b/host/lib/usrp/usrp2/codec_impl.cpp index 8299ce0a6..d7078d985 100644 --- a/host/lib/usrp/usrp2/codec_impl.cpp +++ b/host/lib/usrp/usrp2/codec_impl.cpp @@ -1,5 +1,5 @@  // -// Copyright 2010 Ettus Research LLC +// Copyright 2010-2011 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 @@ -28,10 +28,10 @@ using namespace uhd;  using namespace uhd::usrp;  using namespace boost::assign; -//this only applies to USRP2P +//this only applies to N2XX  static const uhd::dict<std::string, gain_range_t> codec_rx_gain_ranges = map_list_of -                                  ("digital", gain_range_t(0, float(6.0), float(0.5))) -                                  ("digital-fine", gain_range_t(0, float(0.5), float(0.05))); +                                  ("digital", gain_range_t(0, 6.0, 0.5)) +                                  ("digital-fine", gain_range_t(0, 0.5, 0.05));  /*********************************************************************** @@ -111,7 +111,7 @@ void usrp2_mboard_impl::rx_codec_set(const wax::obj &key_, const wax::obj &val){      switch(key.as<codec_prop_t>()) {      case CODEC_PROP_GAIN_I:      case CODEC_PROP_GAIN_Q: -        this->rx_codec_set_gain(val.as<float>(), key.name); +        this->rx_codec_set_gain(val.as<double>(), key.name);          return;      default: UHD_THROW_PROP_SET_ERROR(); @@ -122,7 +122,7 @@ void usrp2_mboard_impl::rx_codec_set(const wax::obj &key_, const wax::obj &val){   * Helper function to set RX codec gain   ***********************************************************************/ -void usrp2_mboard_impl::rx_codec_set_gain(float gain, const std::string &name){ +void usrp2_mboard_impl::rx_codec_set_gain(double gain, const std::string &name){    assert_has(codec_rx_gain_ranges.keys(), name, "codec rx gain name");    _codec_rx_gains[name] = gain; diff --git a/host/lib/usrp/usrp2/dboard_iface.cpp b/host/lib/usrp/usrp2/dboard_iface.cpp index 54c1c735c..c539b0058 100644 --- a/host/lib/usrp/usrp2/dboard_iface.cpp +++ b/host/lib/usrp/usrp2/dboard_iface.cpp @@ -1,5 +1,5 @@  // -// Copyright 2010 Ettus Research LLC +// Copyright 2010-2011 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 @@ -44,8 +44,8 @@ public:          return props;      } -    void write_aux_dac(unit_t, aux_dac_t, float); -    float read_aux_adc(unit_t, aux_adc_t); +    void write_aux_dac(unit_t, aux_dac_t, double); +    double read_aux_adc(unit_t, aux_adc_t);      void _set_pin_ctrl(unit_t, boost::uint16_t);      void _set_atr_reg(unit_t, atr_reg_t, boost::uint16_t); @@ -294,7 +294,7 @@ void usrp2_dboard_iface::_write_aux_dac(unit_t unit){      );  } -void usrp2_dboard_iface::write_aux_dac(unit_t unit, aux_dac_t which, float value){ +void usrp2_dboard_iface::write_aux_dac(unit_t unit, aux_dac_t which, double value){      _dac_regs[unit].data = boost::math::iround(4095*value/3.3);      _dac_regs[unit].cmd = ad5623_regs_t::CMD_WR_UP_DAC_CHAN_N; @@ -317,7 +317,7 @@ void usrp2_dboard_iface::write_aux_dac(unit_t unit, aux_dac_t which, float value      this->_write_aux_dac(unit);  } -float usrp2_dboard_iface::read_aux_adc(unit_t unit, aux_adc_t which){ +double usrp2_dboard_iface::read_aux_adc(unit_t unit, aux_adc_t which){      static const uhd::dict<unit_t, int> unit_to_spi_adc = map_list_of          (UNIT_RX, SPI_SS_RX_ADC)          (UNIT_TX, SPI_SS_TX_ADC) @@ -346,5 +346,5 @@ float usrp2_dboard_iface::read_aux_adc(unit_t unit, aux_adc_t which){      )));      //convert to voltage and return -    return float(3.3*ad7922_regs.result/4095); +    return 3.3*ad7922_regs.result/4095;  } diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h index a9c39e650..a22f805e1 100644 --- a/host/lib/usrp/usrp2/fw_common.h +++ b/host/lib/usrp/usrp2/fw_common.h @@ -1,5 +1,5 @@  // -// Copyright 2010 Ettus Research LLC +// Copyright 2010-2011 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 @@ -18,23 +18,20 @@  #ifndef INCLUDED_USRP2_FW_COMMON_H  #define INCLUDED_USRP2_FW_COMMON_H +#include <stdint.h> +  /*!   * Structs and constants for usrp2 communication.   * This header is shared by the firmware and host code.   * Therefore, this header may only contain valid C code.   */  #ifdef __cplusplus -    #include <boost/cstdint.hpp> -    #define __stdint(type) boost::type  extern "C" { -#else -    #include <stdint.h> -    #define __stdint(type) type  #endif  //fpga and firmware compatibility numbers -#define USRP2_FPGA_COMPAT_NUM 3 -#define USRP2_FW_COMPAT_NUM 7 +#define USRP2_FPGA_COMPAT_NUM 4 +#define USRP2_FW_COMPAT_NUM 8  //used to differentiate control packets over data port  #define USRP2_INVALID_VRT_HEADER 0 @@ -42,7 +39,9 @@ extern "C" {  // udp ports for the usrp2 communication  // Dynamic and/or private ports: 49152-65535  #define USRP2_UDP_CTRL_PORT 49152 -#define USRP2_UDP_DATA_PORT 49153 +//#define USRP2_UDP_UPDATE_PORT 49154 +#define USRP2_UDP_DATA_PORT 49156 +#define USRP2_UDP_ERR0_PORT 49157  ////////////////////////////////////////////////////////////////////////  // I2C addresses @@ -104,40 +103,38 @@ typedef enum{  } usrp2_clk_edge_t;  typedef struct{ -    __stdint(uint32_t) proto_ver; -    __stdint(uint32_t) id; -    __stdint(uint32_t) seq; +    uint32_t proto_ver; +    uint32_t id; +    uint32_t seq;      union{ -        __stdint(uint32_t) ip_addr; +        uint32_t ip_addr;          struct { -            __stdint(uint32_t) dev; -            __stdint(uint32_t) data; -            __stdint(uint8_t) miso_edge; -            __stdint(uint8_t) mosi_edge; -            __stdint(uint8_t) num_bits; -            __stdint(uint8_t) readback; +            uint32_t dev; +            uint32_t data; +            uint8_t miso_edge; +            uint8_t mosi_edge; +            uint8_t num_bits; +            uint8_t readback;          } spi_args;          struct { -            __stdint(uint8_t) addr; -            __stdint(uint8_t) bytes; -            __stdint(uint8_t) data[20]; +            uint8_t addr; +            uint8_t bytes; +            uint8_t data[20];          } i2c_args;          struct { -            __stdint(uint32_t) addr; -            __stdint(uint32_t) data; -            __stdint(uint32_t) addrhi; -            __stdint(uint32_t) datahi; -            __stdint(uint8_t) num_bytes; //1, 2, 4, 8 +            uint32_t addr; +            uint32_t data; +            uint32_t _pad[2]; +            uint8_t num_bytes; //1, 2, 4          } poke_args;          struct { -            __stdint(uint8_t) dev; -            __stdint(uint8_t) bytes; -            __stdint(uint8_t) data[20]; +            uint8_t dev; +            uint8_t bytes; +            uint8_t data[20];          } uart_args;      } data;  } usrp2_ctrl_data_t; -#undef __stdint  #ifdef __cplusplus  }  #endif diff --git a/host/lib/usrp/usrp2/gps_ctrl.hpp b/host/lib/usrp/usrp2/gps_ctrl.hpp deleted file mode 100644 index 5936a6fb6..000000000 --- a/host/lib/usrp/usrp2/gps_ctrl.hpp +++ /dev/null @@ -1,53 +0,0 @@ -// -// Copyright 2010 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program.  If not, see <http://www.gnu.org/licenses/>. -// - -#ifndef INCLUDED_GPS_CTRL_HPP -#define INCLUDED_GPS_CTRL_HPP - -#include "usrp2_iface.hpp" -#include <boost/shared_ptr.hpp> -#include <boost/utility.hpp> -#include <boost/date_time/posix_time/posix_time_types.hpp> - -using namespace boost::posix_time; - -class usrp2_gps_ctrl : boost::noncopyable{ -public: -  typedef boost::shared_ptr<usrp2_gps_ctrl> sptr; - -  /*! -   * Make a GPS config for Jackson Labs or generic NMEA GPS devices -   */ -  static sptr make(usrp2_iface::sptr iface); - -  /*! -   * Get the current GPS time and date -   * \return current GPS time and date as boost::posix_time::ptime object -   */ -  virtual ptime get_time(void) = 0; - -  /*! -   * Tell you if there's a supported GPS connected or not -   * \return true if a supported GPS is connected -   */ -  virtual bool gps_detected(void) = 0; - -  //TODO: other fun things you can do with a GPS. - -}; - -#endif /* INCLUDED_CLOCK_CTRL_HPP */ diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index cbc0a0817..30eaecae2 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -1,5 +1,5 @@  // -// Copyright 2010 Ettus Research LLC +// Copyright 2010-2011 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 @@ -20,12 +20,13 @@  #include "usrp2_regs.hpp"  #include <uhd/utils/byteswap.hpp>  #include <uhd/utils/thread_priority.hpp> -#include <uhd/transport/convert_types.hpp> -#include <uhd/transport/alignment_buffer.hpp> +#include <uhd/transport/bounded_buffer.hpp>  #include <boost/format.hpp>  #include <boost/bind.hpp>  #include <boost/thread.hpp> +#include <boost/date_time/posix_time/posix_time_types.hpp>  #include <iostream> +#include <list>  using namespace uhd;  using namespace uhd::usrp; @@ -108,16 +109,24 @@ private:   * - vrt packet handler states   **********************************************************************/  struct usrp2_impl::io_impl{ -    typedef alignment_buffer<managed_recv_buffer::sptr, time_spec_t> alignment_buffer_type; -    io_impl(size_t num_recv_frames, size_t send_frame_size, size_t width): +    io_impl(size_t send_frame_size, size_t width):          packet_handler_recv_state(width), -        recv_pirate_booty(alignment_buffer_type::make(num_recv_frames-3, width)),          async_msg_fifo(bounded_buffer<async_metadata_t>::make(100/*messages deep*/))      { -        for (size_t i = 0; i < width; i++) fc_mons.push_back( -            flow_control_monitor::sptr(new flow_control_monitor(usrp2_impl::sram_bytes/send_frame_size)) -        ); +        for (size_t i = 0; i < width; i++){ +            fc_mons.push_back(flow_control_monitor::sptr( +                new flow_control_monitor(usrp2_impl::sram_bytes/send_frame_size) +            )); +            //init empty packet infos +            vrt::if_packet_info_t packet_info; +            packet_info.packet_count = 0xf; +            packet_info.has_tsi = true; +            packet_info.tsi = 0; +            packet_info.has_tsf = true; +            packet_info.tsf = 0; +            prev_infos.push_back(packet_info); +        }      }      ~io_impl(void){ @@ -126,11 +135,6 @@ struct usrp2_impl::io_impl{          recv_pirate_crew.join_all();      } -    bool get_recv_buffs(vrt_packet_handler::managed_recv_buffs_t &buffs, double timeout){ -        boost::this_thread::disable_interruption di; //disable because the wait can throw -        return recv_pirate_booty->pop_elems_with_timed_wait(buffs, timeout); -    } -      bool get_send_buffs(          const std::vector<zero_copy_if::sptr> &trans,          vrt_packet_handler::managed_send_buffs_t &buffs, @@ -151,6 +155,15 @@ struct usrp2_impl::io_impl{          return true;      } +    bool get_recv_buffs( +        const std::vector<zero_copy_if::sptr> &xports, +        vrt_packet_handler::managed_recv_buffs_t &buffs, +        double timeout +    ); + +    //previous state for each buffer +    std::vector<vrt::if_packet_info_t> prev_infos; +      //flow control monitors      std::vector<flow_control_monitor::sptr> fc_mons; @@ -162,29 +175,28 @@ struct usrp2_impl::io_impl{      void recv_pirate_loop(zero_copy_if::sptr, usrp2_mboard_impl::sptr, size_t);      boost::thread_group recv_pirate_crew;      bool recv_pirate_crew_raiding; -    alignment_buffer_type::sptr recv_pirate_booty;      bounded_buffer<async_metadata_t>::sptr async_msg_fifo;      boost::mutex spawn_mutex;  };  /***********************************************************************   * Receive Pirate Loop - * - while raiding, loot for recv buffers - * - put booty into the alignment buffer + * - while raiding, loot for message packet + * - update flow control condition count + * - put async message packets into queue   **********************************************************************/  void usrp2_impl::io_impl::recv_pirate_loop( -    zero_copy_if::sptr zc_if, +    zero_copy_if::sptr zc_if_err0,      usrp2_mboard_impl::sptr mboard,      size_t index  ){      set_thread_priority_safe();      recv_pirate_crew_raiding = true; -    size_t next_packet_seq = 0;      spawn_mutex.unlock();      while(recv_pirate_crew_raiding){ -        managed_recv_buffer::sptr buff = zc_if->get_recv_buff(); +        managed_recv_buffer::sptr buff = zc_if_err0->get_recv_buff();          if (not buff.get()) continue; //ignore timeout/error buffers          try{ @@ -194,26 +206,6 @@ void usrp2_impl::io_impl::recv_pirate_loop(              const boost::uint32_t *vrt_hdr = buff->cast<const boost::uint32_t *>();              vrt::if_hdr_unpack_be(vrt_hdr, if_packet_info); -            //handle the rx data stream -            if (if_packet_info.sid == usrp2_impl::RECV_SID){ -                //handle the packet count / sequence number -                if (if_packet_info.packet_count != next_packet_seq){ -                    //std::cerr << "S" << (if_packet_info.packet_count - next_packet_seq)%16; -                    std::cerr << "O" << std::flush; //report overflow (drops in the kernel) -                } -                next_packet_seq = (if_packet_info.packet_count+1)%16; - -                //extract the timespec and round to the nearest packet -                UHD_ASSERT_THROW(if_packet_info.has_tsi and if_packet_info.has_tsf); -                time_spec_t time( -                    time_t(if_packet_info.tsi), size_t(if_packet_info.tsf), mboard->get_master_clock_freq() -                ); - -                //push the packet into the buffer with the new time -                recv_pirate_booty->push_with_pop_on_full(buff, time, index); -                continue; -            } -              //handle a tx async report message              if (if_packet_info.sid == usrp2_impl::ASYNC_SID and if_packet_info.packet_type != vrt::if_packet_info_t::PACKET_TYPE_DATA){ @@ -253,21 +245,10 @@ void usrp2_impl::io_impl::recv_pirate_loop(  void usrp2_impl::io_init(void){      //the assumption is that all data transports should be identical -    const size_t num_recv_frames = _data_transports.front()->get_num_recv_frames();      const size_t send_frame_size = _data_transports.front()->get_send_frame_size();      //create new io impl -    _io_impl = UHD_PIMPL_MAKE(io_impl, (num_recv_frames, send_frame_size, _data_transports.size())); - -    //TODO temporary fix for weird power up state, remove when FPGA fixed -    { -        //send an initial packet to all transports -        tx_metadata_t md; md.end_of_burst = true; -        this->send( -            std::vector<const void *>(_data_transports.size(), NULL), 0, md, -            io_type_t::COMPLEX_FLOAT32, device::SEND_MODE_ONE_PACKET, 0 -        ); -    } +    _io_impl = UHD_PIMPL_MAKE(io_impl, (send_frame_size, _data_transports.size()));      //create a new pirate thread for each zc if (yarr!!)      for (size_t i = 0; i < _data_transports.size(); i++){ @@ -276,7 +257,7 @@ void usrp2_impl::io_init(void){          //spawn a new pirate to plunder the recv booty          _io_impl->recv_pirate_crew.create_thread(boost::bind(              &usrp2_impl::io_impl::recv_pirate_loop, -            _io_impl.get(), _data_transports.at(i), +            _io_impl.get(), _err0_transports.at(i),              _mboards.at(i), i          ));          //block here until the spawned thread unlocks @@ -328,6 +309,133 @@ size_t usrp2_impl::send(  }  /*********************************************************************** + * Alignment logic on receive + **********************************************************************/ +static UHD_INLINE boost::posix_time::time_duration to_time_dur(double timeout){ +    return boost::posix_time::microseconds(long(timeout*1e6)); +} + +static UHD_INLINE double from_time_dur(const boost::posix_time::time_duration &time_dur){ +    return 1e-6*time_dur.total_microseconds(); +} + +static UHD_INLINE time_spec_t extract_time_spec( +    const vrt::if_packet_info_t &packet_info +){ +    return time_spec_t( //assumes has_tsi and has_tsf are true +        time_t(packet_info.tsi), size_t(packet_info.tsf), +        100e6 //tick rate does not have to be correct for comparison purposes +    ); +} + +static UHD_INLINE void extract_packet_info( +    managed_recv_buffer::sptr &buff, +    vrt::if_packet_info_t &prev_info, +    time_spec_t &time, bool &clear, bool &msg +){ +    //extract packet info +    vrt::if_packet_info_t next_info; +    next_info.num_packet_words32 = buff->size()/sizeof(boost::uint32_t); +    vrt::if_hdr_unpack_be(buff->cast<const boost::uint32_t *>(), next_info); + +    //handle the packet count / sequence number +    if ((prev_info.packet_count+1)%16 != next_info.packet_count){ +        std::cerr << "O" << std::flush; //report overflow (drops in the kernel) +    } + +    time = extract_time_spec(next_info); +    clear = extract_time_spec(prev_info) > time; +    msg = next_info.packet_type != vrt::if_packet_info_t::PACKET_TYPE_DATA; +    prev_info = next_info; +} + +static UHD_INLINE bool handle_msg_packet( +    vrt_packet_handler::managed_recv_buffs_t &buffs, size_t index +){ +    for (size_t i = 0; i < buffs.size(); i++){ +        if (i == index) continue; +        buffs[i].reset(); //set NULL +    } +    return true; +} + +UHD_INLINE bool usrp2_impl::io_impl::get_recv_buffs( +    const std::vector<zero_copy_if::sptr> &xports, +    vrt_packet_handler::managed_recv_buffs_t &buffs, +    double timeout +){ +    if (buffs.size() == 1){ +        buffs[0] = xports[0]->get_recv_buff(timeout); +        if (buffs[0].get() == NULL) return false; +        bool clear, msg; time_spec_t time; //unused variables +        //call extract_packet_info to handle printing the overflows +        extract_packet_info(buffs[0], this->prev_infos[0], time, clear, msg); +        return true; +    } +    //-------------------- begin alignment logic ---------------------// +    boost::system_time exit_time = boost::get_system_time() + to_time_dur(timeout); +    managed_recv_buffer::sptr buff_tmp; +    std::list<size_t> _all_indexes, indexes_to_do; +    for (size_t i = 0; i < buffs.size(); i++) _all_indexes.push_back(i); +    bool clear, msg; +    time_spec_t expected_time; + +    //respond to a clear by starting from scratch +    got_clear: +    indexes_to_do = _all_indexes; +    clear = false; + +    //do an initial pop to load an initial sequence id +    size_t index = indexes_to_do.front(); +    buff_tmp = xports[index]->get_recv_buff(from_time_dur(exit_time - boost::get_system_time())); +    if (buff_tmp.get() == NULL) return false; +    extract_packet_info(buff_tmp, this->prev_infos[index], expected_time, clear, msg); +    if (clear) goto got_clear; +    buffs[index] = buff_tmp; +    if (msg) return handle_msg_packet(buffs, index); +    indexes_to_do.pop_front(); + +    //get an aligned set of elements from the buffers: +    while(indexes_to_do.size() != 0){ + +        //pop an element off for this index +        index = indexes_to_do.front(); +        buff_tmp = xports[index]->get_recv_buff(from_time_dur(exit_time - boost::get_system_time())); +        if (buff_tmp.get() == NULL) return false; +        time_spec_t this_time; +        extract_packet_info(buff_tmp, this->prev_infos[index], this_time, clear, msg); +        if (clear) goto got_clear; +        buffs[index] = buff_tmp; +        if (msg) return handle_msg_packet(buffs, index); + +        //if the sequence id matches: +        //  remove this index from the list and continue +        if (this_time == expected_time){ +            indexes_to_do.pop_front(); +            continue; +        } + +        //if the sequence id is older: +        //  continue with the same index to try again +        else if (this_time < expected_time){ +            continue; +        } + +        //if the sequence id is newer: +        //  use the new expected time for comparison +        //  add all other indexes back into the list +        else{ +            expected_time = this_time; +            indexes_to_do = _all_indexes; +            indexes_to_do.remove(index); +            continue; +        } +    } +    return true; +    //-------------------- end alignment logic -----------------------// +} + +/***********************************************************************   * Receive Data   **********************************************************************/  size_t usrp2_impl::get_max_recv_samps_per_packet(void) const{ @@ -357,7 +465,7 @@ size_t usrp2_impl::recv(          io_type, _rx_otw_type,                     //input and output types to convert          _mboards.front()->get_master_clock_freq(), //master clock tick rate          uhd::transport::vrt::if_hdr_unpack_be, -        boost::bind(&usrp2_impl::io_impl::get_recv_buffs, _io_impl.get(), _1, timeout), +        boost::bind(&usrp2_impl::io_impl::get_recv_buffs, _io_impl.get(), _data_transports, _1, timeout),          boost::bind(&handle_overflow, _mboards, _1)      );  } diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index 766ea993c..95f7013e7 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -1,5 +1,5 @@  // -// Copyright 2010 Ettus Research LLC +// Copyright 2010-2011 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 @@ -17,6 +17,7 @@  #include "usrp2_impl.hpp"  #include "usrp2_regs.hpp" +#include <uhd/usrp/gps_ctrl.hpp>  #include <uhd/usrp/misc_utils.hpp>  #include <uhd/usrp/dsp_utils.hpp>  #include <uhd/usrp/mboard_props.hpp> @@ -25,11 +26,13 @@  #include <uhd/utils/algorithm.hpp>  #include <boost/bind.hpp>  #include <iostream> -#include <boost/date_time/posix_time/posix_time.hpp> + +static const double mimo_clock_delay_usrp2_rev4 = 4.18e-9; +static const double mimo_clock_delay_usrp_n2xx = 3.55e-9; +static const size_t mimo_clock_sync_delay_cycles = 137;  using namespace uhd;  using namespace uhd::usrp; -using namespace boost::posix_time;  /***********************************************************************   * Structors @@ -38,8 +41,9 @@ usrp2_mboard_impl::usrp2_mboard_impl(      size_t index,      transport::udp_simple::sptr ctrl_transport,      transport::zero_copy_if::sptr data_transport, -    size_t recv_samps_per_packet, -    const device_addr_t &flow_control_hints +    transport::zero_copy_if::sptr err0_transport, +    const device_addr_t &device_args, +    size_t recv_samps_per_packet  ):      _index(index),      _iface(usrp2_iface::make(ctrl_transport)) @@ -47,19 +51,24 @@ usrp2_mboard_impl::usrp2_mboard_impl(      //Send a small data packet so the usrp2 knows the udp source port.      //This setup must happen before further initialization occurs      //or the async update packets will cause ICMP destination unreachable. -    transport::managed_send_buffer::sptr send_buff = data_transport->get_send_buff(); +    transport::managed_send_buffer::sptr send_buff;      static const boost::uint32_t data[2] = {          uhd::htonx(boost::uint32_t(0 /* don't care seq num */)),          uhd::htonx(boost::uint32_t(USRP2_INVALID_VRT_HEADER))      }; +    send_buff = data_transport->get_send_buff(); +    std::memcpy(send_buff->cast<void*>(), &data, sizeof(data)); +    send_buff->commit(sizeof(data)); +    send_buff = err0_transport->get_send_buff();      std::memcpy(send_buff->cast<void*>(), &data, sizeof(data));      send_buff->commit(sizeof(data));      //contruct the interfaces to mboard perifs      _clock_ctrl = usrp2_clock_ctrl::make(_iface);      _codec_ctrl = usrp2_codec_ctrl::make(_iface); -    _serdes_ctrl = usrp2_serdes_ctrl::make(_iface); -    //_gps_ctrl = usrp2_gps_ctrl::make(_iface); +    //_gps_ctrl = gps_ctrl::make( +    //    _iface->get_gps_write_fn(), +    //    _iface->get_gps_read_fn());      //if(_gps_ctrl->gps_detected()) std::cout << "GPS time: " << _gps_ctrl->get_time() << std::endl; @@ -98,14 +107,14 @@ usrp2_mboard_impl::usrp2_mboard_impl(      _iface->poke32(_iface->regs.tx_ctrl_policy, U2_FLAG_TX_CTRL_POLICY_NEXT_PACKET);      //setting the cycles per update (disabled by default) -    const double ups_per_sec = flow_control_hints.cast<double>("ups_per_sec", 0.0); +    const double ups_per_sec = device_args.cast<double>("ups_per_sec", 0.0);      if (ups_per_sec > 0.0){          const size_t cycles_per_up = size_t(_clock_ctrl->get_master_clock_rate()/ups_per_sec);          _iface->poke32(_iface->regs.tx_ctrl_cycles_per_up, U2_FLAG_TX_CTRL_UP_ENB | cycles_per_up);      }      //setting the packets per update (enabled by default) -    const double ups_per_fifo = flow_control_hints.cast<double>("ups_per_fifo", 8.0); +    const double ups_per_fifo = device_args.cast<double>("ups_per_fifo", 8.0);      if (ups_per_fifo > 0.0){          const size_t packets_per_up = size_t(usrp2_impl::sram_bytes/ups_per_fifo/data_transport->get_send_frame_size());          _iface->poke32(_iface->regs.tx_ctrl_packets_per_up, U2_FLAG_TX_CTRL_UP_ENB | packets_per_up); @@ -118,7 +127,26 @@ usrp2_mboard_impl::usrp2_mboard_impl(      init_duc_config();      //initialize the clock configuration -    init_clock_config(); +    if (device_args.has_key("mimo_mode")){ +        if (device_args["mimo_mode"] == "master"){ +            _mimo_clocking_mode_is_master = true; +        } +        else if (device_args["mimo_mode"] == "slave"){ +            _mimo_clocking_mode_is_master = false; +        } +        else throw std::runtime_error( +            "mimo_mode must be set to master or slave" +        ); +    } +    else { +        _mimo_clocking_mode_is_master = (_iface->peek32(_iface->regs.status) & (1 << 8)) != 0; +    } +    std::cout << boost::format("mboard%d MIMO %s") % _index % +        (_mimo_clocking_mode_is_master?"master":"slave") << std::endl; + +    //init the clock config +    _clock_config = clock_config_t::internal(); +    update_clock_config();      //init the codec before the dboard      codec_init(); @@ -139,23 +167,12 @@ usrp2_mboard_impl::~usrp2_mboard_impl(void){  /***********************************************************************   * Helper Methods   **********************************************************************/ -void usrp2_mboard_impl::init_clock_config(void){ -    //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(); -} -  void usrp2_mboard_impl::update_clock_config(void){      boost::uint32_t pps_flags = 0;      //translate pps source enums      switch(_clock_config.pps_source){      case clock_config_t::PPS_SMA:  pps_flags |= U2_FLAG_TIME64_PPS_SMA;  break; -    case clock_config_t::PPS_MIMO: pps_flags |= U2_FLAG_TIME64_PPS_MIMO; break;      default: throw std::runtime_error("unhandled clock configuration pps source");      } @@ -176,7 +193,6 @@ void usrp2_mboard_impl::update_clock_config(void){          switch(_clock_config.ref_source){          case clock_config_t::REF_INT : _iface->poke32(_iface->regs.misc_ctrl_clock, 0x12); break;          case clock_config_t::REF_SMA : _iface->poke32(_iface->regs.misc_ctrl_clock, 0x1C); break; -        case clock_config_t::REF_MIMO: _iface->poke32(_iface->regs.misc_ctrl_clock, 0x15); break;          default: throw std::runtime_error("unhandled clock configuration reference source");          }          _clock_ctrl->enable_external_ref(true); //USRP2P has an internal 10MHz TCXO @@ -187,7 +203,6 @@ void usrp2_mboard_impl::update_clock_config(void){          switch(_clock_config.ref_source){          case clock_config_t::REF_INT : _iface->poke32(_iface->regs.misc_ctrl_clock, 0x10); break;          case clock_config_t::REF_SMA : _iface->poke32(_iface->regs.misc_ctrl_clock, 0x1C); break; -        case clock_config_t::REF_MIMO: _iface->poke32(_iface->regs.misc_ctrl_clock, 0x15); break;          default: throw std::runtime_error("unhandled clock configuration reference source");          }          _clock_ctrl->enable_external_ref(_clock_config.ref_source != clock_config_t::REF_INT); @@ -195,6 +210,36 @@ void usrp2_mboard_impl::update_clock_config(void){      case usrp2_iface::USRP_NXXX: break;      } + +    //Handle the serdes clocking based on master/slave mode: +    //   - Masters always drive the clock over serdes. +    //   - Slaves always lock to this serdes clock. +    //   - Slaves lock their time over the serdes. +    if (_mimo_clocking_mode_is_master){ +        _clock_ctrl->enable_mimo_clock_out(true); +        switch(_iface->get_rev()){ +        case usrp2_iface::USRP_N200: +        case usrp2_iface::USRP_N210: +            _clock_ctrl->set_mimo_clock_delay(mimo_clock_delay_usrp_n2xx); +            break; + +        case usrp2_iface::USRP2_REV4: +            _clock_ctrl->set_mimo_clock_delay(mimo_clock_delay_usrp2_rev4); +            break; + +        default: break; //not handled +        } +        _iface->poke32(_iface->regs.time64_mimo_sync, 0); +    } +    else{ +        _iface->poke32(_iface->regs.misc_ctrl_clock, 0x15); +        _clock_ctrl->enable_external_ref(true); +        _clock_ctrl->enable_mimo_clock_out(false); +        _iface->poke32(_iface->regs.time64_mimo_sync, +            (1 << 8) | (mimo_clock_sync_delay_cycles & 0xff) +        ); +    } +  }  void usrp2_mboard_impl::set_time_spec(const time_spec_t &time_spec, bool now){ @@ -279,15 +324,21 @@ void usrp2_mboard_impl::get(const wax::obj &key_, wax::obj &val){          val = _clock_config;          return; -    case MBOARD_PROP_TIME_NOW:{ -            usrp2_iface::pair64 time64( -                _iface->peek64(_iface->regs.time64_secs_rb, _iface->regs.time64_ticks_rb) -            ); -            val = time_spec_t( -                time64.first, time64.second, get_master_clock_freq() -            ); -        } +    case MBOARD_PROP_TIME_NOW: while(true){ +        uint32_t secs = _iface->peek32(_iface->regs.time64_secs_rb_imm); +        uint32_t ticks = _iface->peek32(_iface->regs.time64_ticks_rb_imm); +        if (secs != _iface->peek32(_iface->regs.time64_secs_rb_imm)) continue; +        val = time_spec_t(secs, ticks, get_master_clock_freq());          return; +    } + +    case MBOARD_PROP_TIME_PPS: while(true){ +        uint32_t secs = _iface->peek32(_iface->regs.time64_secs_rb_pps); +        uint32_t ticks = _iface->peek32(_iface->regs.time64_ticks_rb_pps); +        if (secs != _iface->peek32(_iface->regs.time64_secs_rb_pps)) continue; +        val = time_spec_t(secs, ticks, get_master_clock_freq()); +        return; +    }      case MBOARD_PROP_RX_SUBDEV_SPEC:          val = _rx_subdev_spec; @@ -321,7 +372,7 @@ void usrp2_mboard_impl::set(const wax::obj &key, const wax::obj &val){          set_time_spec(val.as<time_spec_t>(), true);          return; -    case MBOARD_PROP_TIME_NEXT_PPS: +    case MBOARD_PROP_TIME_PPS:          set_time_spec(val.as<time_spec_t>(), false);          return; diff --git a/host/lib/usrp/usrp2/serdes_ctrl.cpp b/host/lib/usrp/usrp2/serdes_ctrl.cpp deleted file mode 100644 index 1cda22f45..000000000 --- a/host/lib/usrp/usrp2/serdes_ctrl.cpp +++ /dev/null @@ -1,46 +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 "serdes_ctrl.hpp" -#include "usrp2_regs.hpp" - -using namespace uhd; - -/*! - * A usrp2 serdes control implementation - */ -class usrp2_serdes_ctrl_impl : public usrp2_serdes_ctrl{ -public: -    usrp2_serdes_ctrl_impl(usrp2_iface::sptr iface){ -        _iface = iface; -        _iface->poke32(_iface->regs.misc_ctrl_serdes, U2_FLAG_MISC_CTRL_SERDES_ENABLE | U2_FLAG_MISC_CTRL_SERDES_RXEN); -    } - -    ~usrp2_serdes_ctrl_impl(void){ -        _iface->poke32(_iface->regs.misc_ctrl_serdes, 0); //power-down -    } - -private: -    usrp2_iface::sptr _iface; -}; - -/*********************************************************************** - * Public make function for the usrp2 serdes control - **********************************************************************/ -usrp2_serdes_ctrl::sptr usrp2_serdes_ctrl::make(usrp2_iface::sptr iface){ -    return sptr(new usrp2_serdes_ctrl_impl(iface)); -} diff --git a/host/lib/usrp/usrp2/serdes_ctrl.hpp b/host/lib/usrp/usrp2/serdes_ctrl.hpp deleted file mode 100644 index 3c909c531..000000000 --- a/host/lib/usrp/usrp2/serdes_ctrl.hpp +++ /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/>. -// - -#ifndef INCLUDED_SERDES_CTRL_HPP -#define INCLUDED_SERDES_CTRL_HPP - -#include "usrp2_iface.hpp" -#include <boost/shared_ptr.hpp> -#include <boost/utility.hpp> - -class usrp2_serdes_ctrl : boost::noncopyable{ -public: -    typedef boost::shared_ptr<usrp2_serdes_ctrl> sptr; - -    /*! -     * Make a serdes control object for the usrp2 serdes port. -     * \param _iface a pointer to the usrp2 interface object -     * \return a new serdes control object -     */ -    static sptr make(usrp2_iface::sptr iface); - -    //TODO fill me in with virtual methods - -}; - -#endif /* INCLUDED_SERDES_CTRL_HPP */ diff --git a/host/lib/usrp/usrp2/usrp2_iface.cpp b/host/lib/usrp/usrp2/usrp2_iface.cpp index ffbe8eedb..149c5011f 100644 --- a/host/lib/usrp/usrp2/usrp2_iface.cpp +++ b/host/lib/usrp/usrp2/usrp2_iface.cpp @@ -93,20 +93,6 @@ public:          return this->peek<boost::uint16_t>(addr);      } -    pair64 peek64(boost::uint32_t addrlo, boost::uint32_t addrhi){ -        //setup the out data -        usrp2_ctrl_data_t out_data; -        out_data.id = htonl(USRP2_CTRL_ID_PEEK_AT_THIS_REGISTER_FOR_ME_BRO); -        out_data.data.poke_args.addr = htonl(addrlo); -        out_data.data.poke_args.addrhi = htonl(addrhi); -        out_data.data.poke_args.num_bytes = sizeof(boost::uint64_t); - -        //send and recv -        usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data); -        UHD_ASSERT_THROW(ntohl(in_data.id) == USRP2_CTRL_ID_WOAH_I_DEFINITELY_PEEKED_IT_DUDE); -        return pair64(ntohl(in_data.data.poke_args.data), ntohl(in_data.data.poke_args.datahi)); -    } -  /***********************************************************************   * SPI   **********************************************************************/ @@ -232,6 +218,14 @@ public:        }        return result;      } +     +    gps_send_fn_t get_gps_write_fn(void) { +        return boost::bind(&usrp2_iface_impl::write_uart, this, 2, _1); //2 is the GPS UART port on USRP2 +    } +     +    gps_recv_fn_t get_gps_read_fn(void) { +        return boost::bind(&usrp2_iface_impl::read_uart, this, 2); //2 is the GPS UART port on USRP2 +    }  /***********************************************************************   * Send/Recv over control diff --git a/host/lib/usrp/usrp2/usrp2_iface.hpp b/host/lib/usrp/usrp2/usrp2_iface.hpp index af3ed6c9f..49cb0e6dc 100644 --- a/host/lib/usrp/usrp2/usrp2_iface.hpp +++ b/host/lib/usrp/usrp2/usrp2_iface.hpp @@ -24,11 +24,17 @@  #include <boost/shared_ptr.hpp>  #include <boost/utility.hpp>  #include <boost/cstdint.hpp> +#include <boost/function.hpp>  #include <utility>  #include <string>  #include "fw_common.h"  #include "usrp2_regs.hpp" + +//TODO: kill this crap when you have the top level GPS include file +typedef boost::function<void(std::string)> gps_send_fn_t; +typedef boost::function<std::string(void)> gps_recv_fn_t; +  /*!   * The usrp2 interface class:   * Provides a set of functions to implementation layer. @@ -37,7 +43,6 @@  class usrp2_iface : public uhd::i2c_iface, boost::noncopyable{  public:      typedef boost::shared_ptr<usrp2_iface> sptr; -    typedef std::pair<boost::uint32_t, boost::uint32_t> pair64;      /*!       * Make a new usrp2 interface with the control transport. @@ -54,14 +59,6 @@ public:      virtual usrp2_ctrl_data_t ctrl_send_and_recv(const usrp2_ctrl_data_t &data) = 0;      /*! -     * Read a dual register (64 bits) -     * \param addrlo the address for the low-32 bits -     * \param addrhi the address for the high-32 bits -     * \return a pair of 32 bit integers lo, hi -     */ -    virtual pair64 peek64(boost::uint32_t addrlo, boost::uint32_t addrhi) = 0; - -    /*!       * Write a register (32 bits)       * \param addr the address       * \param data the 32bit data @@ -109,6 +106,9 @@ public:      virtual void write_uart(boost::uint8_t dev, const std::string &buf) = 0;      virtual std::string read_uart(boost::uint8_t dev) = 0; +     +    virtual gps_recv_fn_t get_gps_read_fn(void) = 0; +    virtual gps_send_fn_t get_gps_write_fn(void) = 0;      //! The list of possible revision types      enum rev_type { diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index c3bbe4d65..059ddf65f 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -1,5 +1,5 @@  // -// Copyright 2010 Ettus Research LLC +// Copyright 2010-2011 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 @@ -22,7 +22,7 @@  #include <uhd/utils/assert.hpp>  #include <uhd/utils/static.hpp>  #include <uhd/utils/warning.hpp> -#include <uhd/utils/algorithm.hpp> +#include <boost/algorithm/string.hpp> //for split  #include <boost/assign/list_of.hpp>  #include <boost/format.hpp>  #include <boost/foreach.hpp> @@ -31,6 +31,7 @@  #include <boost/bind.hpp>  #include <boost/asio.hpp> //htonl and ntohl  #include <iostream> +#include <vector>  using namespace uhd;  using namespace uhd::usrp; @@ -47,8 +48,8 @@ template <class T> std::string num2str(T num){  //! separate indexed device addresses into a vector of device addresses  device_addrs_t sep_indexed_dev_addrs(const device_addr_t &dev_addr){      //------------ support old deprecated way and print warning -------- -    if (dev_addr.has_key("addr")){ -        std::vector<std::string> addrs = std::split_string(dev_addr["addr"]); +    if (dev_addr.has_key("addr") and not dev_addr["addr"].empty()){ +        std::vector<std::string> addrs; boost::split(addrs, dev_addr["addr"], boost::is_any_of(" "));          if (addrs.size() > 1){              device_addr_t fixed_dev_addr = dev_addr;              fixed_dev_addr.pop("addr"); @@ -197,24 +198,36 @@ static device_addrs_t usrp2_find(const device_addr_t &hint_){   * Make   **********************************************************************/  static device::sptr usrp2_make(const device_addr_t &device_addr){ -sep_indexed_dev_addrs(device_addr); + +    //setup the dsp transport hints (default to a large recv buff) +    device_addr_t dsp_xport_hints = device_addr; +    if (not dsp_xport_hints.has_key("recv_buff_size")){ +        //set to half-a-second of buffering at max rate +        dsp_xport_hints["recv_buff_size"] = "50e6"; +    } +      //create a ctrl and data transport for each address      std::vector<udp_simple::sptr> ctrl_transports;      std::vector<zero_copy_if::sptr> data_transports; +    std::vector<zero_copy_if::sptr> err0_transports; +    const device_addrs_t device_addrs = sep_indexed_dev_addrs(device_addr); -    BOOST_FOREACH(const device_addr_t &dev_addr_i, sep_indexed_dev_addrs(device_addr)){ +    BOOST_FOREACH(const device_addr_t &dev_addr_i, device_addrs){          ctrl_transports.push_back(udp_simple::make_connected(              dev_addr_i["addr"], num2str(USRP2_UDP_CTRL_PORT)          ));          data_transports.push_back(udp_zero_copy::make( -            dev_addr_i["addr"], num2str(USRP2_UDP_DATA_PORT), device_addr +            dev_addr_i["addr"], num2str(USRP2_UDP_DATA_PORT), dsp_xport_hints +        )); +        err0_transports.push_back(udp_zero_copy::make( +            dev_addr_i["addr"], num2str(USRP2_UDP_ERR0_PORT), device_addr_t()          ));      }      //create the usrp2 implementation guts -    return device::sptr( -        new usrp2_impl(ctrl_transports, data_transports, device_addr) -    ); +    return device::sptr(new usrp2_impl( +        ctrl_transports, data_transports, err0_transports, device_addrs +    ));  }  UHD_STATIC_BLOCK(register_usrp2_device){ @@ -227,9 +240,11 @@ UHD_STATIC_BLOCK(register_usrp2_device){  usrp2_impl::usrp2_impl(      std::vector<udp_simple::sptr> ctrl_transports,      std::vector<zero_copy_if::sptr> data_transports, -    const device_addr_t &flow_control_hints +    std::vector<zero_copy_if::sptr> err0_transports, +    const device_addrs_t &device_args  ): -    _data_transports(data_transports) +    _data_transports(data_transports), +    _err0_transports(err0_transports)  {      //setup rx otw type      _rx_otw_type.width = 16; @@ -244,11 +259,11 @@ usrp2_impl::usrp2_impl(      //!!!!! set the otw type here before continuing, its used below      //create a new mboard handler for each control transport -    for(size_t i = 0; i < ctrl_transports.size(); i++){ +    for(size_t i = 0; i < device_args.size(); i++){          _mboards.push_back(usrp2_mboard_impl::sptr(new usrp2_mboard_impl(              i, ctrl_transports[i], data_transports[i], -            this->get_max_recv_samps_per_packet(), -            flow_control_hints +            err0_transports[i], device_args[i], +            this->get_max_recv_samps_per_packet()          )));          //use an empty name when there is only one mboard          std::string name = (ctrl_transports.size() > 1)? boost::lexical_cast<std::string>(i) : ""; diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index aa8eb0155..ad95b2a4a 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -1,5 +1,5 @@  // -// Copyright 2010 Ettus Research LLC +// Copyright 2010-2011 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 @@ -21,8 +21,7 @@  #include "usrp2_iface.hpp"  #include "clock_ctrl.hpp"  #include "codec_ctrl.hpp" -#include "gps_ctrl.hpp" -#include "serdes_ctrl.hpp" +#include <uhd/usrp/gps_ctrl.hpp>  #include <uhd/device.hpp>  #include <uhd/utils/pimpl.hpp>  #include <uhd/types/dict.hpp> @@ -86,8 +85,9 @@ public:          size_t index,          uhd::transport::udp_simple::sptr,          uhd::transport::zero_copy_if::sptr, -        size_t recv_samps_per_packet, -        const uhd::device_addr_t &flow_control_hints +        uhd::transport::zero_copy_if::sptr, +        const uhd::device_addr_t &device_args, +        size_t recv_samps_per_packet      );      ~usrp2_mboard_impl(void); @@ -100,13 +100,13 @@ public:  private:      size_t _index;      bool _continuous_streaming; +    bool _mimo_clocking_mode_is_master;      //interfaces      usrp2_iface::sptr _iface;      usrp2_clock_ctrl::sptr _clock_ctrl;      usrp2_codec_ctrl::sptr _codec_ctrl; -    usrp2_serdes_ctrl::sptr _serdes_ctrl; -    usrp2_gps_ctrl::sptr _gps_ctrl; +    gps_ctrl::sptr _gps_ctrl;      //properties for this mboard      void get(const wax::obj &, wax::obj &); @@ -120,7 +120,6 @@ private:      //methods and shadows for clock configuration      uhd::clock_config_t _clock_config; -    void init_clock_config(void);      void update_clock_config(void);      void set_time_spec(const uhd::time_spec_t &time_spec, bool now); @@ -133,8 +132,8 @@ private:      wax_obj_proxy::sptr _rx_codec_proxy;      wax_obj_proxy::sptr _tx_codec_proxy; -    void rx_codec_set_gain(float, const std::string &); -    uhd::dict<std::string, float> _codec_rx_gains; +    void rx_codec_set_gain(double, const std::string &); +    uhd::dict<std::string, double> _codec_rx_gains;      //properties interface for rx dboard      void rx_dboard_get(const wax::obj &, wax::obj &); @@ -187,12 +186,14 @@ public:       * Create a new usrp2 impl base.       * \param ctrl_transports the udp transports for control       * \param data_transports the udp transports for data -     * \param flow_control_hints optional flow control params +     * \param err0_transports the udp transports for error +     * \param device_args optional misc device parameters       */      usrp2_impl(          std::vector<uhd::transport::udp_simple::sptr> ctrl_transports,          std::vector<uhd::transport::zero_copy_if::sptr> data_transports, -        const uhd::device_addr_t &flow_control_hints +        std::vector<uhd::transport::zero_copy_if::sptr> err0_transports, +        const uhd::device_addrs_t &device_args      );      ~usrp2_impl(void); @@ -223,6 +224,7 @@ private:      //io impl methods and members      std::vector<uhd::transport::zero_copy_if::sptr> _data_transports; +    std::vector<uhd::transport::zero_copy_if::sptr> _err0_transports;      uhd::otw_type_t _rx_otw_type, _tx_otw_type;      UHD_PIMPL_DECL(io_impl) _io_impl;      void io_init(void); diff --git a/host/lib/usrp/usrp2/usrp2_regs.cpp b/host/lib/usrp/usrp2/usrp2_regs.cpp index dd0433816..84907c32e 100644 --- a/host/lib/usrp/usrp2/usrp2_regs.cpp +++ b/host/lib/usrp/usrp2/usrp2_regs.cpp @@ -1,5 +1,5 @@  // -// Copyright 2010 Ettus Research LLC +// Copyright 2010-2011 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 @@ -57,9 +57,13 @@ usrp2_regs_t usrp2_get_regs(bool use_n2xx_map) {    x.time64_flags = sr_addr(misc_output_base, x.sr_time64 + 2);    x.time64_imm = sr_addr(misc_output_base, x.sr_time64 + 3);    x.time64_tps = sr_addr(misc_output_base, x.sr_time64 + 4); -  x.time64_secs_rb = bp_base + 4*10; -  x.time64_ticks_rb = bp_base + 4*11; +  x.time64_mimo_sync = sr_addr(misc_output_base, x.sr_time64 + 5); +  x.status = bp_base + 4*8; +  x.time64_secs_rb_imm = bp_base + 4*10; +  x.time64_ticks_rb_imm = bp_base + 4*11;    x.compat_num_rb = bp_base + 4*12; +  x.time64_secs_rb_pps = bp_base + 4*14; +  x.time64_ticks_rb_pps = bp_base + 4*15;    x.dsp_tx_freq = sr_addr(misc_output_base, x.sr_tx_dsp + 0);    x.dsp_tx_scale_iq = sr_addr(misc_output_base, x.sr_tx_dsp + 1);    x.dsp_tx_interp_rate = sr_addr(misc_output_base, x.sr_tx_dsp + 2); diff --git a/host/lib/usrp/usrp2/usrp2_regs.hpp b/host/lib/usrp/usrp2/usrp2_regs.hpp index 9936d634a..977b342cb 100644 --- a/host/lib/usrp/usrp2/usrp2_regs.hpp +++ b/host/lib/usrp/usrp2/usrp2_regs.hpp @@ -1,5 +1,5 @@  // -// Copyright 2010 Ettus Research LLC +// Copyright 2010-2011 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 @@ -25,10 +25,10 @@  #define USRP2_ATR_BASE          0xE400  #define USRP2_BP_STATUS_BASE    0xCC00 -#define USRP2P_MISC_OUTPUT_BASE 0x2000 -#define USRP2P_GPIO_BASE        0x3200 -#define USRP2P_ATR_BASE         0x3800 -#define USRP2P_BP_STATUS_BASE   0x3300 +#define USRP2P_MISC_OUTPUT_BASE 0x5000 +#define USRP2P_GPIO_BASE        0x6200 +#define USRP2P_ATR_BASE         0x6800 +#define USRP2P_BP_STATUS_BASE   0x6300  typedef struct {      int sr_misc; @@ -57,8 +57,12 @@ typedef struct {      int time64_flags; // flags -- see chart below      int time64_imm; // set immediate (0=latch on next pps, 1=latch immediate, default=0)      int time64_tps; // ticks per second rollover count -    int time64_secs_rb; -    int time64_ticks_rb; +    int time64_mimo_sync; +    int status; +    int time64_secs_rb_imm; +    int time64_ticks_rb_imm; +    int time64_secs_rb_pps; +    int time64_ticks_rb_pps;      int compat_num_rb;      int dsp_tx_freq;      int dsp_tx_scale_iq; diff --git a/host/lib/usrp/usrp_e100/codec_ctrl.cpp b/host/lib/usrp/usrp_e100/codec_ctrl.cpp index 18d9daca0..b33c8ae65 100644 --- a/host/lib/usrp/usrp_e100/codec_ctrl.cpp +++ b/host/lib/usrp/usrp_e100/codec_ctrl.cpp @@ -1,5 +1,5 @@  // -// Copyright 2010 Ettus Research LLC +// Copyright 2010-2011 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 @@ -31,7 +31,7 @@ using namespace uhd;  static const bool codec_debug = false; -const gain_range_t usrp_e100_codec_ctrl::tx_pga_gain_range(-20, 0, float(0.1)); +const gain_range_t usrp_e100_codec_ctrl::tx_pga_gain_range(-20, 0, double(0.1));  const gain_range_t usrp_e100_codec_ctrl::rx_pga_gain_range(0, 20, 1);  /*********************************************************************** @@ -44,14 +44,14 @@ public:      ~usrp_e100_codec_ctrl_impl(void);      //aux adc and dac control -    float read_aux_adc(aux_adc_t which); -    void write_aux_dac(aux_dac_t which, float volts); +    double read_aux_adc(aux_adc_t which); +    void write_aux_dac(aux_dac_t which, double volts);      //pga gain control -    void set_tx_pga_gain(float); -    float get_tx_pga_gain(void); -    void set_rx_pga_gain(float, char); -    float get_rx_pga_gain(char); +    void set_tx_pga_gain(double); +    double get_tx_pga_gain(void); +    void set_rx_pga_gain(double, char); +    double get_rx_pga_gain(char);  private:      usrp_e100_iface::sptr _iface; @@ -135,19 +135,19 @@ usrp_e100_codec_ctrl_impl::~usrp_e100_codec_ctrl_impl(void){   **********************************************************************/  static const int mtpgw = 255; //maximum tx pga gain word -void usrp_e100_codec_ctrl_impl::set_tx_pga_gain(float gain){ +void usrp_e100_codec_ctrl_impl::set_tx_pga_gain(double gain){      int gain_word = int(mtpgw*(gain - tx_pga_gain_range.start())/(tx_pga_gain_range.stop() - tx_pga_gain_range.start()));      _ad9862_regs.tx_pga_gain = std::clip(gain_word, 0, mtpgw);      this->send_reg(16);  } -float usrp_e100_codec_ctrl_impl::get_tx_pga_gain(void){ +double usrp_e100_codec_ctrl_impl::get_tx_pga_gain(void){      return (_ad9862_regs.tx_pga_gain*(tx_pga_gain_range.stop() - tx_pga_gain_range.start())/mtpgw) + tx_pga_gain_range.start();  }  static const int mrpgw = 0x14; //maximum rx pga gain word -void usrp_e100_codec_ctrl_impl::set_rx_pga_gain(float gain, char which){ +void usrp_e100_codec_ctrl_impl::set_rx_pga_gain(double gain, char which){      int gain_word = int(mrpgw*(gain - rx_pga_gain_range.start())/(rx_pga_gain_range.stop() - rx_pga_gain_range.start()));      gain_word = std::clip(gain_word, 0, mrpgw);      switch(which){ @@ -163,7 +163,7 @@ void usrp_e100_codec_ctrl_impl::set_rx_pga_gain(float gain, char which){      }  } -float usrp_e100_codec_ctrl_impl::get_rx_pga_gain(char which){ +double usrp_e100_codec_ctrl_impl::get_rx_pga_gain(char which){      int gain_word;      switch(which){      case 'A': gain_word = _ad9862_regs.rx_pga_a; break; @@ -176,11 +176,11 @@ float usrp_e100_codec_ctrl_impl::get_rx_pga_gain(char which){  /***********************************************************************   * Codec Control AUX ADC Methods   **********************************************************************/ -static float aux_adc_to_volts(boost::uint8_t high, boost::uint8_t low){ -    return float((boost::uint16_t(high) << 2) | low)*3.3/0x3ff; +static double aux_adc_to_volts(boost::uint8_t high, boost::uint8_t low){ +    return double((boost::uint16_t(high) << 2) | low)*3.3/0x3ff;  } -float usrp_e100_codec_ctrl_impl::read_aux_adc(aux_adc_t which){ +double usrp_e100_codec_ctrl_impl::read_aux_adc(aux_adc_t which){      //check to see if the switch needs to be set      bool write_switch = false;      switch(which){ @@ -233,7 +233,7 @@ float usrp_e100_codec_ctrl_impl::read_aux_adc(aux_adc_t which){  /***********************************************************************   * Codec Control AUX DAC Methods   **********************************************************************/ -void usrp_e100_codec_ctrl_impl::write_aux_dac(aux_dac_t which, float volts){ +void usrp_e100_codec_ctrl_impl::write_aux_dac(aux_dac_t which, double volts){      //special case for aux dac d (aka sigma delta word)      if (which == AUX_DAC_D){          boost::uint16_t dac_word = std::clip(boost::math::iround(volts*0xfff/3.3), 0, 0xfff); diff --git a/host/lib/usrp/usrp_e100/codec_ctrl.hpp b/host/lib/usrp/usrp_e100/codec_ctrl.hpp index 74ce9bd9a..05d7aab38 100644 --- a/host/lib/usrp/usrp_e100/codec_ctrl.hpp +++ b/host/lib/usrp/usrp_e100/codec_ctrl.hpp @@ -1,5 +1,5 @@  // -// Copyright 2010 Ettus Research LLC +// Copyright 2010-2011 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 @@ -57,7 +57,7 @@ public:       * \param which which of the 4 adcs       * \return a value in volts       */ -    virtual float read_aux_adc(aux_adc_t which) = 0; +    virtual double read_aux_adc(aux_adc_t which) = 0;      //! aux dac identifier constants      enum aux_dac_t{ @@ -72,19 +72,19 @@ public:       * \param which which of the 4 dacs       * \param volts the level in in volts       */ -    virtual void write_aux_dac(aux_dac_t which, float volts) = 0; +    virtual void write_aux_dac(aux_dac_t which, double volts) = 0;      //! Set the TX PGA gain -    virtual void set_tx_pga_gain(float gain) = 0; +    virtual void set_tx_pga_gain(double gain) = 0;      //! Get the TX PGA gain -    virtual float get_tx_pga_gain(void) = 0; +    virtual double get_tx_pga_gain(void) = 0;      //! Set the RX PGA gain ('A' or 'B') -    virtual void set_rx_pga_gain(float gain, char which) = 0; +    virtual void set_rx_pga_gain(double gain, char which) = 0;      //! Get the RX PGA gain ('A' or 'B') -    virtual float get_rx_pga_gain(char which) = 0; +    virtual double get_rx_pga_gain(char which) = 0;  };  #endif /* INCLUDED_USRP_E100_CODEC_CTRL_HPP */ diff --git a/host/lib/usrp/usrp_e100/codec_impl.cpp b/host/lib/usrp/usrp_e100/codec_impl.cpp index 6fd44bad3..0d91fb42c 100644 --- a/host/lib/usrp/usrp_e100/codec_impl.cpp +++ b/host/lib/usrp/usrp_e100/codec_impl.cpp @@ -1,5 +1,5 @@  // -// Copyright 2010 Ettus Research LLC +// Copyright 2010-2011 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 @@ -86,12 +86,12 @@ void usrp_e100_impl::rx_codec_set(const wax::obj &key_, const wax::obj &val){      switch(key.as<codec_prop_t>()){      case CODEC_PROP_GAIN_I:          UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); -        _codec_ctrl->set_rx_pga_gain(val.as<float>(), 'A'); +        _codec_ctrl->set_rx_pga_gain(val.as<double>(), 'A');          return;      case CODEC_PROP_GAIN_Q:          UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); -        _codec_ctrl->set_rx_pga_gain(val.as<float>(), 'B'); +        _codec_ctrl->set_rx_pga_gain(val.as<double>(), 'B');          return;      default: UHD_THROW_PROP_SET_ERROR(); @@ -141,7 +141,7 @@ void usrp_e100_impl::tx_codec_set(const wax::obj &key_, const wax::obj &val){      case CODEC_PROP_GAIN_I: //only one gain for I and Q      case CODEC_PROP_GAIN_Q:          UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); -        _codec_ctrl->set_tx_pga_gain(val.as<float>()); +        _codec_ctrl->set_tx_pga_gain(val.as<double>());          return;      default: UHD_THROW_PROP_SET_ERROR(); diff --git a/host/lib/usrp/usrp_e100/dboard_iface.cpp b/host/lib/usrp/usrp_e100/dboard_iface.cpp index a5032f86f..e4c3856c9 100644 --- a/host/lib/usrp/usrp_e100/dboard_iface.cpp +++ b/host/lib/usrp/usrp_e100/dboard_iface.cpp @@ -1,5 +1,5 @@  // -// Copyright 2010 Ettus Research LLC +// Copyright 2010-2011 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 @@ -60,8 +60,8 @@ public:          return props;      } -    void write_aux_dac(unit_t, aux_dac_t, float); -    float read_aux_adc(unit_t, aux_adc_t); +    void write_aux_dac(unit_t, aux_dac_t, double); +    double read_aux_adc(unit_t, aux_adc_t);      void _set_pin_ctrl(unit_t, boost::uint16_t);      void _set_atr_reg(unit_t, atr_reg_t, boost::uint16_t); @@ -270,7 +270,7 @@ byte_vector_t usrp_e100_dboard_iface::read_i2c(boost::uint8_t addr, size_t num_b  /***********************************************************************   * Aux DAX/ADC   **********************************************************************/ -void usrp_e100_dboard_iface::write_aux_dac(dboard_iface::unit_t, aux_dac_t which, float value){ +void usrp_e100_dboard_iface::write_aux_dac(dboard_iface::unit_t, aux_dac_t which, double value){      //same aux dacs for each unit      static const uhd::dict<aux_dac_t, usrp_e100_codec_ctrl::aux_dac_t> which_to_aux_dac = map_list_of          (AUX_DAC_A, usrp_e100_codec_ctrl::AUX_DAC_A) @@ -281,7 +281,7 @@ void usrp_e100_dboard_iface::write_aux_dac(dboard_iface::unit_t, aux_dac_t which      _codec->write_aux_dac(which_to_aux_dac[which], value);  } -float usrp_e100_dboard_iface::read_aux_adc(dboard_iface::unit_t unit, aux_adc_t which){ +double usrp_e100_dboard_iface::read_aux_adc(dboard_iface::unit_t unit, aux_adc_t which){      static const uhd::dict<          unit_t, uhd::dict<aux_adc_t, usrp_e100_codec_ctrl::aux_adc_t>      > unit_to_which_to_aux_adc = map_list_of diff --git a/host/lib/usrp/usrp_e100/dsp_impl.cpp b/host/lib/usrp/usrp_e100/dsp_impl.cpp index 43a3bd3be..7d358a607 100644 --- a/host/lib/usrp/usrp_e100/dsp_impl.cpp +++ b/host/lib/usrp/usrp_e100/dsp_impl.cpp @@ -38,7 +38,7 @@ void usrp_e100_impl::rx_ddc_init(void){      //initial config and update      rx_ddc_set(DSP_PROP_FREQ_SHIFT, double(0)); -    rx_ddc_set(DSP_PROP_HOST_RATE, double(64e6/10)); +    rx_ddc_set(DSP_PROP_HOST_RATE, double(16e6));  }  /*********************************************************************** @@ -121,7 +121,7 @@ void usrp_e100_impl::tx_duc_init(void){      //initial config and update      tx_duc_set(DSP_PROP_FREQ_SHIFT, double(0)); -    tx_duc_set(DSP_PROP_HOST_RATE, double(64e6/10)); +    tx_duc_set(DSP_PROP_HOST_RATE, double(16e6));  }  /*********************************************************************** diff --git a/host/lib/usrp/usrp_e100/mboard_impl.cpp b/host/lib/usrp/usrp_e100/mboard_impl.cpp index fe26cd63d..f52d2e6fb 100644 --- a/host/lib/usrp/usrp_e100/mboard_impl.cpp +++ b/host/lib/usrp/usrp_e100/mboard_impl.cpp @@ -1,5 +1,5 @@  // -// Copyright 2010 Ettus Research LLC +// Copyright 2010-2011 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 @@ -36,11 +36,13 @@ void usrp_e100_impl::mboard_init(void){          boost::bind(&usrp_e100_impl::mboard_set, this, _1, _2)      ); -    //init the clock config -    _clock_config.ref_source = clock_config_t::REF_AUTO; -    _clock_config.pps_source = clock_config_t::PPS_SMA; -    _clock_config.pps_polarity = clock_config_t::PPS_NEG; +    //set the ticks per seconds into the vita time control +    _iface->poke32(UE_REG_TIME64_TPS, +        boost::uint32_t(_clock_ctrl->get_fpga_clock_rate()) +    ); +    //init the clock config +    _clock_config = clock_config_t::internal();      update_clock_config();  } @@ -134,6 +136,22 @@ void usrp_e100_impl::mboard_get(const wax::obj &key_, wax::obj &val){          val = _iface->mb_eeprom;          return; +    case MBOARD_PROP_TIME_NOW: while(true){ +        uint32_t secs = _iface->peek32(UE_REG_RB_TIME_NOW_SECS); +        uint32_t ticks = _iface->peek32(UE_REG_RB_TIME_NOW_TICKS); +        if (secs != _iface->peek32(UE_REG_RB_TIME_NOW_SECS)) continue; +        val = time_spec_t(secs, ticks, _clock_ctrl->get_fpga_clock_rate()); +        return; +    } + +    case MBOARD_PROP_TIME_PPS: while(true){ +        uint32_t secs = _iface->peek32(UE_REG_RB_TIME_PPS_SECS); +        uint32_t ticks = _iface->peek32(UE_REG_RB_TIME_PPS_TICKS); +        if (secs != _iface->peek32(UE_REG_RB_TIME_PPS_SECS)) continue; +        val = time_spec_t(secs, ticks, _clock_ctrl->get_fpga_clock_rate()); +        return; +    } +      default: UHD_THROW_PROP_GET_ERROR();      }  } @@ -150,7 +168,7 @@ void usrp_e100_impl::mboard_set(const wax::obj &key, const wax::obj &val){          return;      case MBOARD_PROP_TIME_NOW: -    case MBOARD_PROP_TIME_NEXT_PPS:{ +    case MBOARD_PROP_TIME_PPS:{              time_spec_t time_spec = val.as<time_spec_t>();              _iface->poke32(UE_REG_TIME64_TICKS, time_spec.get_tick_count(_clock_ctrl->get_fpga_clock_rate()));              boost::uint32_t imm_flags = (key.as<mboard_prop_t>() == MBOARD_PROP_TIME_NOW)? 1 : 0; diff --git a/host/lib/usrp/usrp_e100/usrp_e100_impl.hpp b/host/lib/usrp/usrp_e100/usrp_e100_impl.hpp index de158ea5e..864e82099 100644 --- a/host/lib/usrp/usrp_e100/usrp_e100_impl.hpp +++ b/host/lib/usrp/usrp_e100/usrp_e100_impl.hpp @@ -30,7 +30,7 @@  #ifndef INCLUDED_USRP_E100_IMPL_HPP  #define INCLUDED_USRP_E100_IMPL_HPP -static const boost::uint16_t USRP_E_COMPAT_NUM = 0x02; +static const boost::uint16_t USRP_E_COMPAT_NUM = 0x03;  //! load an fpga image from a bin file into the usrp-e fpga  extern void usrp_e100_load_fpga(const std::string &bin_file); diff --git a/host/lib/usrp/usrp_e100/usrp_e100_regs.hpp b/host/lib/usrp/usrp_e100/usrp_e100_regs.hpp index 625fb2c35..a57fe5171 100644 --- a/host/lib/usrp/usrp_e100/usrp_e100_regs.hpp +++ b/host/lib/usrp/usrp_e100/usrp_e100_regs.hpp @@ -114,6 +114,16 @@  #define	UE_REG_ATR_FULL_RXSIDE  UE_REG_ATR_BASE + 12  #define	UE_REG_ATR_FULL_TXSIDE  UE_REG_ATR_BASE + 14 +/////////////////////////////////////////////////// +// Slave 7 -- Readback Mux 32 + +#define UE_REG_RB_MUX_32_BASE  UE_REG_SLAVE(7) + +#define UE_REG_RB_TIME_NOW_SECS   UE_REG_RB_MUX_32_BASE + 0 +#define UE_REG_RB_TIME_NOW_TICKS  UE_REG_RB_MUX_32_BASE + 4 +#define UE_REG_RB_TIME_PPS_SECS   UE_REG_RB_MUX_32_BASE + 8 +#define UE_REG_RB_TIME_PPS_TICKS  UE_REG_RB_MUX_32_BASE + 12 +  /////////////////////////////////////////////////  // DSP RX Regs  //////////////////////////////////////////////// diff --git a/host/lib/utils/CMakeLists.txt b/host/lib/utils/CMakeLists.txt index 60df24eef..5fa5b4d6d 100644 --- a/host/lib/utils/CMakeLists.txt +++ b/host/lib/utils/CMakeLists.txt @@ -1,5 +1,5 @@  # -# Copyright 2010 Ettus Research LLC +# Copyright 2010-2011 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 @@ -87,6 +87,7 @@ LIBUHD_APPEND_SOURCES(      ${CMAKE_CURRENT_SOURCE_DIR}/load_modules.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/paths.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/props.cpp +    ${CMAKE_CURRENT_SOURCE_DIR}/static.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/thread_priority.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/warning.cpp  ) diff --git a/host/lib/utils/gain_group.cpp b/host/lib/utils/gain_group.cpp index 11bbb8c0a..07aa21115 100644 --- a/host/lib/utils/gain_group.cpp +++ b/host/lib/utils/gain_group.cpp @@ -1,5 +1,5 @@  // -// Copyright 2010 Ettus Research LLC +// Copyright 2010-2011 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 @@ -39,7 +39,7 @@ static bool compare_by_step_size(   * Get a multiple of step with the following relation:   *     result = step*floor(num/step)   * - * Due to small floating-point inaccuracies: + * Due to small doubleing-point inaccuracies:   *     num = n*step + e, where e is a small inaccuracy.   * When e is negative, floor would yeild (n-1)*step,   * despite that n*step is really the desired result. @@ -66,7 +66,7 @@ public:      gain_range_t get_range(const std::string &name){          if (not name.empty()) return _name_to_fcns[name].get_range(); -        float overall_min = 0, overall_max = 0, overall_step = 0; +        double overall_min = 0, overall_max = 0, overall_step = 0;          BOOST_FOREACH(const gain_fcns_t &fcns, get_all_fcns()){              const gain_range_t range = fcns.get_range();              overall_min += range.start(); @@ -78,33 +78,33 @@ public:          return gain_range_t(overall_min, overall_max, overall_step);      } -    float get_value(const std::string &name){ +    double get_value(const std::string &name){          if (not name.empty()) return _name_to_fcns[name].get_value(); -        float overall_gain = 0; +        double overall_gain = 0;          BOOST_FOREACH(const gain_fcns_t &fcns, get_all_fcns()){              overall_gain += fcns.get_value();          }          return overall_gain;      } -    void set_value(float gain, const std::string &name){ +    void set_value(double gain, const std::string &name){          if (not name.empty()) return _name_to_fcns[name].set_value(gain);          std::vector<gain_fcns_t> all_fcns = get_all_fcns();          if (all_fcns.size() == 0) return; //nothing to set!          //get the max step size among the gains -        float max_step = 0; +        double max_step = 0;          BOOST_FOREACH(const gain_fcns_t &fcns, all_fcns){              max_step = std::max(max_step, fcns.get_range().step());          }          //create gain bucket to distribute power -        std::vector<float> gain_bucket; +        std::vector<double> gain_bucket;          //distribute power according to priority (round to max step) -        float gain_left_to_distribute = gain; +        double gain_left_to_distribute = gain;          BOOST_FOREACH(const gain_fcns_t &fcns, all_fcns){              const gain_range_t range = fcns.get_range();              gain_bucket.push_back(floor_step(std::clip( @@ -131,7 +131,7 @@ public:          //fill in the largest step sizes first that are less than the remainder          BOOST_FOREACH(size_t i, indexes_step_size_dec){              const gain_range_t range = all_fcns.at(i).get_range(); -            float additional_gain = floor_step(std::clip( +            double additional_gain = floor_step(std::clip(                  gain_bucket.at(i) + gain_left_to_distribute, range.start(), range.stop()              ), range.step()) - gain_bucket.at(i);              gain_bucket.at(i) += additional_gain; diff --git a/host/lib/utils/paths.cpp b/host/lib/utils/paths.cpp index 9e9525caf..93d15d290 100644 --- a/host/lib/utils/paths.cpp +++ b/host/lib/utils/paths.cpp @@ -1,5 +1,5 @@  // -// Copyright 2010 Ettus Research LLC +// Copyright 2010-2011 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 @@ -17,7 +17,7 @@  #include "constants.hpp"  #include <uhd/config.hpp> -#include <uhd/utils/algorithm.hpp> +#include <boost/tokenizer.hpp>  #include <boost/program_options.hpp>  #include <boost/filesystem.hpp>  #include <boost/foreach.hpp> @@ -38,6 +38,10 @@ namespace fs = boost::filesystem;      static const std::string env_path_sep = ":";  #endif /*UHD_PLATFORM_WIN32*/ +#define path_tokenizer(inp) \ +    boost::tokenizer<boost::char_separator<char> > \ +    (inp, boost::char_separator<char>(env_path_sep.c_str())) +  /***********************************************************************   * Get a list of paths for an environment variable   **********************************************************************/ @@ -60,7 +64,7 @@ static std::vector<fs::path> get_env_paths(const std::string &var_name){      //convert to filesystem path, filter blank paths      std::vector<fs::path> paths; -    BOOST_FOREACH(const std::string &path_string, std::split_string(var_value, env_path_sep)){ +    BOOST_FOREACH(const std::string &path_string, path_tokenizer(var_value)){          if (path_string.empty()) continue;          paths.push_back(fs::system_complete(path_string));      } diff --git a/host/lib/transport/msvc/stdint.h b/host/lib/utils/static.cpp index b3eb61aae..a0dea3372 100644 --- a/host/lib/transport/msvc/stdint.h +++ b/host/lib/utils/static.cpp @@ -1,35 +1,32 @@ -//
 -// Copyright 2010 Ettus Research LLC
 -//
 -// This program is free software: you can redistribute it and/or modify
 -// it under the terms of the GNU General Public License as published by
 -// the Free Software Foundation, either version 3 of the License, or
 -// (at your option) any later version.
 -//
 -// This program is distributed in the hope that it will be useful,
 -// but WITHOUT ANY WARRANTY; without even the implied warranty of
 -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 -// GNU General Public License for more details.
 -//
 -// You should have received a copy of the GNU General Public License
 -// along with this program.  If not, see <http://www.gnu.org/licenses/>.
 -//
 -
 -#ifndef INCLUDED_LIBUHD_TRANSPORT_STDINT_H
 -#define INCLUDED_LIBUHD_TRANSPORT_STDINT_H
 -
 -#include <boost/cstdint.hpp>
 -
 -//provide a stdint implementation for libusb
 -
 -typedef boost::uint64_t uint64_t;
 -typedef boost::uint32_t uint32_t;
 -typedef boost::uint16_t uint16_t;
 -typedef boost::uint8_t uint8_t;
 -
 -typedef boost::int64_t int64_t;
 -typedef boost::int32_t int32_t;
 -typedef boost::int16_t int16_t;
 -typedef boost::int8_t int8_t;
 -
 -#endif /* INCLUDED_LIBUHD_TRANSPORT_STDINT_H */
 +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#include <uhd/utils/static.hpp> +#include <stdexcept> +#include <iostream> +_uhd_static_fixture::_uhd_static_fixture(void (*fcn)(void), const char *name){ +    try{ +        fcn(); +    } +    catch(const std::exception &e){ +        std::cerr << "Exception in static block " << name << std::endl; +        std::cerr << "  " << e.what() << std::endl; +    } +    catch(...){ +        std::cerr << "Exception in static block " << name << std::endl; +    } +} diff --git a/host/lib/utils/warning.cpp b/host/lib/utils/warning.cpp index 05be7ae4d..bc4c79b6e 100644 --- a/host/lib/utils/warning.cpp +++ b/host/lib/utils/warning.cpp @@ -1,5 +1,5 @@  // -// Copyright 2010 Ettus Research LLC +// Copyright 2010-2011 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 @@ -16,7 +16,7 @@  //  #include <uhd/utils/warning.hpp> -#include <uhd/utils/algorithm.hpp> +#include <boost/tokenizer.hpp>  #include <uhd/utils/static.hpp>  #include <uhd/types/dict.hpp>  #include <boost/foreach.hpp> @@ -27,6 +27,10 @@  using namespace uhd; +#define tokenizer(inp, sep) \ +    boost::tokenizer<boost::char_separator<char> > \ +    (inp, boost::char_separator<char>(sep)) +  /***********************************************************************   * Registry implementation   **********************************************************************/ @@ -52,7 +56,7 @@ void warning::post(const std::string &msg){      //format the warning message      ss << std::endl << "Warning:" << std::endl; -    BOOST_FOREACH(const std::string &line, std::split_string(msg, "\n")){ +    BOOST_FOREACH(const std::string &line, tokenizer(msg, "\n")){          ss << "    " << line << std::endl;      } | 
